diff --git a/StormLib/stormlib/Makefile b/StormLib/stormlib/Makefile deleted file mode 100644 index 6c49337..0000000 --- a/StormLib/stormlib/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -##################################################################### -### -# -# Makefile for compiling StormLib under linux -# -# Author: Marko Friedemann -# Created at: Mon Jan 29 18:26:01 CEST 2001 -# Computer: whiplash.flachland-chemnitz.de -# System: Linux 2.4.0 on i686 -# -# Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved. -# -##################################################################### -### - -############################################## -# updated on October 6, 2008 by Trevor Hogan # -############################################## - -SHELL = /bin/sh -SYSTEM = $(shell uname) -C++ = g++ -CC = gcc -DFLAGS = -D__SYS_ZLIB -OFLAGS = -LFLAGS = -lbz2 -lz -CFLAGS = -fPIC -CFLAGS += $(OFLAGS) $(DFLAGS) - -OBJS = SCommon.o SCompression.o SFileCompactArchive.o \ - SFileCreateArchiveEx.o SFileExtractFile.o SFileFindFile.o \ - SListFile.o SFileOpenArchive.o SFileOpenFileEx.o \ - SAttrFile.o SFileReadFile.o \ - wave/wave.o \ - huffman/huff.o \ - misc/crc32.o misc/md5.o - -COBJS = pklib/crc32.o pklib/explode.o pklib/implode.o - -ifeq ($(SYSTEM),Darwin) -OBJS += StormPortMac.o -LFLAGS += -dynamiclib -framework CoreServices -LIB = libStorm.dylib -else -OBJS += StormPortLinux.o -LFLAGS += -shared -LIB = libStorm.so -endif - -all: $(OBJS) $(COBJS) $(LIB) - -$(LIB): $(OBJS) $(COBJS) - $(C++) -o $(LIB) $(OBJS) $(COBJS) $(LFLAGS) - -clean: - rm -f $(OBJS) $(COBJS) $(LIB) - -$(OBJS): %.o: %.cpp - $(C++) -o $@ $(CFLAGS) -c $< - -$(COBJS): %.o: %.c - $(CC) -o $@ $(CFLAGS) -c $< - -$(LIB): $(OBJS) $(COBJS) - -all: $(LIB) - -install: $(LIB) - install $(LIB) /usr/local/lib - mkdir -p /usr/local/include/StormLib - cp StormLib.h /usr/local/include/StormLib - cp StormPort.h /usr/local/include/StormLib - ldconfig diff --git a/default.cfg b/bin/default.cfg similarity index 100% rename from default.cfg rename to bin/default.cfg diff --git a/gameloaded.txt b/bin/gameloaded.txt similarity index 100% rename from gameloaded.txt rename to bin/gameloaded.txt diff --git a/gameover.txt b/bin/gameover.txt similarity index 100% rename from gameover.txt rename to bin/gameover.txt diff --git a/ghost dynamic configurator.exe b/bin/ghost dynamic configurator.exe similarity index 100% rename from ghost dynamic configurator.exe rename to bin/ghost dynamic configurator.exe diff --git a/ip-to-country.csv b/bin/ip-to-country.csv similarity index 100% rename from ip-to-country.csv rename to bin/ip-to-country.csv diff --git a/ipblacklist.txt b/bin/ipblacklist.txt similarity index 100% rename from ipblacklist.txt rename to bin/ipblacklist.txt diff --git a/language.cfg b/bin/language.cfg similarity index 100% rename from language.cfg rename to bin/language.cfg diff --git a/language_german.cfg b/bin/language_german.cfg similarity index 100% rename from language_german.cfg rename to bin/language_german.cfg diff --git a/language_russian.cfg b/bin/language_russian.cfg similarity index 100% rename from language_russian.cfg rename to bin/language_russian.cfg diff --git a/language_spanish.cfg b/bin/language_spanish.cfg similarity index 100% rename from language_spanish.cfg rename to bin/language_spanish.cfg diff --git a/language_turkish.cfg b/bin/language_turkish.cfg similarity index 100% rename from language_turkish.cfg rename to bin/language_turkish.cfg diff --git a/bin/license.txt b/bin/license.txt new file mode 100644 index 0000000..0507f2e --- /dev/null +++ b/bin/license.txt @@ -0,0 +1,13 @@ + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/mapcfgs/wormwar.cfg b/bin/mapcfgs/wormwar.cfg similarity index 99% rename from mapcfgs/wormwar.cfg rename to bin/mapcfgs/wormwar.cfg index ac77c84..e2ffc31 100644 --- a/mapcfgs/wormwar.cfg +++ b/bin/mapcfgs/wormwar.cfg @@ -88,7 +88,7 @@ map_height = 84 0 # map information (if incorrect it will force downloading for players and kick from the game lobby) -map_size = 201 213 5 0 +//map_size = 201 213 5 0 map_info = 206 105 219 80 map_crc = 15 15 71 22 map_sha1 = 91 92 122 144 89 127 250 70 133 235 247 76 193 31 109 105 36 250 36 16 diff --git a/mysql_create_tables_v1.sql b/bin/mysql_create_tables_v1.sql similarity index 100% rename from mysql_create_tables_v1.sql rename to bin/mysql_create_tables_v1.sql diff --git a/mysql_create_tables_v2.sql b/bin/mysql_create_tables_v2.sql similarity index 100% rename from mysql_create_tables_v2.sql rename to bin/mysql_create_tables_v2.sql diff --git a/mysql_upgrade_v1-v2.sql b/bin/mysql_upgrade_v1-v2.sql similarity index 100% rename from mysql_upgrade_v1-v2.sql rename to bin/mysql_upgrade_v1-v2.sql diff --git a/readme.txt b/bin/readme.txt similarity index 100% rename from readme.txt rename to bin/readme.txt diff --git a/update_dota_elo.cfg b/bin/update_dota_elo.cfg similarity index 100% rename from update_dota_elo.cfg rename to bin/update_dota_elo.cfg diff --git a/update_dota_elo.exe b/bin/update_dota_elo.exe similarity index 100% rename from update_dota_elo.exe rename to bin/update_dota_elo.exe diff --git a/update_w3mmd_elo.cfg b/bin/update_w3mmd_elo.cfg similarity index 100% rename from update_w3mmd_elo.cfg rename to bin/update_w3mmd_elo.cfg diff --git a/update_w3mmd_elo.exe b/bin/update_w3mmd_elo.exe similarity index 100% rename from update_w3mmd_elo.exe rename to bin/update_w3mmd_elo.exe diff --git a/bncsutil/product_version b/bncsutil/product_version deleted file mode 100644 index 1892b92..0000000 --- a/bncsutil/product_version +++ /dev/null @@ -1 +0,0 @@ -1.3.2 diff --git a/bncsutil/vc8_build/BNCSutil.vcproj b/bncsutil/vc8_build/BNCSutil.vcproj deleted file mode 100644 index 8c04042..0000000 --- a/bncsutil/vc8_build/BNCSutil.vcproj +++ /dev/null @@ -1,626 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bncsutil/vc8_build/bncsutil.def b/bncsutil/vc8_build/bncsutil.def deleted file mode 100644 index 32db61d..0000000 --- a/bncsutil/vc8_build/bncsutil.def +++ /dev/null @@ -1,45 +0,0 @@ -LIBRARY BNCSutil -VERSION 1.1 -EXPORTS - bncsutil_getVersion=_bncsutil_getVersion@0 @1 - bncsutil_getVersionString=_bncsutil_getVersionString@4 @2 - - calcHashBuf=_calcHashBuf@12 @3 - doubleHashPassword=_doubleHashPassword@16 @4 - hashPassword=_hashPassword@8 @5 - - kd_quick=_kd_quick@28 - kd_init=_kd_init@0 @6 - kd_create=_kd_create@8 @7 - kd_free=_kd_free@4 @8 - kd_val2Length=_kd_val2Length@4 @9 - kd_product=_kd_product@4 @10 - kd_val1=_kd_val1@4 @11 - kd_val2=_kd_val2@4 @12 - kd_longVal2=_kd_longVal2@8 @13 - kd_calculateHash=_kd_calculateHash@12 @14 - kd_getHash=_kd_getHash@8 @15 - kd_isValid=_kd_isValid@4 @16 - - checkRevision=_checkRevision@20 @17 - checkRevisionFlat=_checkRevisionFlat@24 @18 - getExeInfo=_getExeInfo@20 @19 - - extractMPQNumber=_extractMPQNumber@4 @20 - - nls_account_create=_nls_account_create@12 @21 - nls_account_logon=_nls_account_logon@12 @22 - nls_free=_nls_free@4 @23 - nls_get_A=_nls_get_A@8 @24 - nls_get_K=_nls_get_K@12 @25 - nls_get_M1=_nls_get_M1@16 @26 - nls_get_S=_nls_get_S@16 @27 - nls_get_v=_nls_get_v@12 @28 - nls_init=_nls_init@8 @29 - nls_init_l=_nls_init_l@16 @30 - nls_reinit=_nls_reinit@12 @31 - nls_reinit_l=_nls_reinit_l@20 @32 - nls_check_M2=_nls_check_M2@16 @33 - nls_check_signature=_nls_check_signature@8 @34 - nls_account_change_proof=_nls_account_change_proof@20 @35 - \ No newline at end of file diff --git a/bncsutil/vc8_build/gmp.lib b/bncsutil/vc8_build/gmp.lib deleted file mode 100644 index b5e2d63..0000000 Binary files a/bncsutil/vc8_build/gmp.lib and /dev/null differ diff --git a/ghost.exe b/ghost.exe deleted file mode 100644 index ceac20a..0000000 Binary files a/ghost.exe and /dev/null differ diff --git a/ghost.pro b/ghost.pro new file mode 100644 index 0000000..f3e4d42 --- /dev/null +++ b/ghost.pro @@ -0,0 +1,14 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = bncsutil libghost cli plugins + +# set up correct paths +libghost.subdir = src/libghost +plugins.subdir = src/plugins +cli.subdir = src/cli +bncsutil.subdir = src/bncsutil + +# dependencies +libghost.depends = bncsutil +cli.depends = libghost +plugins.depends = libghost diff --git a/ghost/Makefile b/ghost/Makefile deleted file mode 100644 index c3a5d5d..0000000 --- a/ghost/Makefile +++ /dev/null @@ -1,84 +0,0 @@ -SHELL = /bin/sh -SYSTEM = $(shell uname) -C++ = g++ -CC = gcc -DFLAGS = -DGHOST_MYSQL -OFLAGS = -O3 -LFLAGS = -L. -L../bncsutil/src/bncsutil/ -L../StormLib/stormlib/ -lbncsutil -lpthread -ldl -lz -lStorm -lmysqlclient_r -lboost_date_time-mt -lboost_thread-mt -lboost_system-mt -lboost_filesystem-mt -CFLAGS = - -ifeq ($(SYSTEM),Darwin) -DFLAGS += -D__APPLE__ -OFLAGS += -flat_namespace -else -LFLAGS += -lrt -endif - -ifeq ($(SYSTEM),FreeBSD) -DFLAGS += -D__FREEBSD__ -endif - -ifeq ($(SYSTEM),SunOS) -DFLAGS += -D__SOLARIS__ -LFLAGS += -lresolv -lsocket -lnsl -endif - -CFLAGS += $(OFLAGS) $(DFLAGS) -I. -I../bncsutil/src/ -I../StormLib/ - -ifeq ($(SYSTEM),Darwin) -CFLAGS += -I../mysql/include/ -endif - -OBJS = bncsutilinterface.o bnet.o bnetprotocol.o bnlsclient.o bnlsprotocol.o commandpacket.o config.o crc32.o csvparser.o game.o game_admin.o game_base.o gameplayer.o gameprotocol.o gameslot.o ghost.o ghostdb.o ghostdbmysql.o ghostdbsqlite.o gpsprotocol.o language.o map.o packed.o replay.o savegame.o sha1.o socket.o stats.o statsdota.o statsw3mmd.o util.o -COBJS = sqlite3.o -PROGS = ./ghost++ - -all: $(OBJS) $(COBJS) $(PROGS) - -./ghost++: $(OBJS) $(COBJS) - $(C++) -o ./ghost++ $(OBJS) $(COBJS) $(LFLAGS) - -clean: - rm -f $(OBJS) $(COBJS) $(PROGS) - -$(OBJS): %.o: %.cpp - $(C++) -o $@ $(CFLAGS) -c $< - -$(COBJS): %.o: %.c - $(CC) -o $@ $(CFLAGS) -c $< - -./ghost++: $(OBJS) $(COBJS) - -all: $(PROGS) - -bncsutilinterface.o: ghost.h includes.h util.h bncsutilinterface.h -bnet.o: ghost.h includes.h util.h config.h language.h socket.h commandpacket.h ghostdb.h bncsutilinterface.h bnlsclient.h bnetprotocol.h bnet.h map.h packed.h savegame.h replay.h gameprotocol.h game_base.h -bnetprotocol.o: ghost.h includes.h util.h bnetprotocol.h -bnlsclient.o: ghost.h includes.h util.h socket.h commandpacket.h bnlsprotocol.h bnlsclient.h -bnlsprotocol.o: ghost.h includes.h util.h bnlsprotocol.h -commandpacket.o: ghost.h includes.h commandpacket.h -config.o: ghost.h includes.h config.h -crc32.o: ghost.h includes.h crc32.h -csvparser.o: csvparser.h -game.o: ghost.h includes.h util.h config.h language.h socket.h ghostdb.h bnet.h map.h packed.h savegame.h gameplayer.h gameprotocol.h game_base.h game.h stats.h statsdota.h statsw3mmd.h -game_admin.o: ghost.h includes.h util.h config.h language.h socket.h ghostdb.h bnet.h map.h packed.h savegame.h replay.h gameplayer.h gameprotocol.h game_base.h game_admin.h -game_base.o: ghost.h includes.h util.h config.h language.h socket.h ghostdb.h bnet.h map.h packed.h savegame.h replay.h gameplayer.h gameprotocol.h game_base.h next_combination.h -gameplayer.o: ghost.h includes.h util.h language.h socket.h commandpacket.h bnet.h map.h gameplayer.h gameprotocol.h gpsprotocol.h game_base.h -gameprotocol.o: ghost.h includes.h util.h crc32.h gameplayer.h gameprotocol.h game_base.h -gameslot.o: ghost.h includes.h gameslot.h -ghost.o: ghost.h includes.h util.h crc32.h sha1.h csvparser.h config.h language.h socket.h ghostdb.h ghostdbsqlite.h ghostdbmysql.h bnet.h map.h packed.h savegame.h gameplayer.h gameprotocol.h gpsprotocol.h game_base.h game.h game_admin.h -ghostdb.o: ghost.h includes.h util.h config.h ghostdb.h -ghostdbmysql.o: ghost.h includes.h util.h config.h ghostdb.h ghostdbmysql.h -ghostdbsqlite.o: ghost.h includes.h util.h config.h ghostdb.h ghostdbsqlite.h -gpsprotocol.o: ghost.h util.h gpsprotocol.h -language.o: ghost.h includes.h config.h language.h -map.o: ghost.h includes.h util.h crc32.h sha1.h config.h map.h -packed.o: ghost.h includes.h util.h crc32.h packed.h -replay.o: ghost.h includes.h util.h packed.h replay.h gameprotocol.h -savegame.o: ghost.h includes.h util.h packed.h savegame.h -sha1.o: sha1.h -socket.o: ghost.h includes.h util.h socket.h -stats.o: ghost.h includes.h stats.h -statsdota.o: ghost.h includes.h util.h ghostdb.h gameplayer.h gameprotocol.h game_base.h stats.h statsdota.h -statsw3mmd.o: ghost.h includes.h util.h ghostdb.h gameprotocol.h game_base.h stats.h statsw3mmd.h -util.o: ghost.h includes.h util.h diff --git a/ghost/bncsutilinterface.cpp b/ghost/bncsutilinterface.cpp deleted file mode 100644 index 637bc8d..0000000 --- a/ghost/bncsutilinterface.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "bncsutilinterface.h" - -#include - -// -// CBNCSUtilInterface -// - -CBNCSUtilInterface :: CBNCSUtilInterface( string userName, string userPassword ) -{ - // m_nls = (void *)nls_init( userName.c_str( ), userPassword.c_str( ) ); - m_NLS = new NLS( userName, userPassword ); -} - -CBNCSUtilInterface :: ~CBNCSUtilInterface( ) -{ - // nls_free( (nls_t *)m_nls ); - delete (NLS *)m_NLS; -} - -void CBNCSUtilInterface :: Reset( string userName, string userPassword ) -{ - // nls_free( (nls_t *)m_nls ); - // m_nls = (void *)nls_init( userName.c_str( ), userPassword.c_str( ) ); - delete (NLS *)m_NLS; - m_NLS = new NLS( userName, userPassword ); -} - -bool CBNCSUtilInterface :: HELP_SID_AUTH_CHECK( bool TFT, string war3Path, string keyROC, string keyTFT, string valueStringFormula, string mpqFileName, BYTEARRAY clientToken, BYTEARRAY serverToken ) -{ - // set m_EXEVersion, m_EXEVersionHash, m_EXEInfo, m_InfoROC, m_InfoTFT - - string FileWar3EXE = war3Path + "war3.exe"; - string FileStormDLL = war3Path + "Storm.dll"; - - if( !UTIL_FileExists( FileStormDLL ) ) - FileStormDLL = war3Path + "storm.dll"; - - string FileGameDLL = war3Path + "game.dll"; - bool ExistsWar3EXE = UTIL_FileExists( FileWar3EXE ); - bool ExistsStormDLL = UTIL_FileExists( FileStormDLL ); - bool ExistsGameDLL = UTIL_FileExists( FileGameDLL ); - - if( ExistsWar3EXE && ExistsStormDLL && ExistsGameDLL ) - { - // todotodo: check getExeInfo return value to ensure 1024 bytes was enough - - char buf[1024]; - uint32_t EXEVersion; - getExeInfo( FileWar3EXE.c_str( ), (char *)&buf, 1024, (uint32_t *)&EXEVersion, BNCSUTIL_PLATFORM_X86 ); - m_EXEInfo = buf; - m_EXEVersion = UTIL_CreateByteArray( EXEVersion, false ); - uint32_t EXEVersionHash; - checkRevisionFlat( valueStringFormula.c_str( ), FileWar3EXE.c_str( ), FileStormDLL.c_str( ), FileGameDLL.c_str( ), extractMPQNumber( mpqFileName.c_str( ) ), (unsigned long *)&EXEVersionHash ); - m_EXEVersionHash = UTIL_CreateByteArray( EXEVersionHash, false ); - m_KeyInfoROC = CreateKeyInfo( keyROC, UTIL_ByteArrayToUInt32( clientToken, false ), UTIL_ByteArrayToUInt32( serverToken, false ) ); - - if( TFT ) - m_KeyInfoTFT = CreateKeyInfo( keyTFT, UTIL_ByteArrayToUInt32( clientToken, false ), UTIL_ByteArrayToUInt32( serverToken, false ) ); - - if( m_KeyInfoROC.size( ) == 36 && ( !TFT || m_KeyInfoTFT.size( ) == 36 ) ) - return true; - else - { - if( m_KeyInfoROC.size( ) != 36 ) - CONSOLE_Print( "[BNCSUI] unable to create ROC key info - invalid ROC key" ); - - if( TFT && m_KeyInfoTFT.size( ) != 36 ) - CONSOLE_Print( "[BNCSUI] unable to create TFT key info - invalid TFT key" ); - } - } - else - { - if( !ExistsWar3EXE ) - CONSOLE_Print( "[BNCSUI] unable to open [" + FileWar3EXE + "]" ); - - if( !ExistsStormDLL ) - CONSOLE_Print( "[BNCSUI] unable to open [" + FileStormDLL + "]" ); - - if( !ExistsGameDLL ) - CONSOLE_Print( "[BNCSUI] unable to open [" + FileGameDLL + "]" ); - } - - return false; -} - -bool CBNCSUtilInterface :: HELP_SID_AUTH_ACCOUNTLOGON( ) -{ - // set m_ClientKey - - char buf[32]; - // nls_get_A( (nls_t *)m_nls, buf ); - ( (NLS *)m_NLS )->getPublicKey( buf ); - m_ClientKey = UTIL_CreateByteArray( (unsigned char *)buf, 32 ); - return true; -} - -bool CBNCSUtilInterface :: HELP_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY salt, BYTEARRAY serverKey ) -{ - // set m_M1 - - char buf[20]; - // nls_get_M1( (nls_t *)m_nls, buf, string( serverKey.begin( ), serverKey.end( ) ).c_str( ), string( salt.begin( ), salt.end( ) ).c_str( ) ); - ( (NLS *)m_NLS )->getClientSessionKey( buf, string( salt.begin( ), salt.end( ) ).c_str( ), string( serverKey.begin( ), serverKey.end( ) ).c_str( ) ); - m_M1 = UTIL_CreateByteArray( (unsigned char *)buf, 20 ); - return true; -} - -bool CBNCSUtilInterface :: HELP_PvPGNPasswordHash( string userPassword ) -{ - // set m_PvPGNPasswordHash - - char buf[20]; - hashPassword( userPassword.c_str( ), buf ); - m_PvPGNPasswordHash = UTIL_CreateByteArray( (unsigned char *)buf, 20 ); - return true; -} - -BYTEARRAY CBNCSUtilInterface :: CreateKeyInfo( string key, uint32_t clientToken, uint32_t serverToken ) -{ - unsigned char Zeros[] = { 0, 0, 0, 0 }; - BYTEARRAY KeyInfo; - CDKeyDecoder Decoder( key.c_str( ), key.size( ) ); - - if( Decoder.isKeyValid( ) ) - { - UTIL_AppendByteArray( KeyInfo, UTIL_CreateByteArray( (uint32_t)key.size( ), false ) ); - UTIL_AppendByteArray( KeyInfo, UTIL_CreateByteArray( Decoder.getProduct( ), false ) ); - UTIL_AppendByteArray( KeyInfo, UTIL_CreateByteArray( Decoder.getVal1( ), false ) ); - UTIL_AppendByteArray( KeyInfo, UTIL_CreateByteArray( Zeros, 4 ) ); - size_t Length = Decoder.calculateHash( clientToken, serverToken ); - char *buf = new char[Length]; - Length = Decoder.getHash( buf ); - UTIL_AppendByteArray( KeyInfo, UTIL_CreateByteArray( (unsigned char *)buf, Length ) ); - delete [] buf; - } - - return KeyInfo; -} diff --git a/ghost/bncsutilinterface.h b/ghost/bncsutilinterface.h deleted file mode 100644 index 76b5858..0000000 --- a/ghost/bncsutilinterface.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef BNCSUTIL_INTERFACE_H -#define BNCSUTIL_INTERFACE_H - -// -// CBNCSUtilInterface -// - -class CBNCSUtilInterface -{ -private: - void *m_NLS; - BYTEARRAY m_EXEVersion; // set in HELP_SID_AUTH_CHECK - BYTEARRAY m_EXEVersionHash; // set in HELP_SID_AUTH_CHECK - string m_EXEInfo; // set in HELP_SID_AUTH_CHECK - BYTEARRAY m_KeyInfoROC; // set in HELP_SID_AUTH_CHECK - BYTEARRAY m_KeyInfoTFT; // set in HELP_SID_AUTH_CHECK - BYTEARRAY m_ClientKey; // set in HELP_SID_AUTH_ACCOUNTLOGON - BYTEARRAY m_M1; // set in HELP_SID_AUTH_ACCOUNTLOGONPROOF - BYTEARRAY m_PvPGNPasswordHash; // set in HELP_PvPGNPasswordHash - -public: - CBNCSUtilInterface( string userName, string userPassword ); - ~CBNCSUtilInterface( ); - - BYTEARRAY GetEXEVersion( ) { return m_EXEVersion; } - BYTEARRAY GetEXEVersionHash( ) { return m_EXEVersionHash; } - string GetEXEInfo( ) { return m_EXEInfo; } - BYTEARRAY GetKeyInfoROC( ) { return m_KeyInfoROC; } - BYTEARRAY GetKeyInfoTFT( ) { return m_KeyInfoTFT; } - BYTEARRAY GetClientKey( ) { return m_ClientKey; } - BYTEARRAY GetM1( ) { return m_M1; } - BYTEARRAY GetPvPGNPasswordHash( ) { return m_PvPGNPasswordHash; } - - void SetEXEVersion( BYTEARRAY &nEXEVersion ) { m_EXEVersion = nEXEVersion; } - void SetEXEVersionHash( BYTEARRAY &nEXEVersionHash ) { m_EXEVersionHash = nEXEVersionHash; } - - void Reset( string userName, string userPassword ); - - bool HELP_SID_AUTH_CHECK( bool TFT, string war3Path, string keyROC, string keyTFT, string valueStringFormula, string mpqFileName, BYTEARRAY clientToken, BYTEARRAY serverToken ); - bool HELP_SID_AUTH_ACCOUNTLOGON( ); - bool HELP_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY salt, BYTEARRAY serverKey ); - bool HELP_PvPGNPasswordHash( string userPassword ); - -private: - BYTEARRAY CreateKeyInfo( string key, uint32_t clientToken, uint32_t serverToken ); -}; - -#endif diff --git a/ghost/bnet.cpp b/ghost/bnet.cpp deleted file mode 100644 index 21b0855..0000000 --- a/ghost/bnet.cpp +++ /dev/null @@ -1,2565 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "config.h" -#include "language.h" -#include "socket.h" -#include "commandpacket.h" -#include "ghostdb.h" -#include "bncsutilinterface.h" -#include "bnlsclient.h" -#include "bnetprotocol.h" -#include "bnet.h" -#include "map.h" -#include "packed.h" -#include "savegame.h" -#include "replay.h" -#include "gameprotocol.h" -#include "game_base.h" - -#include - -using namespace boost :: filesystem; - -// -// CBNET -// - -CBNET :: CBNET( CGHost *nGHost, string nServer, string nServerAlias, string nBNLSServer, uint16_t nBNLSPort, uint32_t nBNLSWardenCookie, string nCDKeyROC, string nCDKeyTFT, string nCountryAbbrev, string nCountry, uint32_t nLocaleID, string nUserName, string nUserPassword, string nFirstChannel, string nRootAdmin, char nCommandTrigger, bool nHoldFriends, bool nHoldClan, bool nPublicCommands, unsigned char nWar3Version, BYTEARRAY nEXEVersion, BYTEARRAY nEXEVersionHash, string nPasswordHashType, string nPVPGNRealmName, uint32_t nMaxMessageLength, uint32_t nHostCounterID ) -{ - // todotodo: append path seperator to Warcraft3Path if needed - - m_GHost = nGHost; - m_Socket = new CTCPClient( ); - m_Protocol = new CBNETProtocol( ); - m_BNLSClient = NULL; - m_BNCSUtil = new CBNCSUtilInterface( nUserName, nUserPassword ); - m_CallableAdminList = m_GHost->m_DB->ThreadedAdminList( nServer ); - m_CallableBanList = m_GHost->m_DB->ThreadedBanList( nServer ); - m_Exiting = false; - m_Server = nServer; - string LowerServer = m_Server; - transform( LowerServer.begin( ), LowerServer.end( ), LowerServer.begin( ), (int(*)(int))tolower ); - - if( !nServerAlias.empty( ) ) - m_ServerAlias = nServerAlias; - else if( LowerServer == "useast.battle.net" ) - m_ServerAlias = "USEast"; - else if( LowerServer == "uswest.battle.net" ) - m_ServerAlias = "USWest"; - else if( LowerServer == "asia.battle.net" ) - m_ServerAlias = "Asia"; - else if( LowerServer == "europe.battle.net" ) - m_ServerAlias = "Europe"; - else - m_ServerAlias = m_Server; - - if( nPasswordHashType == "pvpgn" && !nBNLSServer.empty( ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] pvpgn connection found with a configured BNLS server, ignoring BNLS server" ); - nBNLSServer.clear( ); - nBNLSPort = 0; - nBNLSWardenCookie = 0; - } - - m_BNLSServer = nBNLSServer; - m_BNLSPort = nBNLSPort; - m_BNLSWardenCookie = nBNLSWardenCookie; - m_CDKeyROC = nCDKeyROC; - m_CDKeyTFT = nCDKeyTFT; - - // remove dashes from CD keys and convert to uppercase - - m_CDKeyROC.erase( remove( m_CDKeyROC.begin( ), m_CDKeyROC.end( ), '-' ), m_CDKeyROC.end( ) ); - m_CDKeyTFT.erase( remove( m_CDKeyTFT.begin( ), m_CDKeyTFT.end( ), '-' ), m_CDKeyTFT.end( ) ); - transform( m_CDKeyROC.begin( ), m_CDKeyROC.end( ), m_CDKeyROC.begin( ), (int(*)(int))toupper ); - transform( m_CDKeyTFT.begin( ), m_CDKeyTFT.end( ), m_CDKeyTFT.begin( ), (int(*)(int))toupper ); - - if( m_CDKeyROC.size( ) != 26 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - your ROC CD key is not 26 characters long and is probably invalid" ); - - if( m_GHost->m_TFT && m_CDKeyTFT.size( ) != 26 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - your TFT CD key is not 26 characters long and is probably invalid" ); - - m_CountryAbbrev = nCountryAbbrev; - m_Country = nCountry; - m_LocaleID = nLocaleID; - m_UserName = nUserName; - m_UserPassword = nUserPassword; - m_FirstChannel = nFirstChannel; - m_RootAdmin = nRootAdmin; - transform( m_RootAdmin.begin( ), m_RootAdmin.end( ), m_RootAdmin.begin( ), (int(*)(int))tolower ); - m_CommandTrigger = nCommandTrigger; - m_War3Version = nWar3Version; - m_EXEVersion = nEXEVersion; - m_EXEVersionHash = nEXEVersionHash; - m_PasswordHashType = nPasswordHashType; - m_PVPGNRealmName = nPVPGNRealmName; - m_MaxMessageLength = nMaxMessageLength; - m_HostCounterID = nHostCounterID; - m_LastDisconnectedTime = 0; - m_LastConnectionAttemptTime = 0; - m_LastNullTime = 0; - m_LastOutPacketTicks = 0; - m_LastOutPacketSize = 0; - m_LastAdminRefreshTime = GetTime( ); - m_LastBanRefreshTime = GetTime( ); - m_FirstConnect = true; - m_WaitingToConnect = true; - m_LoggedIn = false; - m_InChat = false; - m_HoldFriends = nHoldFriends; - m_HoldClan = nHoldClan; - m_PublicCommands = nPublicCommands; -} - -CBNET :: ~CBNET( ) -{ - delete m_Socket; - delete m_Protocol; - delete m_BNLSClient; - - while( !m_Packets.empty( ) ) - { - delete m_Packets.front( ); - m_Packets.pop( ); - } - - delete m_BNCSUtil; - - for( vector :: iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) - delete *i; - - for( vector :: iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) - delete *i; - - for( vector :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - if( m_CallableAdminList ) - m_GHost->m_Callables.push_back( m_CallableAdminList ); - - if( m_CallableBanList ) - m_GHost->m_Callables.push_back( m_CallableBanList ); - - for( vector :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) - delete *i; -} - -BYTEARRAY CBNET :: GetUniqueName( ) -{ - return m_Protocol->GetUniqueName( ); -} - -unsigned int CBNET :: SetFD( void *fd, void *send_fd, int *nfds ) -{ - unsigned int NumFDs = 0; - - if( !m_Socket->HasError( ) && m_Socket->GetConnected( ) ) - { - m_Socket->SetFD( (fd_set *)fd, (fd_set *)send_fd, nfds ); - NumFDs++; - - if( m_BNLSClient ) - NumFDs += m_BNLSClient->SetFD( fd, send_fd, nfds ); - } - - return NumFDs; -} - -bool CBNET :: Update( void *fd, void *send_fd ) -{ - // - // update callables - // - - for( vector :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); ) - { - if( i->second->GetReady( ) ) - { - uint32_t Count = i->second->GetResult( ); - - if( Count == 0 ) - QueueChatCommand( m_GHost->m_Language->ThereAreNoAdmins( m_Server ), i->first, !i->first.empty( ) ); - else if( Count == 1 ) - QueueChatCommand( m_GHost->m_Language->ThereIsAdmin( m_Server ), i->first, !i->first.empty( ) ); - else - QueueChatCommand( m_GHost->m_Language->ThereAreAdmins( m_Server, UTIL_ToString( Count ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminCounts.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - AddAdmin( i->second->GetUser( ) ); - QueueChatCommand( m_GHost->m_Language->AddedUserToAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - } - else - QueueChatCommand( m_GHost->m_Language->ErrorAddingUserToAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminAdds.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - RemoveAdmin( i->second->GetUser( ) ); - QueueChatCommand( m_GHost->m_Language->DeletedUserFromAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - } - else - QueueChatCommand( m_GHost->m_Language->ErrorDeletingUserFromAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminRemoves.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); ) - { - if( i->second->GetReady( ) ) - { - uint32_t Count = i->second->GetResult( ); - - if( Count == 0 ) - QueueChatCommand( m_GHost->m_Language->ThereAreNoBannedUsers( m_Server ), i->first, !i->first.empty( ) ); - else if( Count == 1 ) - QueueChatCommand( m_GHost->m_Language->ThereIsBannedUser( m_Server ), i->first, !i->first.empty( ) ); - else - QueueChatCommand( m_GHost->m_Language->ThereAreBannedUsers( m_Server, UTIL_ToString( Count ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanCounts.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - AddBan( i->second->GetUser( ), i->second->GetIP( ), i->second->GetGameName( ), i->second->GetAdmin( ), i->second->GetReason( ) ); - QueueChatCommand( m_GHost->m_Language->BannedUser( i->second->GetServer( ), i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - } - else - QueueChatCommand( m_GHost->m_Language->ErrorBanningUser( i->second->GetServer( ), i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanAdds.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - RemoveBan( i->second->GetUser( ) ); - QueueChatCommand( m_GHost->m_Language->UnbannedUser( i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - } - else - QueueChatCommand( m_GHost->m_Language->ErrorUnbanningUser( i->second->GetUser( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanRemoves.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); ) - { - if( i->second->GetReady( ) ) - { - CDBGamePlayerSummary *GamePlayerSummary = i->second->GetResult( ); - - if( GamePlayerSummary ) - QueueChatCommand( m_GHost->m_Language->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), UTIL_ToString( GamePlayerSummary->GetTotalGames( ) ), UTIL_ToString( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 2 ), UTIL_ToString( GamePlayerSummary->GetAvgLeftPercent( ) ) ), i->first, !i->first.empty( ) ); - else - QueueChatCommand( m_GHost->m_Language->HasntPlayedGamesWithThisBot( i->second->GetName( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedGPSChecks.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); ) - { - if( i->second->GetReady( ) ) - { - CDBDotAPlayerSummary *DotAPlayerSummary = i->second->GetResult( ); - - if( DotAPlayerSummary ) - { - string Summary = m_GHost->m_Language->HasPlayedDotAGamesWithThisBot( i->second->GetName( ), - UTIL_ToString( DotAPlayerSummary->GetTotalGames( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalWins( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalLosses( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalDeaths( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCreepKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCreepDenies( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalAssists( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalNeutralKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalTowerKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalRaxKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCourierKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetAvgKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgDeaths( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCreepKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCreepDenies( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgAssists( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgNeutralKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgTowerKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgRaxKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCourierKills( ), 2 ) ); - - QueueChatCommand( Summary, i->first, !i->first.empty( ) ); - } - else - QueueChatCommand( m_GHost->m_Language->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ), i->first, !i->first.empty( ) ); - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedDPSChecks.erase( i ); - } - else - i++; - } - - // refresh the admin list every 5 minutes - - if( !m_CallableAdminList && GetTime( ) - m_LastAdminRefreshTime >= 300 ) - m_CallableAdminList = m_GHost->m_DB->ThreadedAdminList( m_Server ); - - if( m_CallableAdminList && m_CallableAdminList->GetReady( ) ) - { - // CONSOLE_Print( "[BNET: " + m_ServerAlias + "] refreshed admin list (" + UTIL_ToString( m_Admins.size( ) ) + " -> " + UTIL_ToString( m_CallableAdminList->GetResult( ).size( ) ) + " admins)" ); - m_Admins = m_CallableAdminList->GetResult( ); - m_GHost->m_DB->RecoverCallable( m_CallableAdminList ); - delete m_CallableAdminList; - m_CallableAdminList = NULL; - m_LastAdminRefreshTime = GetTime( ); - } - - // refresh the ban list every 60 minutes - - if( !m_CallableBanList && GetTime( ) - m_LastBanRefreshTime >= 3600 ) - m_CallableBanList = m_GHost->m_DB->ThreadedBanList( m_Server ); - - if( m_CallableBanList && m_CallableBanList->GetReady( ) ) - { - // CONSOLE_Print( "[BNET: " + m_ServerAlias + "] refreshed ban list (" + UTIL_ToString( m_Bans.size( ) ) + " -> " + UTIL_ToString( m_CallableBanList->GetResult( ).size( ) ) + " bans)" ); - - for( vector :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) - delete *i; - - m_Bans = m_CallableBanList->GetResult( ); - m_GHost->m_DB->RecoverCallable( m_CallableBanList ); - delete m_CallableBanList; - m_CallableBanList = NULL; - m_LastBanRefreshTime = GetTime( ); - } - - // we return at the end of each if statement so we don't have to deal with errors related to the order of the if statements - // that means it might take a few ms longer to complete a task involving multiple steps (in this case, reconnecting) due to blocking or sleeping - // but it's not a big deal at all, maybe 100ms in the worst possible case (based on a 50ms blocking time) - - if( m_Socket->HasError( ) ) - { - // the socket has an error - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] disconnected from battle.net due to socket error" ); - - if( m_Socket->GetError( ) == ECONNRESET && GetTime( ) - m_LastConnectionAttemptTime <= 15 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - you are probably temporarily IP banned from battle.net" ); - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting 90 seconds to reconnect" ); - m_GHost->EventBNETDisconnected( this ); - delete m_BNLSClient; - m_BNLSClient = NULL; - m_BNCSUtil->Reset( m_UserName, m_UserPassword ); - m_Socket->Reset( ); - m_LastDisconnectedTime = GetTime( ); - m_LoggedIn = false; - m_InChat = false; - m_WaitingToConnect = true; - return m_Exiting; - } - - if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && !m_WaitingToConnect ) - { - // the socket was disconnected - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] disconnected from battle.net" ); - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting 90 seconds to reconnect" ); - m_GHost->EventBNETDisconnected( this ); - delete m_BNLSClient; - m_BNLSClient = NULL; - m_BNCSUtil->Reset( m_UserName, m_UserPassword ); - m_Socket->Reset( ); - m_LastDisconnectedTime = GetTime( ); - m_LoggedIn = false; - m_InChat = false; - m_WaitingToConnect = true; - return m_Exiting; - } - - if( m_Socket->GetConnected( ) ) - { - // the socket is connected and everything appears to be working properly - - m_Socket->DoRecv( (fd_set *)fd ); - ExtractPackets( ); - ProcessPackets( ); - - // update the BNLS client - - if( m_BNLSClient ) - { - if( m_BNLSClient->Update( fd, send_fd ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] deleting BNLS client" ); - delete m_BNLSClient; - m_BNLSClient = NULL; - } - else - { - BYTEARRAY WardenResponse = m_BNLSClient->GetWardenResponse( ); - - if( !WardenResponse.empty( ) ) - m_Socket->PutBytes( m_Protocol->SEND_SID_WARDEN( WardenResponse ) ); - } - } - - // check if at least one packet is waiting to be sent and if we've waited long enough to prevent flooding - // this formula has changed many times but currently we wait 1 second if the last packet was "small", 3.5 seconds if it was "medium", and 4 seconds if it was "big" - - uint32_t WaitTicks = 0; - - if( m_LastOutPacketSize < 10 ) - WaitTicks = 1000; - else if( m_LastOutPacketSize < 100 ) - WaitTicks = 3500; - else - WaitTicks = 4000; - - if( !m_OutPackets.empty( ) && GetTicks( ) - m_LastOutPacketTicks >= WaitTicks ) - { - if( m_OutPackets.size( ) > 7 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] packet queue warning - there are " + UTIL_ToString( m_OutPackets.size( ) ) + " packets waiting to be sent" ); - - m_Socket->PutBytes( m_OutPackets.front( ) ); - m_LastOutPacketSize = m_OutPackets.front( ).size( ); - m_OutPackets.pop( ); - m_LastOutPacketTicks = GetTicks( ); - } - - // send a null packet every 60 seconds to detect disconnects - - if( GetTime( ) - m_LastNullTime >= 60 && GetTicks( ) - m_LastOutPacketTicks >= 60000 ) - { - m_Socket->PutBytes( m_Protocol->SEND_SID_NULL( ) ); - m_LastNullTime = GetTime( ); - } - - m_Socket->DoSend( (fd_set *)send_fd ); - return m_Exiting; - } - - if( m_Socket->GetConnecting( ) ) - { - // we are currently attempting to connect to battle.net - - if( m_Socket->CheckConnect( ) ) - { - // the connection attempt completed - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connected" ); - m_GHost->EventBNETConnected( this ); - m_Socket->PutBytes( m_Protocol->SEND_PROTOCOL_INITIALIZE_SELECTOR( ) ); - m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_INFO( m_War3Version, m_GHost->m_TFT, m_LocaleID, m_CountryAbbrev, m_Country ) ); - m_Socket->DoSend( (fd_set *)send_fd ); - m_LastNullTime = GetTime( ); - m_LastOutPacketTicks = GetTicks( ); - - while( !m_OutPackets.empty( ) ) - m_OutPackets.pop( ); - - return m_Exiting; - } - else if( GetTime( ) - m_LastConnectionAttemptTime >= 15 ) - { - // the connection attempt timed out (15 seconds) - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connect timed out" ); - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting 90 seconds to reconnect" ); - m_GHost->EventBNETConnectTimedOut( this ); - m_Socket->Reset( ); - m_LastDisconnectedTime = GetTime( ); - m_WaitingToConnect = true; - return m_Exiting; - } - } - - if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && ( m_FirstConnect || GetTime( ) - m_LastDisconnectedTime >= 90 ) ) - { - // attempt to connect to battle.net - - m_FirstConnect = false; - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connecting to server [" + m_Server + "] on port 6112" ); - m_GHost->EventBNETConnecting( this ); - - if( !m_GHost->m_BindAddress.empty( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempting to bind to address [" + m_GHost->m_BindAddress + "]" ); - - if( m_ServerIP.empty( ) ) - { - m_Socket->Connect( m_GHost->m_BindAddress, m_Server, 6112 ); - - if( !m_Socket->HasError( ) ) - { - m_ServerIP = m_Socket->GetIPString( ); - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] resolved and cached server IP address " + m_ServerIP ); - } - } - else - { - // use cached server IP address since resolving takes time and is blocking - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using cached server IP address " + m_ServerIP ); - m_Socket->Connect( m_GHost->m_BindAddress, m_ServerIP, 6112 ); - } - - m_WaitingToConnect = false; - m_LastConnectionAttemptTime = GetTime( ); - return m_Exiting; - } - - return m_Exiting; -} - -void CBNET :: ExtractPackets( ) -{ - // extract as many packets as possible from the socket's receive buffer and put them in the m_Packets queue - - string *RecvBuffer = m_Socket->GetBytes( ); - BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); - - // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes - - while( Bytes.size( ) >= 4 ) - { - // byte 0 is always 255 - - if( Bytes[0] == BNET_HEADER_CONSTANT ) - { - // bytes 2 and 3 contain the length of the packet - - uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); - - if( Length >= 4 ) - { - if( Bytes.size( ) >= Length ) - { - m_Packets.push( new CCommandPacket( BNET_HEADER_CONSTANT, Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); - *RecvBuffer = RecvBuffer->substr( Length ); - Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); - } - else - return; - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error - received invalid packet from battle.net (bad length), disconnecting" ); - m_Socket->Disconnect( ); - return; - } - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error - received invalid packet from battle.net (bad header constant), disconnecting" ); - m_Socket->Disconnect( ); - return; - } - } -} - -void CBNET :: ProcessPackets( ) -{ - CIncomingGameHost *GameHost = NULL; - CIncomingChatEvent *ChatEvent = NULL; - BYTEARRAY WardenData; - vector Friends; - vector Clans; - - // process all the received packets in the m_Packets queue - // this normally means sending some kind of response - - while( !m_Packets.empty( ) ) - { - CCommandPacket *Packet = m_Packets.front( ); - m_Packets.pop( ); - - if( Packet->GetPacketType( ) == BNET_HEADER_CONSTANT ) - { - switch( Packet->GetID( ) ) - { - case CBNETProtocol :: SID_NULL: - // warning: we do not respond to NULL packets with a NULL packet of our own - // this is because PVPGN servers are programmed to respond to NULL packets so it will create a vicious cycle of useless traffic - // official battle.net servers do not respond to NULL packets - - m_Protocol->RECEIVE_SID_NULL( Packet->GetData( ) ); - break; - - case CBNETProtocol :: SID_GETADVLISTEX: - GameHost = m_Protocol->RECEIVE_SID_GETADVLISTEX( Packet->GetData( ) ); - - if( GameHost ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joining game [" + GameHost->GetGameName( ) + "]" ); - - delete GameHost; - GameHost = NULL; - break; - - case CBNETProtocol :: SID_ENTERCHAT: - if( m_Protocol->RECEIVE_SID_ENTERCHAT( Packet->GetData( ) ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joining channel [" + m_FirstChannel + "]" ); - m_InChat = true; - m_Socket->PutBytes( m_Protocol->SEND_SID_JOINCHANNEL( m_FirstChannel ) ); - } - - break; - - case CBNETProtocol :: SID_CHATEVENT: - ChatEvent = m_Protocol->RECEIVE_SID_CHATEVENT( Packet->GetData( ) ); - - if( ChatEvent ) - ProcessChatEvent( ChatEvent ); - - delete ChatEvent; - ChatEvent = NULL; - break; - - case CBNETProtocol :: SID_CHECKAD: - m_Protocol->RECEIVE_SID_CHECKAD( Packet->GetData( ) ); - break; - - case CBNETProtocol :: SID_STARTADVEX3: - if( m_Protocol->RECEIVE_SID_STARTADVEX3( Packet->GetData( ) ) ) - { - m_InChat = false; - m_GHost->EventBNETGameRefreshed( this ); - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] startadvex3 failed" ); - m_GHost->EventBNETGameRefreshFailed( this ); - } - - break; - - case CBNETProtocol :: SID_PING: - m_Socket->PutBytes( m_Protocol->SEND_SID_PING( m_Protocol->RECEIVE_SID_PING( Packet->GetData( ) ) ) ); - break; - - case CBNETProtocol :: SID_AUTH_INFO: - if( m_Protocol->RECEIVE_SID_AUTH_INFO( Packet->GetData( ) ) ) - { - if( m_BNCSUtil->HELP_SID_AUTH_CHECK( m_GHost->m_TFT, m_GHost->m_Warcraft3Path, m_CDKeyROC, m_CDKeyTFT, m_Protocol->GetValueStringFormulaString( ), m_Protocol->GetIX86VerFileNameString( ), m_Protocol->GetClientToken( ), m_Protocol->GetServerToken( ) ) ) - { - // override the exe information generated by bncsutil if specified in the config file - // apparently this is useful for pvpgn users - - if( m_EXEVersion.size( ) == 4 ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using custom exe version bnet_custom_exeversion = " + UTIL_ToString( m_EXEVersion[0] ) + " " + UTIL_ToString( m_EXEVersion[1] ) + " " + UTIL_ToString( m_EXEVersion[2] ) + " " + UTIL_ToString( m_EXEVersion[3] ) ); - m_BNCSUtil->SetEXEVersion( m_EXEVersion ); - } - - if( m_EXEVersionHash.size( ) == 4 ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using custom exe version hash bnet_custom_exeversionhash = " + UTIL_ToString( m_EXEVersionHash[0] ) + " " + UTIL_ToString( m_EXEVersionHash[1] ) + " " + UTIL_ToString( m_EXEVersionHash[2] ) + " " + UTIL_ToString( m_EXEVersionHash[3] ) ); - m_BNCSUtil->SetEXEVersionHash( m_EXEVersionHash ); - } - - if( m_GHost->m_TFT ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: The Frozen Throne" ); - else - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: Reign of Chaos" ); - - m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_CHECK( m_GHost->m_TFT, m_Protocol->GetClientToken( ), m_BNCSUtil->GetEXEVersion( ), m_BNCSUtil->GetEXEVersionHash( ), m_BNCSUtil->GetKeyInfoROC( ), m_BNCSUtil->GetKeyInfoTFT( ), m_BNCSUtil->GetEXEInfo( ), "GHost" ) ); - - // the Warden seed is the first 4 bytes of the ROC key hash - // initialize the Warden handler - - if( !m_BNLSServer.empty( ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] creating BNLS client" ); - delete m_BNLSClient; - m_BNLSClient = new CBNLSClient( m_BNLSServer, m_BNLSPort, m_BNLSWardenCookie ); - m_BNLSClient->QueueWardenSeed( UTIL_ByteArrayToUInt32( m_BNCSUtil->GetKeyInfoROC( ), false, 16 ) ); - } - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - bncsutil key hash failed (check your Warcraft 3 path and cd keys), disconnecting" ); - m_Socket->Disconnect( ); - delete Packet; - return; - } - } - - break; - - case CBNETProtocol :: SID_AUTH_CHECK: - if( m_Protocol->RECEIVE_SID_AUTH_CHECK( Packet->GetData( ) ) ) - { - // cd keys accepted - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] cd keys accepted" ); - m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGON( ); - m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGON( m_BNCSUtil->GetClientKey( ), m_UserName ) ); - } - else - { - // cd keys not accepted - - switch( UTIL_ByteArrayToUInt32( m_Protocol->GetKeyState( ), false ) ) - { - case CBNETProtocol :: KR_ROC_KEY_IN_USE: - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - ROC CD key in use by user [" + m_Protocol->GetKeyStateDescription( ) + "], disconnecting" ); - break; - case CBNETProtocol :: KR_TFT_KEY_IN_USE: - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - TFT CD key in use by user [" + m_Protocol->GetKeyStateDescription( ) + "], disconnecting" ); - break; - case CBNETProtocol :: KR_OLD_GAME_VERSION: - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - game version is too old, disconnecting" ); - break; - case CBNETProtocol :: KR_INVALID_VERSION: - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - game version is invalid, disconnecting" ); - break; - default: - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - cd keys not accepted, disconnecting" ); - break; - } - - m_Socket->Disconnect( ); - delete Packet; - return; - } - - break; - - case CBNETProtocol :: SID_AUTH_ACCOUNTLOGON: - if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGON( Packet->GetData( ) ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] username [" + m_UserName + "] accepted" ); - - if( m_PasswordHashType == "pvpgn" ) - { - // pvpgn logon - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using pvpgn logon type (for pvpgn servers only)" ); - m_BNCSUtil->HELP_PvPGNPasswordHash( m_UserPassword ); - m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetPvPGNPasswordHash( ) ) ); - } - else - { - // battle.net logon - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using battle.net logon type (for official battle.net servers only)" ); - m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGONPROOF( m_Protocol->GetSalt( ), m_Protocol->GetServerPublicKey( ) ); - m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetM1( ) ) ); - } - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - invalid username, disconnecting" ); - m_Socket->Disconnect( ); - delete Packet; - return; - } - - break; - - case CBNETProtocol :: SID_AUTH_ACCOUNTLOGONPROOF: - if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( Packet->GetData( ) ) ) - { - // logon successful - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon successful" ); - m_LoggedIn = true; - m_GHost->EventBNETLoggedIn( this ); - m_Socket->PutBytes( m_Protocol->SEND_SID_NETGAMEPORT( m_GHost->m_HostPort ) ); - m_Socket->PutBytes( m_Protocol->SEND_SID_ENTERCHAT( ) ); - m_Socket->PutBytes( m_Protocol->SEND_SID_FRIENDSLIST( ) ); - m_Socket->PutBytes( m_Protocol->SEND_SID_CLANMEMBERLIST( ) ); - } - else - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - invalid password, disconnecting" ); - - // try to figure out if the user might be using the wrong logon type since too many people are confused by this - - string Server = m_Server; - transform( Server.begin( ), Server.end( ), Server.begin( ), (int(*)(int))tolower ); - - if( m_PasswordHashType == "pvpgn" && ( Server == "useast.battle.net" || Server == "uswest.battle.net" || Server == "asia.battle.net" || Server == "europe.battle.net" ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] it looks like you're trying to connect to a battle.net server using a pvpgn logon type, check your config file's \"battle.net custom data\" section" ); - else if( m_PasswordHashType != "pvpgn" && ( Server != "useast.battle.net" && Server != "uswest.battle.net" && Server != "asia.battle.net" && Server != "europe.battle.net" ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] it looks like you're trying to connect to a pvpgn server using a battle.net logon type, check your config file's \"battle.net custom data\" section" ); - - m_Socket->Disconnect( ); - delete Packet; - return; - } - - break; - - case CBNETProtocol :: SID_WARDEN: - WardenData = m_Protocol->RECEIVE_SID_WARDEN( Packet->GetData( ) ); - - if( m_BNLSClient ) - m_BNLSClient->QueueWardenRaw( WardenData ); - else - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - received warden packet but no BNLS server is available, you will be kicked from battle.net soon" ); - - break; - - case CBNETProtocol :: SID_FRIENDSLIST: - Friends = m_Protocol->RECEIVE_SID_FRIENDSLIST( Packet->GetData( ) ); - - for( vector :: iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) - delete *i; - - m_Friends = Friends; - break; - - case CBNETProtocol :: SID_CLANMEMBERLIST: - vector Clans = m_Protocol->RECEIVE_SID_CLANMEMBERLIST( Packet->GetData( ) ); - - for( vector :: iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) - delete *i; - - m_Clans = Clans; - break; - } - } - - delete Packet; - } -} - -void CBNET :: ProcessChatEvent( CIncomingChatEvent *chatEvent ) -{ - CBNETProtocol :: IncomingChatEvent Event = chatEvent->GetChatEvent( ); - bool Whisper = ( Event == CBNETProtocol :: EID_WHISPER ); - string User = chatEvent->GetUser( ); - string Message = chatEvent->GetMessage( ); - - if( Event == CBNETProtocol :: EID_WHISPER || Event == CBNETProtocol :: EID_TALK ) - { - if( Event == CBNETProtocol :: EID_WHISPER ) - { - CONSOLE_Print( "[WHISPER: " + m_ServerAlias + "] [" + User + "] " + Message ); - m_GHost->EventBNETWhisper( this, User, Message ); - } - else - { - CONSOLE_Print( "[LOCAL: " + m_ServerAlias + "] [" + User + "] " + Message ); - m_GHost->EventBNETChat( this, User, Message ); - } - - // handle spoof checking for current game - // this case covers whispers - we assume that anyone who sends a whisper to the bot with message "spoofcheck" should be considered spoof checked - // note that this means you can whisper "spoofcheck" even in a public game to manually spoofcheck if the /whois fails - - if( Event == CBNETProtocol :: EID_WHISPER && m_GHost->m_CurrentGame ) - { - if( Message == "s" || Message == "sc" || Message == "spoof" || Message == "check" || Message == "spoofcheck" ) - m_GHost->m_CurrentGame->AddToSpoofed( m_Server, User, true ); - else if( Message.find( m_GHost->m_CurrentGame->GetGameName( ) ) != string :: npos ) - { - // look for messages like "entered a Warcraft III The Frozen Throne game called XYZ" - // we don't look for the English part of the text anymore because we want this to work with multiple languages - // it's a pretty safe bet that anyone whispering the bot with a message containing the game name is a valid spoofcheck - - if( m_PasswordHashType == "pvpgn" && User == m_PVPGNRealmName ) - { - // the equivalent pvpgn message is: [PvPGN Realm] Your friend abc has entered a Warcraft III Frozen Throne game named "xyz". - - vector Tokens = UTIL_Tokenize( Message, ' ' ); - - if( Tokens.size( ) >= 3 ) - m_GHost->m_CurrentGame->AddToSpoofed( m_Server, Tokens[2], false ); - } - else - m_GHost->m_CurrentGame->AddToSpoofed( m_Server, User, false ); - } - } - - // handle bot commands - - if( Message == "?trigger" && ( IsAdmin( User ) || IsRootAdmin( User ) || ( m_PublicCommands && m_OutPackets.size( ) <= 3 ) ) ) - QueueChatCommand( m_GHost->m_Language->CommandTrigger( string( 1, m_CommandTrigger ) ), User, Whisper ); - else if( !Message.empty( ) && Message[0] == m_CommandTrigger ) - { - // extract the command trigger, the command, and the payload - // e.g. "!say hello world" -> command: "say", payload: "hello world" - - string Command; - string Payload; - string :: size_type PayloadStart = Message.find( " " ); - - if( PayloadStart != string :: npos ) - { - Command = Message.substr( 1, PayloadStart - 1 ); - Payload = Message.substr( PayloadStart + 1 ); - } - else - Command = Message.substr( 1 ); - - transform( Command.begin( ), Command.end( ), Command.begin( ), (int(*)(int))tolower ); - - if( IsAdmin( User ) || IsRootAdmin( User ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] admin [" + User + "] sent command [" + Message + "]" ); - - /***************** - * ADMIN COMMANDS * - ******************/ - - // - // !ADDADMIN - // - - if( Command == "addadmin" && !Payload.empty( ) ) - { - if( IsRootAdmin( User ) ) - { - if( IsAdmin( Payload ) ) - QueueChatCommand( m_GHost->m_Language->UserIsAlreadyAnAdmin( m_Server, Payload ), User, Whisper ); - else - m_PairedAdminAdds.push_back( PairedAdminAdd( Whisper ? User : string( ), m_GHost->m_DB->ThreadedAdminAdd( m_Server, Payload ) ) ); - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !ADDBAN - // !BAN - // - - if( ( Command == "addban" || Command == "ban" ) && !Payload.empty( ) ) - { - // extract the victim and the reason - // e.g. "Varlock leaver after dying" -> victim: "Varlock", reason: "leaver after dying" - - string Victim; - string Reason; - stringstream SS; - SS << Payload; - SS >> Victim; - - if( !SS.eof( ) ) - { - getline( SS, Reason ); - string :: size_type Start = Reason.find_first_not_of( " " ); - - if( Start != string :: npos ) - Reason = Reason.substr( Start ); - } - - if( IsBannedName( Victim ) ) - QueueChatCommand( m_GHost->m_Language->UserIsAlreadyBanned( m_Server, Victim ), User, Whisper ); - else - m_PairedBanAdds.push_back( PairedBanAdd( Whisper ? User : string( ), m_GHost->m_DB->ThreadedBanAdd( m_Server, Victim, string( ), string( ), User, Reason ) ) ); - } - - // - // !ANNOUNCE - // - - if( Command == "announce" && m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetCountDownStarted( ) ) - { - if( Payload.empty( ) || Payload == "off" ) - { - QueueChatCommand( m_GHost->m_Language->AnnounceMessageDisabled( ), User, Whisper ); - m_GHost->m_CurrentGame->SetAnnounce( 0, string( ) ); - } - else - { - // extract the interval and the message - // e.g. "30 hello everyone" -> interval: "30", message: "hello everyone" - - uint32_t Interval; - string Message; - stringstream SS; - SS << Payload; - SS >> Interval; - - if( SS.fail( ) || Interval == 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to announce command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to announce command" ); - else - { - getline( SS, Message ); - string :: size_type Start = Message.find_first_not_of( " " ); - - if( Start != string :: npos ) - Message = Message.substr( Start ); - - QueueChatCommand( m_GHost->m_Language->AnnounceMessageEnabled( ), User, Whisper ); - m_GHost->m_CurrentGame->SetAnnounce( Interval, Message ); - } - } - } - } - - // - // !AUTOHOST - // - - if( Command == "autohost" ) - { - if( IsRootAdmin( User ) ) - { - if( Payload.empty( ) || Payload == "off" ) - { - QueueChatCommand( m_GHost->m_Language->AutoHostDisabled( ), User, Whisper ); - m_GHost->m_AutoHostGameName.clear( ); - m_GHost->m_AutoHostOwner.clear( ); - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = 0; - m_GHost->m_AutoHostAutoStartPlayers = 0; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - else - { - // extract the maximum games, auto start players, and the game name - // e.g. "5 10 BattleShips Pro" -> maximum games: "5", auto start players: "10", game name: "BattleShips Pro" - - uint32_t MaximumGames; - uint32_t AutoStartPlayers; - string GameName; - stringstream SS; - SS << Payload; - SS >> MaximumGames; - - if( SS.fail( ) || MaximumGames == 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to autohost command" ); - else - { - SS >> AutoStartPlayers; - - if( SS.fail( ) || AutoStartPlayers == 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to autohost command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #3 to autohost command" ); - else - { - getline( SS, GameName ); - string :: size_type Start = GameName.find_first_not_of( " " ); - - if( Start != string :: npos ) - GameName = GameName.substr( Start ); - - QueueChatCommand( m_GHost->m_Language->AutoHostEnabled( ), User, Whisper ); - delete m_GHost->m_AutoHostMap; - m_GHost->m_AutoHostMap = new CMap( *m_GHost->m_Map ); - m_GHost->m_AutoHostGameName = GameName; - m_GHost->m_AutoHostOwner = User; - m_GHost->m_AutoHostServer = m_Server; - m_GHost->m_AutoHostMaximumGames = MaximumGames; - m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - } - } - } - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !AUTOHOSTMM - // - - if( Command == "autohostmm" ) - { - if( IsRootAdmin( User ) ) - { - if( Payload.empty( ) || Payload == "off" ) - { - QueueChatCommand( m_GHost->m_Language->AutoHostDisabled( ), User, Whisper ); - m_GHost->m_AutoHostGameName.clear( ); - m_GHost->m_AutoHostOwner.clear( ); - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = 0; - m_GHost->m_AutoHostAutoStartPlayers = 0; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - else - { - // extract the maximum games, auto start players, minimum score, maximum score, and the game name - // e.g. "5 10 800 1200 BattleShips Pro" -> maximum games: "5", auto start players: "10", minimum score: "800", maximum score: "1200", game name: "BattleShips Pro" - - uint32_t MaximumGames; - uint32_t AutoStartPlayers; - double MinimumScore; - double MaximumScore; - string GameName; - stringstream SS; - SS << Payload; - SS >> MaximumGames; - - if( SS.fail( ) || MaximumGames == 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to autohostmm command" ); - else - { - SS >> AutoStartPlayers; - - if( SS.fail( ) || AutoStartPlayers == 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to autohostmm command" ); - else - { - SS >> MinimumScore; - - if( SS.fail( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #3 to autohostmm command" ); - else - { - SS >> MaximumScore; - - if( SS.fail( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #4 to autohostmm command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #5 to autohostmm command" ); - else - { - getline( SS, GameName ); - string :: size_type Start = GameName.find_first_not_of( " " ); - - if( Start != string :: npos ) - GameName = GameName.substr( Start ); - - QueueChatCommand( m_GHost->m_Language->AutoHostEnabled( ), User, Whisper ); - delete m_GHost->m_AutoHostMap; - m_GHost->m_AutoHostMap = new CMap( *m_GHost->m_Map ); - m_GHost->m_AutoHostGameName = GameName; - m_GHost->m_AutoHostOwner = User; - m_GHost->m_AutoHostServer = m_Server; - m_GHost->m_AutoHostMaximumGames = MaximumGames; - m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = true; - m_GHost->m_AutoHostMinimumScore = MinimumScore; - m_GHost->m_AutoHostMaximumScore = MaximumScore; - } - } - } - } - } - } - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !AUTOSTART - // - - if( Command == "autostart" && m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetCountDownStarted( ) ) - { - if( Payload.empty( ) || Payload == "off" ) - { - QueueChatCommand( m_GHost->m_Language->AutoStartDisabled( ), User, Whisper ); - m_GHost->m_CurrentGame->SetAutoStartPlayers( 0 ); - } - else - { - uint32_t AutoStartPlayers = UTIL_ToUInt32( Payload ); - - if( AutoStartPlayers != 0 ) - { - QueueChatCommand( m_GHost->m_Language->AutoStartEnabled( UTIL_ToString( AutoStartPlayers ) ), User, Whisper ); - m_GHost->m_CurrentGame->SetAutoStartPlayers( AutoStartPlayers ); - } - } - } - - // - // !CHANNEL (change channel) - // - - if( Command == "channel" && !Payload.empty( ) ) - QueueChatCommand( "/join " + Payload ); - - // - // !CHECKADMIN - // - - if( Command == "checkadmin" && !Payload.empty( ) ) - { - if( IsRootAdmin( User ) ) - { - if( IsAdmin( Payload ) ) - QueueChatCommand( m_GHost->m_Language->UserIsAnAdmin( m_Server, Payload ), User, Whisper ); - else - QueueChatCommand( m_GHost->m_Language->UserIsNotAnAdmin( m_Server, Payload ), User, Whisper ); - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !CHECKBAN - // - - if( Command == "checkban" && !Payload.empty( ) ) - { - CDBBan *Ban = IsBannedName( Payload ); - - if( Ban ) - QueueChatCommand( m_GHost->m_Language->UserWasBannedOnByBecause( m_Server, Payload, Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ), User, Whisper ); - else - QueueChatCommand( m_GHost->m_Language->UserIsNotBanned( m_Server, Payload ), User, Whisper ); - } - - // - // !CLOSE (close slot) - // - - if( Command == "close" && !Payload.empty( ) && m_GHost->m_CurrentGame ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - { - // close as many slots as specified, e.g. "5 10" closes slots 5 and 10 - - stringstream SS; - SS << Payload; - - while( !SS.eof( ) ) - { - uint32_t SID; - SS >> SID; - - if( SS.fail( ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to close command" ); - break; - } - else - m_GHost->m_CurrentGame->CloseSlot( (unsigned char)( SID - 1 ), true ); - } - } - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !CLOSEALL - // - - if( Command == "closeall" && m_GHost->m_CurrentGame ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - m_GHost->m_CurrentGame->CloseAllSlots( ); - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !COUNTADMINS - // - - if( Command == "countadmins" ) - { - if( IsRootAdmin( User ) ) - m_PairedAdminCounts.push_back( PairedAdminCount( Whisper ? User : string( ), m_GHost->m_DB->ThreadedAdminCount( m_Server ) ) ); - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !COUNTBANS - // - - if( Command == "countbans" ) - m_PairedBanCounts.push_back( PairedBanCount( Whisper ? User : string( ), m_GHost->m_DB->ThreadedBanCount( m_Server ) ) ); - - // - // !DBSTATUS - // - - if( Command == "dbstatus" ) - QueueChatCommand( m_GHost->m_DB->GetStatus( ), User, Whisper ); - - // - // !DELADMIN - // - - if( Command == "deladmin" && !Payload.empty( ) ) - { - if( IsRootAdmin( User ) ) - { - if( !IsAdmin( Payload ) ) - QueueChatCommand( m_GHost->m_Language->UserIsNotAnAdmin( m_Server, Payload ), User, Whisper ); - else - m_PairedAdminRemoves.push_back( PairedAdminRemove( Whisper ? User : string( ), m_GHost->m_DB->ThreadedAdminRemove( m_Server, Payload ) ) ); - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !DELBAN - // !UNBAN - // - - if( ( Command == "delban" || Command == "unban" ) && !Payload.empty( ) ) - m_PairedBanRemoves.push_back( PairedBanRemove( Whisper ? User : string( ), m_GHost->m_DB->ThreadedBanRemove( Payload ) ) ); - - // - // !DISABLE - // - - if( Command == "disable" ) - { - if( IsRootAdmin( User ) ) - { - QueueChatCommand( m_GHost->m_Language->BotDisabled( ), User, Whisper ); - m_GHost->m_Enabled = false; - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !DOWNLOADS - // - - if( Command == "downloads" && !Payload.empty( ) ) - { - uint32_t Downloads = UTIL_ToUInt32( Payload ); - - if( Downloads == 0 ) - { - QueueChatCommand( m_GHost->m_Language->MapDownloadsDisabled( ), User, Whisper ); - m_GHost->m_AllowDownloads = 0; - } - else if( Downloads == 1 ) - { - QueueChatCommand( m_GHost->m_Language->MapDownloadsEnabled( ), User, Whisper ); - m_GHost->m_AllowDownloads = 1; - } - else if( Downloads == 2 ) - { - QueueChatCommand( m_GHost->m_Language->MapDownloadsConditional( ), User, Whisper ); - m_GHost->m_AllowDownloads = 2; - } - } - - // - // !ENABLE - // - - if( Command == "enable" ) - { - if( IsRootAdmin( User ) ) - { - QueueChatCommand( m_GHost->m_Language->BotEnabled( ), User, Whisper ); - m_GHost->m_Enabled = true; - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !END - // - - if( Command == "end" && !Payload.empty( ) ) - { - // todotodo: what if a game ends just as you're typing this command and the numbering changes? - - uint32_t GameNumber = UTIL_ToUInt32( Payload ) - 1; - - if( GameNumber < m_GHost->m_Games.size( ) ) - { - // if the game owner is still in the game only allow the root admin to end the game - - if( m_GHost->m_Games[GameNumber]->GetPlayerFromName( m_GHost->m_Games[GameNumber]->GetOwnerName( ), false ) && !IsRootAdmin( User ) ) - QueueChatCommand( m_GHost->m_Language->CantEndGameOwnerIsStillPlaying( m_GHost->m_Games[GameNumber]->GetOwnerName( ) ), User, Whisper ); - else - { - QueueChatCommand( m_GHost->m_Language->EndingGame( m_GHost->m_Games[GameNumber]->GetDescription( ) ), User, Whisper ); - CONSOLE_Print( "[GAME: " + m_GHost->m_Games[GameNumber]->GetGameName( ) + "] is over (admin ended game)" ); - m_GHost->m_Games[GameNumber]->StopPlayers( "was disconnected (admin ended game)" ); - } - } - else - QueueChatCommand( m_GHost->m_Language->GameNumberDoesntExist( Payload ), User, Whisper ); - } - - // - // !ENFORCESG - // - - if( Command == "enforcesg" && !Payload.empty( ) ) - { - // only load files in the current directory just to be safe - - if( Payload.find( "/" ) != string :: npos || Payload.find( "\\" ) != string :: npos ) - QueueChatCommand( m_GHost->m_Language->UnableToLoadReplaysOutside( ), User, Whisper ); - else - { - string File = m_GHost->m_ReplayPath + Payload + ".w3g"; - - if( UTIL_FileExists( File ) ) - { - QueueChatCommand( m_GHost->m_Language->LoadingReplay( File ), User, Whisper ); - CReplay *Replay = new CReplay( ); - Replay->Load( File, false ); - Replay->ParseReplay( false ); - m_GHost->m_EnforcePlayers = Replay->GetPlayers( ); - delete Replay; - } - else - QueueChatCommand( m_GHost->m_Language->UnableToLoadReplayDoesntExist( File ), User, Whisper ); - } - } - - // - // !EXIT - // !QUIT - // - - if( Command == "exit" || Command == "quit" ) - { - if( IsRootAdmin( User ) ) - { - if( Payload == "nice" ) - m_GHost->m_ExitingNice = true; - else if( Payload == "force" ) - m_Exiting = true; - else - { - if( m_GHost->m_CurrentGame || !m_GHost->m_Games.empty( ) ) - QueueChatCommand( m_GHost->m_Language->AtLeastOneGameActiveUseForceToShutdown( ), User, Whisper ); - else - m_Exiting = true; - } - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !GETCLAN - // - - if( Command == "getclan" ) - { - SendGetClanList( ); - QueueChatCommand( m_GHost->m_Language->UpdatingClanList( ), User, Whisper ); - } - - // - // !GETFRIENDS - // - - if( Command == "getfriends" ) - { - SendGetFriendsList( ); - QueueChatCommand( m_GHost->m_Language->UpdatingFriendsList( ), User, Whisper ); - } - - // - // !GETGAME - // - - if( Command == "getgame" && !Payload.empty( ) ) - { - uint32_t GameNumber = UTIL_ToUInt32( Payload ) - 1; - - if( GameNumber < m_GHost->m_Games.size( ) ) - QueueChatCommand( m_GHost->m_Language->GameNumberIs( Payload, m_GHost->m_Games[GameNumber]->GetDescription( ) ), User, Whisper ); - else - QueueChatCommand( m_GHost->m_Language->GameNumberDoesntExist( Payload ), User, Whisper ); - } - - // - // !GETGAMES - // - - if( Command == "getgames" ) - { - if( m_GHost->m_CurrentGame ) - QueueChatCommand( m_GHost->m_Language->GameIsInTheLobby( m_GHost->m_CurrentGame->GetDescription( ), UTIL_ToString( m_GHost->m_Games.size( ) ), UTIL_ToString( m_GHost->m_MaxGames ) ), User, Whisper ); - else - QueueChatCommand( m_GHost->m_Language->ThereIsNoGameInTheLobby( UTIL_ToString( m_GHost->m_Games.size( ) ), UTIL_ToString( m_GHost->m_MaxGames ) ), User, Whisper ); - } - - // - // !HOLD (hold a slot for someone) - // - - if( Command == "hold" && !Payload.empty( ) && m_GHost->m_CurrentGame ) - { - // hold as many players as specified, e.g. "Varlock Kilranin" holds players "Varlock" and "Kilranin" - - stringstream SS; - SS << Payload; - - while( !SS.eof( ) ) - { - string HoldName; - SS >> HoldName; - - if( SS.fail( ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to hold command" ); - break; - } - else - { - QueueChatCommand( m_GHost->m_Language->AddedPlayerToTheHoldList( HoldName ), User, Whisper ); - m_GHost->m_CurrentGame->AddToReserved( HoldName ); - } - } - } - - // - // !HOSTSG - // - - if( Command == "hostsg" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, true, Payload, User, User, m_Server, Whisper ); - - // - // !LOAD (load config file) - // - - if( Command == "load" ) - { - if( Payload.empty( ) ) - QueueChatCommand( m_GHost->m_Language->CurrentlyLoadedMapCFGIs( m_GHost->m_Map->GetCFGFile( ) ), User, Whisper ); - else - { - string FoundMapConfigs; - - try - { - path MapCFGPath( m_GHost->m_MapCFGPath ); - string Pattern = Payload; - transform( Pattern.begin( ), Pattern.end( ), Pattern.begin( ), (int(*)(int))tolower ); - - if( !exists( MapCFGPath ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error listing map configs - map config path doesn't exist" ); - QueueChatCommand( m_GHost->m_Language->ErrorListingMapConfigs( ), User, Whisper ); - } - else - { - directory_iterator EndIterator; - path LastMatch; - uint32_t Matches = 0; - - for( directory_iterator i( MapCFGPath ); i != EndIterator; i++ ) - { - string FileName = i->filename( ); - string Stem = i->path( ).stem( ); - transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower ); - transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower ); - - if( !is_directory( i->status( ) ) && i->path( ).extension( ) == ".cfg" && FileName.find( Pattern ) != string :: npos ) - { - LastMatch = i->path( ); - Matches++; - - if( FoundMapConfigs.empty( ) ) - FoundMapConfigs = i->filename( ); - else - FoundMapConfigs += ", " + i->filename( ); - - // if the pattern matches the filename exactly, with or without extension, stop any further matching - - if( FileName == Pattern || Stem == Pattern ) - { - Matches = 1; - break; - } - } - } - - if( Matches == 0 ) - QueueChatCommand( m_GHost->m_Language->NoMapConfigsFound( ), User, Whisper ); - else if( Matches == 1 ) - { - string File = LastMatch.filename( ); - QueueChatCommand( m_GHost->m_Language->LoadingConfigFile( m_GHost->m_MapCFGPath + File ), User, Whisper ); - CConfig MapCFG; - MapCFG.Read( LastMatch.string( ) ); - m_GHost->m_Map->Load( &MapCFG, m_GHost->m_MapCFGPath + File ); - } - else - QueueChatCommand( m_GHost->m_Language->FoundMapConfigs( FoundMapConfigs ), User, Whisper ); - } - } - catch( const exception &ex ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error listing map configs - caught exception [" + ex.what( ) + "]" ); - QueueChatCommand( m_GHost->m_Language->ErrorListingMapConfigs( ), User, Whisper ); - } - } - } - - // - // !LOADSG - // - - if( Command == "loadsg" && !Payload.empty( ) ) - { - // only load files in the current directory just to be safe - - if( Payload.find( "/" ) != string :: npos || Payload.find( "\\" ) != string :: npos ) - QueueChatCommand( m_GHost->m_Language->UnableToLoadSaveGamesOutside( ), User, Whisper ); - else - { - string File = m_GHost->m_SaveGamePath + Payload + ".w3z"; - string FileNoPath = Payload + ".w3z"; - - if( UTIL_FileExists( File ) ) - { - if( m_GHost->m_CurrentGame ) - QueueChatCommand( m_GHost->m_Language->UnableToLoadSaveGameGameInLobby( ), User, Whisper ); - else - { - QueueChatCommand( m_GHost->m_Language->LoadingSaveGame( File ), User, Whisper ); - m_GHost->m_SaveGame->Load( File, false ); - m_GHost->m_SaveGame->ParseSaveGame( ); - m_GHost->m_SaveGame->SetFileName( File ); - m_GHost->m_SaveGame->SetFileNameNoPath( FileNoPath ); - } - } - else - QueueChatCommand( m_GHost->m_Language->UnableToLoadSaveGameDoesntExist( File ), User, Whisper ); - } - } - - // - // !MAP (load map file) - // - - if( Command == "map" ) - { - if( Payload.empty( ) ) - QueueChatCommand( m_GHost->m_Language->CurrentlyLoadedMapCFGIs( m_GHost->m_Map->GetCFGFile( ) ), User, Whisper ); - else - { - string FoundMaps; - - try - { - path MapPath( m_GHost->m_MapPath ); - string Pattern = Payload; - transform( Pattern.begin( ), Pattern.end( ), Pattern.begin( ), (int(*)(int))tolower ); - - if( !exists( MapPath ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error listing maps - map path doesn't exist" ); - QueueChatCommand( m_GHost->m_Language->ErrorListingMaps( ), User, Whisper ); - } - else - { - directory_iterator EndIterator; - path LastMatch; - uint32_t Matches = 0; - - for( directory_iterator i( MapPath ); i != EndIterator; i++ ) - { - string FileName = i->filename( ); - string Stem = i->path( ).stem( ); - transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower ); - transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower ); - - if( !is_directory( i->status( ) ) && FileName.find( Pattern ) != string :: npos ) - { - LastMatch = i->path( ); - Matches++; - - if( FoundMaps.empty( ) ) - FoundMaps = i->filename( ); - else - FoundMaps += ", " + i->filename( ); - - // if the pattern matches the filename exactly, with or without extension, stop any further matching - - if( FileName == Pattern || Stem == Pattern ) - { - Matches = 1; - break; - } - } - } - - if( Matches == 0 ) - QueueChatCommand( m_GHost->m_Language->NoMapsFound( ), User, Whisper ); - else if( Matches == 1 ) - { - string File = LastMatch.filename( ); - QueueChatCommand( m_GHost->m_Language->LoadingConfigFile( File ), User, Whisper ); - - // hackhack: create a config file in memory with the required information to load the map - - CConfig MapCFG; - MapCFG.Set( "map_path", "Maps\\Download\\" + File ); - MapCFG.Set( "map_localpath", File ); - m_GHost->m_Map->Load( &MapCFG, File ); - } - else - QueueChatCommand( m_GHost->m_Language->FoundMaps( FoundMaps ), User, Whisper ); - } - } - catch( const exception &ex ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error listing maps - caught exception [" + ex.what( ) + "]" ); - QueueChatCommand( m_GHost->m_Language->ErrorListingMaps( ), User, Whisper ); - } - } - } - - // - // !OPEN (open slot) - // - - if( Command == "open" && !Payload.empty( ) && m_GHost->m_CurrentGame ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - { - // open as many slots as specified, e.g. "5 10" opens slots 5 and 10 - - stringstream SS; - SS << Payload; - - while( !SS.eof( ) ) - { - uint32_t SID; - SS >> SID; - - if( SS.fail( ) ) - { - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to open command" ); - break; - } - else - m_GHost->m_CurrentGame->OpenSlot( (unsigned char)( SID - 1 ), true ); - } - } - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !OPENALL - // - - if( Command == "openall" && m_GHost->m_CurrentGame ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - m_GHost->m_CurrentGame->OpenAllSlots( ); - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !PRIV (host private game) - // - - if( Command == "priv" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, false, Payload, User, User, m_Server, Whisper ); - - // - // !PRIVBY (host private game by other player) - // - - if( Command == "privby" && !Payload.empty( ) ) - { - // extract the owner and the game name - // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" - - string Owner; - string GameName; - string :: size_type GameNameStart = Payload.find( " " ); - - if( GameNameStart != string :: npos ) - { - Owner = Payload.substr( 0, GameNameStart ); - GameName = Payload.substr( GameNameStart + 1 ); - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, false, GameName, Owner, User, m_Server, Whisper ); - } - } - - // - // !PUB (host public game) - // - - if( Command == "pub" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PUBLIC, false, Payload, User, User, m_Server, Whisper ); - - // - // !PUBBY (host public game by other player) - // - - if( Command == "pubby" && !Payload.empty( ) ) - { - // extract the owner and the game name - // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" - - string Owner; - string GameName; - string :: size_type GameNameStart = Payload.find( " " ); - - if( GameNameStart != string :: npos ) - { - Owner = Payload.substr( 0, GameNameStart ); - GameName = Payload.substr( GameNameStart + 1 ); - m_GHost->CreateGame( m_GHost->m_Map, GAME_PUBLIC, false, GameName, Owner, User, m_Server, Whisper ); - } - } - - // - // !RELOAD - // - - if( Command == "reload" ) - { - if( IsRootAdmin( User ) ) - { - QueueChatCommand( m_GHost->m_Language->ReloadingConfigurationFiles( ), User, Whisper ); - m_GHost->ReloadConfigs( ); - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !SAY - // - - if( Command == "say" && !Payload.empty( ) ) - QueueChatCommand( Payload ); - - // - // !SAYGAME - // - - if( Command == "saygame" && !Payload.empty( ) ) - { - if( IsRootAdmin( User ) ) - { - // extract the game number and the message - // e.g. "3 hello everyone" -> game number: "3", message: "hello everyone" - - uint32_t GameNumber; - string Message; - stringstream SS; - SS << Payload; - SS >> GameNumber; - - if( SS.fail( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to saygame command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to saygame command" ); - else - { - getline( SS, Message ); - string :: size_type Start = Message.find_first_not_of( " " ); - - if( Start != string :: npos ) - Message = Message.substr( Start ); - - if( GameNumber - 1 < m_GHost->m_Games.size( ) ) - m_GHost->m_Games[GameNumber - 1]->SendAllChat( "ADMIN: " + Message ); - else - QueueChatCommand( m_GHost->m_Language->GameNumberDoesntExist( UTIL_ToString( GameNumber ) ), User, Whisper ); - } - } - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !SAYGAMES - // - - if( Command == "saygames" && !Payload.empty( ) ) - { - if( IsRootAdmin( User ) ) - { - if( m_GHost->m_CurrentGame ) - m_GHost->m_CurrentGame->SendAllChat( Payload ); - - for( vector :: iterator i = m_GHost->m_Games.begin( ); i != m_GHost->m_Games.end( ); i++ ) - (*i)->SendAllChat( "ADMIN: " + Payload ); - } - else - QueueChatCommand( m_GHost->m_Language->YouDontHaveAccessToThatCommand( ), User, Whisper ); - } - - // - // !SP - // - - if( Command == "sp" && m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetCountDownStarted( ) ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - { - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->ShufflingPlayers( ) ); - m_GHost->m_CurrentGame->ShuffleSlots( ); - } - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !START - // - - if( Command == "start" && m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetCountDownStarted( ) && m_GHost->m_CurrentGame->GetNumHumanPlayers( ) > 0 ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - { - // if the player sent "!start force" skip the checks and start the countdown - // otherwise check that the game is ready to start - - if( Payload == "force" ) - m_GHost->m_CurrentGame->StartCountDown( true ); - else - m_GHost->m_CurrentGame->StartCountDown( false ); - } - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !SWAP (swap slots) - // - - if( Command == "swap" && !Payload.empty( ) && m_GHost->m_CurrentGame ) - { - if( !m_GHost->m_CurrentGame->GetLocked( ) ) - { - uint32_t SID1; - uint32_t SID2; - stringstream SS; - SS << Payload; - SS >> SID1; - - if( SS.fail( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to swap command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to swap command" ); - else - { - SS >> SID2; - - if( SS.fail( ) ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to swap command" ); - else - m_GHost->m_CurrentGame->SwapSlots( (unsigned char)( SID1 - 1 ), (unsigned char)( SID2 - 1 ) ); - } - } - } - else - QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper ); - } - - // - // !UNHOST - // - - if( Command == "unhost" ) - { - if( m_GHost->m_CurrentGame ) - { - if( m_GHost->m_CurrentGame->GetCountDownStarted( ) ) - QueueChatCommand( m_GHost->m_Language->UnableToUnhostGameCountdownStarted( m_GHost->m_CurrentGame->GetDescription( ) ), User, Whisper ); - - // if the game owner is still in the game only allow the root admin to unhost the game - - else if( m_GHost->m_CurrentGame->GetPlayerFromName( m_GHost->m_CurrentGame->GetOwnerName( ), false ) && !IsRootAdmin( User ) ) - QueueChatCommand( m_GHost->m_Language->CantUnhostGameOwnerIsPresent( m_GHost->m_CurrentGame->GetOwnerName( ) ), User, Whisper ); - else - { - QueueChatCommand( m_GHost->m_Language->UnhostingGame( m_GHost->m_CurrentGame->GetDescription( ) ), User, Whisper ); - m_GHost->m_CurrentGame->SetExiting( true ); - } - } - else - QueueChatCommand( m_GHost->m_Language->UnableToUnhostGameNoGameInLobby( ), User, Whisper ); - } - - // - // !WARDENSTATUS - // - - if( Command == "wardenstatus" ) - { - if( m_BNLSClient ) - QueueChatCommand( "WARDEN STATUS --- " + UTIL_ToString( m_BNLSClient->GetTotalWardenIn( ) ) + " requests received, " + UTIL_ToString( m_BNLSClient->GetTotalWardenOut( ) ) + " responses sent.", User, Whisper ); - else - QueueChatCommand( "WARDEN STATUS --- Not connected to BNLS server.", User, Whisper ); - } - } - else - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] non-admin [" + User + "] sent command [" + Message + "]" ); - - /********************* - * NON ADMIN COMMANDS * - *********************/ - - // don't respond to non admins if there are more than 3 messages already in the queue - // this prevents malicious users from filling up the bot's chat queue and crippling the bot - // in some cases the queue may be full of legitimate messages but we don't really care if the bot ignores one of these commands once in awhile - // e.g. when several users join a game at the same time and cause multiple /whois messages to be queued at once - - if( IsAdmin( User ) || IsRootAdmin( User ) || ( m_PublicCommands && m_OutPackets.size( ) <= 3 ) ) - { - // - // !STATS - // - - if( Command == "stats" ) - { - string StatsUser = User; - - if( !Payload.empty( ) ) - StatsUser = Payload; - - // check for potential abuse - - if( !StatsUser.empty( ) && StatsUser.size( ) < 16 && StatsUser[0] != '/' ) - m_PairedGPSChecks.push_back( PairedGPSCheck( Whisper ? User : string( ), m_GHost->m_DB->ThreadedGamePlayerSummaryCheck( StatsUser ) ) ); - } - - // - // !STATSDOTA - // - - if( Command == "statsdota" ) - { - string StatsUser = User; - - if( !Payload.empty( ) ) - StatsUser = Payload; - - // check for potential abuse - - if( !StatsUser.empty( ) && StatsUser.size( ) < 16 && StatsUser[0] != '/' ) - m_PairedDPSChecks.push_back( PairedDPSCheck( Whisper ? User : string( ), m_GHost->m_DB->ThreadedDotAPlayerSummaryCheck( StatsUser ) ) ); - } - - // - // !VERSION - // - - if( Command == "version" ) - { - if( IsAdmin( User ) || IsRootAdmin( User ) ) - QueueChatCommand( m_GHost->m_Language->VersionAdmin( m_GHost->m_Version ), User, Whisper ); - else - QueueChatCommand( m_GHost->m_Language->VersionNotAdmin( m_GHost->m_Version ), User, Whisper ); - } - } - } - } - else if( Event == CBNETProtocol :: EID_CHANNEL ) - { - // keep track of current channel so we can rejoin it after hosting a game - - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joined channel [" + Message + "]" ); - m_CurrentChannel = Message; - } - else if( Event == CBNETProtocol :: EID_INFO ) - { - CONSOLE_Print( "[INFO: " + m_ServerAlias + "] " + Message ); - - // extract the first word which we hope is the username - // this is not necessarily true though since info messages also include channel MOTD's and such - - string UserName; - string :: size_type Split = Message.find( " " ); - - if( Split != string :: npos ) - UserName = Message.substr( 0, Split ); - else - UserName = Message.substr( 0 ); - - // handle spoof checking for current game - // this case covers whois results which are used when hosting a public game (we send out a "/whois [player]" for each player) - // at all times you can still /w the bot with "spoofcheck" to manually spoof check - - if( m_GHost->m_CurrentGame && m_GHost->m_CurrentGame->GetPlayerFromName( UserName, true ) ) - { - if( Message.find( "is away" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofPossibleIsAway( UserName ) ); - else if( Message.find( "is unavailable" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofPossibleIsUnavailable( UserName ) ); - else if( Message.find( "is refusing messages" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofPossibleIsRefusingMessages( UserName ) ); - else if( Message.find( "is using Warcraft III The Frozen Throne in the channel" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofDetectedIsNotInGame( UserName ) ); - else if( Message.find( "is using Warcraft III The Frozen Throne in channel" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofDetectedIsNotInGame( UserName ) ); - else if( Message.find( "is using Warcraft III The Frozen Throne in a private channel" ) != string :: npos ) - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofDetectedIsInPrivateChannel( UserName ) ); - - if( Message.find( "is using Warcraft III The Frozen Throne in game" ) != string :: npos || Message.find( "is using Warcraft III Frozen Throne and is currently in game" ) != string :: npos ) - { - // check both the current game name and the last game name against the /whois response - // this is because when the game is rehosted, players who joined recently will be in the previous game according to battle.net - // note: if the game is rehosted more than once it is possible (but unlikely) for a false positive because only two game names are checked - - if( Message.find( m_GHost->m_CurrentGame->GetGameName( ) ) != string :: npos || Message.find( m_GHost->m_CurrentGame->GetLastGameName( ) ) != string :: npos ) - m_GHost->m_CurrentGame->AddToSpoofed( m_Server, UserName, false ); - else - m_GHost->m_CurrentGame->SendAllChat( m_GHost->m_Language->SpoofDetectedIsInAnotherGame( UserName ) ); - } - } - } - else if( Event == CBNETProtocol :: EID_ERROR ) - CONSOLE_Print( "[ERROR: " + m_ServerAlias + "] " + Message ); - else if( Event == CBNETProtocol :: EID_EMOTE ) - { - CONSOLE_Print( "[EMOTE: " + m_ServerAlias + "] [" + User + "] " + Message ); - m_GHost->EventBNETEmote( this, User, Message ); - } -} - -void CBNET :: SendJoinChannel( string channel ) -{ - if( m_LoggedIn && m_InChat ) - m_Socket->PutBytes( m_Protocol->SEND_SID_JOINCHANNEL( channel ) ); -} - -void CBNET :: SendGetFriendsList( ) -{ - if( m_LoggedIn ) - m_Socket->PutBytes( m_Protocol->SEND_SID_FRIENDSLIST( ) ); -} - -void CBNET :: SendGetClanList( ) -{ - if( m_LoggedIn ) - m_Socket->PutBytes( m_Protocol->SEND_SID_CLANMEMBERLIST( ) ); -} - -void CBNET :: QueueEnterChat( ) -{ - if( m_LoggedIn ) - m_OutPackets.push( m_Protocol->SEND_SID_ENTERCHAT( ) ); -} - -void CBNET :: QueueChatCommand( string chatCommand ) -{ - if( chatCommand.empty( ) ) - return; - - if( m_LoggedIn ) - { - if( m_PasswordHashType == "pvpgn" && chatCommand.size( ) > m_MaxMessageLength ) - chatCommand = chatCommand.substr( 0, m_MaxMessageLength ); - - if( chatCommand.size( ) > 255 ) - chatCommand = chatCommand.substr( 0, 255 ); - - if( m_OutPackets.size( ) > 10 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempted to queue chat command [" + chatCommand + "] but there are too many (" + UTIL_ToString( m_OutPackets.size( ) ) + ") packets queued, discarding" ); - else - { - CONSOLE_Print( "[QUEUED: " + m_ServerAlias + "] " + chatCommand ); - m_OutPackets.push( m_Protocol->SEND_SID_CHATCOMMAND( chatCommand ) ); - } - } -} - -void CBNET :: QueueChatCommand( string chatCommand, string user, bool whisper ) -{ - if( chatCommand.empty( ) ) - return; - - // if whisper is true send the chat command as a whisper to user, otherwise just queue the chat command - - if( whisper ) - QueueChatCommand( "/w " + user + " " + chatCommand ); - else - QueueChatCommand( chatCommand ); -} - -void CBNET :: QueueGameCreate( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *savegame, uint32_t hostCounter ) -{ - if( m_LoggedIn && map ) - { - if( !m_CurrentChannel.empty( ) ) - m_FirstChannel = m_CurrentChannel; - - m_InChat = false; - - // a game creation message is just a game refresh message with upTime = 0 - - QueueGameRefresh( state, gameName, hostName, map, savegame, 0, hostCounter ); - } -} - -void CBNET :: QueueGameRefresh( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *saveGame, uint32_t upTime, uint32_t hostCounter ) -{ - if( hostName.empty( ) ) - { - BYTEARRAY UniqueName = m_Protocol->GetUniqueName( ); - hostName = string( UniqueName.begin( ), UniqueName.end( ) ); - } - - if( m_LoggedIn && map ) - { - // construct a fixed host counter which will be used to identify players from this realm - // the fixed host counter's 4 most significant bits will contain a 4 bit ID (0-15) - // the rest of the fixed host counter will contain the 28 least significant bits of the actual host counter - // since we're destroying 4 bits of information here the actual host counter should not be greater than 2^28 which is a reasonable assumption - // when a player joins a game we can obtain the ID from the received host counter - // note: LAN broadcasts use an ID of 0, battle.net refreshes use an ID of 1-10, the rest are unused - - uint32_t FixedHostCounter = ( hostCounter & 0x0FFFFFFF ) | ( m_HostCounterID << 28 ); - - if( saveGame ) - { - uint32_t MapGameType = MAPGAMETYPE_SAVEDGAME; - - // the state should always be private when creating a saved game - - if( state == GAME_PRIVATE ) - MapGameType |= MAPGAMETYPE_PRIVATEGAME; - - // use an invalid map width/height to indicate reconnectable games - - BYTEARRAY MapWidth; - MapWidth.push_back( 192 ); - MapWidth.push_back( 7 ); - BYTEARRAY MapHeight; - MapHeight.push_back( 192 ); - MapHeight.push_back( 7 ); - - if( m_GHost->m_Reconnect ) - m_OutPackets.push( m_Protocol->SEND_SID_STARTADVEX3( state, UTIL_CreateByteArray( MapGameType, false ), map->GetMapGameFlags( ), MapWidth, MapHeight, gameName, hostName, upTime, "Save\\Multiplayer\\" + saveGame->GetFileNameNoPath( ), saveGame->GetMagicNumber( ), map->GetMapSHA1( ), FixedHostCounter ) ); - else - m_OutPackets.push( m_Protocol->SEND_SID_STARTADVEX3( state, UTIL_CreateByteArray( MapGameType, false ), map->GetMapGameFlags( ), UTIL_CreateByteArray( (uint16_t)0, false ), UTIL_CreateByteArray( (uint16_t)0, false ), gameName, hostName, upTime, "Save\\Multiplayer\\" + saveGame->GetFileNameNoPath( ), saveGame->GetMagicNumber( ), map->GetMapSHA1( ), FixedHostCounter ) ); - } - else - { - uint32_t MapGameType = map->GetMapGameType( ); - MapGameType |= MAPGAMETYPE_UNKNOWN0; - - if( state == GAME_PRIVATE ) - MapGameType |= MAPGAMETYPE_PRIVATEGAME; - - // use an invalid map width/height to indicate reconnectable games - - BYTEARRAY MapWidth; - MapWidth.push_back( 192 ); - MapWidth.push_back( 7 ); - BYTEARRAY MapHeight; - MapHeight.push_back( 192 ); - MapHeight.push_back( 7 ); - - if( m_GHost->m_Reconnect ) - m_OutPackets.push( m_Protocol->SEND_SID_STARTADVEX3( state, UTIL_CreateByteArray( MapGameType, false ), map->GetMapGameFlags( ), MapWidth, MapHeight, gameName, hostName, upTime, map->GetMapPath( ), map->GetMapCRC( ), map->GetMapSHA1( ), FixedHostCounter ) ); - else - m_OutPackets.push( m_Protocol->SEND_SID_STARTADVEX3( state, UTIL_CreateByteArray( MapGameType, false ), map->GetMapGameFlags( ), map->GetMapWidth( ), map->GetMapHeight( ), gameName, hostName, upTime, map->GetMapPath( ), map->GetMapCRC( ), map->GetMapSHA1( ), FixedHostCounter ) ); - } - } -} - -void CBNET :: QueueGameUncreate( ) -{ - if( m_LoggedIn ) - m_OutPackets.push( m_Protocol->SEND_SID_STOPADV( ) ); -} - -void CBNET :: UnqueuePackets( unsigned char type ) -{ - queue Packets; - uint32_t Unqueued = 0; - - while( !m_OutPackets.empty( ) ) - { - // todotodo: it's very inefficient to have to copy all these packets while searching the queue - - BYTEARRAY Packet = m_OutPackets.front( ); - m_OutPackets.pop( ); - - if( Packet.size( ) >= 2 && Packet[1] == type ) - Unqueued++; - else - Packets.push( Packet ); - } - - m_OutPackets = Packets; - - if( Unqueued > 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] unqueued " + UTIL_ToString( Unqueued ) + " packets of type " + UTIL_ToString( type ) ); -} - -void CBNET :: UnqueueChatCommand( string chatCommand ) -{ - // hackhack: this is ugly code - // generate the packet that would be sent for this chat command - // then search the queue for that exact packet - - BYTEARRAY PacketToUnqueue = m_Protocol->SEND_SID_CHATCOMMAND( chatCommand ); - queue Packets; - uint32_t Unqueued = 0; - - while( !m_OutPackets.empty( ) ) - { - // todotodo: it's very inefficient to have to copy all these packets while searching the queue - - BYTEARRAY Packet = m_OutPackets.front( ); - m_OutPackets.pop( ); - - if( Packet == PacketToUnqueue ) - Unqueued++; - else - Packets.push( Packet ); - } - - m_OutPackets = Packets; - - if( Unqueued > 0 ) - CONSOLE_Print( "[BNET: " + m_ServerAlias + "] unqueued " + UTIL_ToString( Unqueued ) + " chat command packets" ); -} - -void CBNET :: UnqueueGameRefreshes( ) -{ - UnqueuePackets( CBNETProtocol :: SID_STARTADVEX3 ); -} - -bool CBNET :: IsAdmin( string name ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - for( vector :: iterator i = m_Admins.begin( ); i != m_Admins.end( ); i++ ) - { - if( *i == name ) - return true; - } - - return false; -} - -bool CBNET :: IsRootAdmin( string name ) -{ - // m_RootAdmin was already transformed to lower case in the constructor - - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - // updated to permit multiple root admins seperated by a space, e.g. "Varlock Kilranin Instinct121" - // note: this function gets called frequently so it would be better to parse the root admins just once and store them in a list somewhere - // however, it's hardly worth optimizing at this point since the code's already written - - stringstream SS; - string s; - SS << m_RootAdmin; - - while( !SS.eof( ) ) - { - SS >> s; - - if( name == s ) - return true; - } - - return false; -} - -CDBBan *CBNET :: IsBannedName( string name ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - // todotodo: optimize this - maybe use a map? - - for( vector :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) - { - if( (*i)->GetName( ) == name ) - return *i; - } - - return NULL; -} - -CDBBan *CBNET :: IsBannedIP( string ip ) -{ - // todotodo: optimize this - maybe use a map? - - for( vector :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) - { - if( (*i)->GetIP( ) == ip ) - return *i; - } - - return NULL; -} - -void CBNET :: AddAdmin( string name ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - m_Admins.push_back( name ); -} - -void CBNET :: AddBan( string name, string ip, string gamename, string admin, string reason ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - m_Bans.push_back( new CDBBan( m_Server, name, ip, "N/A", gamename, admin, reason ) ); -} - -void CBNET :: RemoveAdmin( string name ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - for( vector :: iterator i = m_Admins.begin( ); i != m_Admins.end( ); ) - { - if( *i == name ) - i = m_Admins.erase( i ); - else - i++; - } -} - -void CBNET :: RemoveBan( string name ) -{ - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - for( vector :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); ) - { - if( (*i)->GetName( ) == name ) - i = m_Bans.erase( i ); - else - i++; - } -} - -void CBNET :: HoldFriends( CBaseGame *game ) -{ - if( game ) - { - for( vector :: iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) - game->AddToReserved( (*i)->GetAccount( ) ); - } -} - -void CBNET :: HoldClan( CBaseGame *game ) -{ - if( game ) - { - for( vector :: iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) - game->AddToReserved( (*i)->GetName( ) ); - } -} diff --git a/ghost/bnet.h b/ghost/bnet.h deleted file mode 100644 index 488afbb..0000000 --- a/ghost/bnet.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef BNET_H -#define BNET_H - -// -// CBNET -// - -class CTCPClient; -class CCommandPacket; -class CBNCSUtilInterface; -class CBNETProtocol; -class CBNLSClient; -class CIncomingFriendList; -class CIncomingClanList; -class CIncomingChatEvent; -class CCallableAdminCount; -class CCallableAdminAdd; -class CCallableAdminRemove; -class CCallableAdminList; -class CCallableBanCount; -class CCallableBanAdd; -class CCallableBanRemove; -class CCallableBanList; -class CCallableGamePlayerSummaryCheck; -class CCallableDotAPlayerSummaryCheck; -class CDBBan; - -typedef pair PairedAdminCount; -typedef pair PairedAdminAdd; -typedef pair PairedAdminRemove; -typedef pair PairedBanCount; -typedef pair PairedBanAdd; -typedef pair PairedBanRemove; -typedef pair PairedGPSCheck; -typedef pair PairedDPSCheck; - -class CBNET -{ -public: - CGHost *m_GHost; - -private: - CTCPClient *m_Socket; // the connection to battle.net - CBNETProtocol *m_Protocol; // battle.net protocol - CBNLSClient *m_BNLSClient; // the BNLS client (for external warden handling) - queue m_Packets; // queue of incoming packets - CBNCSUtilInterface *m_BNCSUtil; // the interface to the bncsutil library (used for logging into battle.net) - queue m_OutPackets; // queue of outgoing packets to be sent (to prevent getting kicked for flooding) - vector m_Friends; // vector of friends - vector m_Clans; // vector of clan members - vector m_PairedAdminCounts; // vector of paired threaded database admin counts in progress - vector m_PairedAdminAdds; // vector of paired threaded database admin adds in progress - vector m_PairedAdminRemoves; // vector of paired threaded database admin removes in progress - vector m_PairedBanCounts; // vector of paired threaded database ban counts in progress - vector m_PairedBanAdds; // vector of paired threaded database ban adds in progress - vector m_PairedBanRemoves; // vector of paired threaded database ban removes in progress - vector m_PairedGPSChecks; // vector of paired threaded database game player summary checks in progress - vector m_PairedDPSChecks; // vector of paired threaded database DotA player summary checks in progress - CCallableAdminList *m_CallableAdminList; // threaded database admin list in progress - CCallableBanList *m_CallableBanList; // threaded database ban list in progress - vector m_Admins; // vector of cached admins - vector m_Bans; // vector of cached bans - bool m_Exiting; // set to true and this class will be deleted next update - string m_Server; // battle.net server to connect to - string m_ServerIP; // battle.net server to connect to (the IP address so we don't have to resolve it every time we connect) - string m_ServerAlias; // battle.net server alias (short name, e.g. "USEast") - string m_BNLSServer; // BNLS server to connect to (for warden handling) - uint16_t m_BNLSPort; // BNLS port - uint32_t m_BNLSWardenCookie; // BNLS warden cookie - string m_CDKeyROC; // ROC CD key - string m_CDKeyTFT; // TFT CD key - string m_CountryAbbrev; // country abbreviation - string m_Country; // country - uint32_t m_LocaleID; // see: http://msdn.microsoft.com/en-us/library/0h88fahh%28VS.85%29.aspx - string m_UserName; // battle.net username - string m_UserPassword; // battle.net password - string m_FirstChannel; // the first chat channel to join upon entering chat (note: we hijack this to store the last channel when entering a game) - string m_CurrentChannel; // the current chat channel - string m_RootAdmin; // the root admin - char m_CommandTrigger; // the character prefix to identify commands - unsigned char m_War3Version; // custom warcraft 3 version for PvPGN users - BYTEARRAY m_EXEVersion; // custom exe version for PvPGN users - BYTEARRAY m_EXEVersionHash; // custom exe version hash for PvPGN users - string m_PasswordHashType; // password hash type for PvPGN users - string m_PVPGNRealmName; // realm name for PvPGN users (for mutual friend spoofchecks) - uint32_t m_MaxMessageLength; // maximum message length for PvPGN users - uint32_t m_HostCounterID; // the host counter ID to identify players from this realm - uint32_t m_LastDisconnectedTime; // GetTime when we were last disconnected from battle.net - uint32_t m_LastConnectionAttemptTime; // GetTime when we last attempted to connect to battle.net - uint32_t m_LastNullTime; // GetTime when the last null packet was sent for detecting disconnects - uint32_t m_LastOutPacketTicks; // GetTicks when the last packet was sent for the m_OutPackets queue - uint32_t m_LastOutPacketSize; - uint32_t m_LastAdminRefreshTime; // GetTime when the admin list was last refreshed from the database - uint32_t m_LastBanRefreshTime; // GetTime when the ban list was last refreshed from the database - bool m_FirstConnect; // if we haven't tried to connect to battle.net yet - bool m_WaitingToConnect; // if we're waiting to reconnect to battle.net after being disconnected - bool m_LoggedIn; // if we've logged into battle.net or not - bool m_InChat; // if we've entered chat or not (but we're not necessarily in a chat channel yet) - bool m_HoldFriends; // whether to auto hold friends when creating a game or not - bool m_HoldClan; // whether to auto hold clan members when creating a game or not - bool m_PublicCommands; // whether to allow public commands or not - -public: - CBNET( CGHost *nGHost, string nServer, string nServerAlias, string nBNLSServer, uint16_t nBNLSPort, uint32_t nBNLSWardenCookie, string nCDKeyROC, string nCDKeyTFT, string nCountryAbbrev, string nCountry, uint32_t nLocaleID, string nUserName, string nUserPassword, string nFirstChannel, string nRootAdmin, char nCommandTrigger, bool nHoldFriends, bool nHoldClan, bool nPublicCommands, unsigned char nWar3Version, BYTEARRAY nEXEVersion, BYTEARRAY nEXEVersionHash, string nPasswordHashType, string nPVPGNRealmName, uint32_t nMaxMessageLength, uint32_t nHostCounterID ); - ~CBNET( ); - - bool GetExiting( ) { return m_Exiting; } - string GetServer( ) { return m_Server; } - string GetServerAlias( ) { return m_ServerAlias; } - string GetCDKeyROC( ) { return m_CDKeyROC; } - string GetCDKeyTFT( ) { return m_CDKeyTFT; } - string GetUserName( ) { return m_UserName; } - string GetUserPassword( ) { return m_UserPassword; } - string GetFirstChannel( ) { return m_FirstChannel; } - string GetCurrentChannel( ) { return m_CurrentChannel; } - string GetRootAdmin( ) { return m_RootAdmin; } - char GetCommandTrigger( ) { return m_CommandTrigger; } - BYTEARRAY GetEXEVersion( ) { return m_EXEVersion; } - BYTEARRAY GetEXEVersionHash( ) { return m_EXEVersionHash; } - string GetPasswordHashType( ) { return m_PasswordHashType; } - string GetPVPGNRealmName( ) { return m_PVPGNRealmName; } - uint32_t GetHostCounterID( ) { return m_HostCounterID; } - bool GetLoggedIn( ) { return m_LoggedIn; } - bool GetInChat( ) { return m_InChat; } - bool GetHoldFriends( ) { return m_HoldFriends; } - bool GetHoldClan( ) { return m_HoldClan; } - bool GetPublicCommands( ) { return m_PublicCommands; } - uint32_t GetOutPacketsQueued( ) { return m_OutPackets.size( ); } - BYTEARRAY GetUniqueName( ); - - // processing functions - - unsigned int SetFD( void *fd, void *send_fd, int *nfds ); - bool Update( void *fd, void *send_fd ); - void ExtractPackets( ); - void ProcessPackets( ); - void ProcessChatEvent( CIncomingChatEvent *chatEvent ); - - // functions to send packets to battle.net - - void SendJoinChannel( string channel ); - void SendGetFriendsList( ); - void SendGetClanList( ); - void QueueEnterChat( ); - void QueueChatCommand( string chatCommand ); - void QueueChatCommand( string chatCommand, string user, bool whisper ); - void QueueGameCreate( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *saveGame, uint32_t hostCounter ); - void QueueGameRefresh( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *saveGame, uint32_t upTime, uint32_t hostCounter ); - void QueueGameUncreate( ); - - void UnqueuePackets( unsigned char type ); - void UnqueueChatCommand( string chatCommand ); - void UnqueueGameRefreshes( ); - - // other functions - - bool IsAdmin( string name ); - bool IsRootAdmin( string name ); - CDBBan *IsBannedName( string name ); - CDBBan *IsBannedIP( string ip ); - void AddAdmin( string name ); - void AddBan( string name, string ip, string gamename, string admin, string reason ); - void RemoveAdmin( string name ); - void RemoveBan( string name ); - void HoldFriends( CBaseGame *game ); - void HoldClan( CBaseGame *game ); -}; - -#endif diff --git a/ghost/bnetprotocol.cpp b/ghost/bnetprotocol.cpp deleted file mode 100644 index 3176405..0000000 --- a/ghost/bnetprotocol.cpp +++ /dev/null @@ -1,1144 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "bnetprotocol.h" - -CBNETProtocol :: CBNETProtocol( ) -{ - unsigned char ClientToken[] = { 220, 1, 203, 7 }; - m_ClientToken = UTIL_CreateByteArray( ClientToken, 4 ); -} - -CBNETProtocol :: ~CBNETProtocol( ) -{ - -} - -/////////////////////// -// RECEIVE FUNCTIONS // -/////////////////////// - -bool CBNETProtocol :: RECEIVE_SID_NULL( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_NULL" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - - return ValidateLength( data ); -} - -CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_GETADVLISTEX" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> GamesFound - // if( GamesFound > 0 ) - // 10 bytes -> ??? - // 2 bytes -> Port - // 4 bytes -> IP - // null term string -> GameName - // 2 bytes -> ??? - // 8 bytes -> HostCounter - - if( ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY GamesFound = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - if( UTIL_ByteArrayToUInt32( GamesFound, false ) > 0 && data.size( ) >= 25 ) - { - BYTEARRAY Port = BYTEARRAY( data.begin( ) + 18, data.begin( ) + 20 ); - BYTEARRAY IP = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 24 ); - BYTEARRAY GameName = UTIL_ExtractCString( data, 24 ); - - if( data.size( ) >= GameName.size( ) + 35 ) - { - BYTEARRAY HostCounter; - HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) ); - HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) ); - HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) ); - HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) ); - return new CIncomingGameHost( IP, - UTIL_ByteArrayToUInt16( Port, false ), - string( GameName.begin( ), GameName.end( ) ), - HostCounter ); - } - } - } - - return NULL; -} - -bool CBNETProtocol :: RECEIVE_SID_ENTERCHAT( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_ENTERCHAT" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // null terminated string -> UniqueName - - if( ValidateLength( data ) && data.size( ) >= 5 ) - { - m_UniqueName = UTIL_ExtractCString( data, 4 ); - return true; - } - - return false; -} - -CIncomingChatEvent *CBNETProtocol :: RECEIVE_SID_CHATEVENT( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_CHATEVENT" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> EventID - // 4 bytes -> ??? - // 4 bytes -> Ping - // 12 bytes -> ??? - // null terminated string -> User - // null terminated string -> Message - - if( ValidateLength( data ) && data.size( ) >= 29 ) - { - BYTEARRAY EventID = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - BYTEARRAY Ping = BYTEARRAY( data.begin( ) + 12, data.begin( ) + 16 ); - BYTEARRAY User = UTIL_ExtractCString( data, 28 ); - BYTEARRAY Message = UTIL_ExtractCString( data, User.size( ) + 29 ); - - switch( UTIL_ByteArrayToUInt32( EventID, false ) ) - { - case CBNETProtocol :: EID_SHOWUSER: - case CBNETProtocol :: EID_JOIN: - case CBNETProtocol :: EID_LEAVE: - case CBNETProtocol :: EID_WHISPER: - case CBNETProtocol :: EID_TALK: - case CBNETProtocol :: EID_BROADCAST: - case CBNETProtocol :: EID_CHANNEL: - case CBNETProtocol :: EID_USERFLAGS: - case CBNETProtocol :: EID_WHISPERSENT: - case CBNETProtocol :: EID_CHANNELFULL: - case CBNETProtocol :: EID_CHANNELDOESNOTEXIST: - case CBNETProtocol :: EID_CHANNELRESTRICTED: - case CBNETProtocol :: EID_INFO: - case CBNETProtocol :: EID_ERROR: - case CBNETProtocol :: EID_EMOTE: - return new CIncomingChatEvent( (CBNETProtocol :: IncomingChatEvent)UTIL_ByteArrayToUInt32( EventID, false ), - UTIL_ByteArrayToUInt32( Ping, false ), - string( User.begin( ), User.end( ) ), - string( Message.begin( ), Message.end( ) ) ); - } - - } - - return NULL; -} - -bool CBNETProtocol :: RECEIVE_SID_CHECKAD( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_CHECKAD" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - - return ValidateLength( data ); -} - -bool CBNETProtocol :: RECEIVE_SID_STARTADVEX3( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_STARTADVEX3" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Status - - if( ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY Status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - if( UTIL_ByteArrayToUInt32( Status, false ) == 0 ) - return true; - } - - return false; -} - -BYTEARRAY CBNETProtocol :: RECEIVE_SID_PING( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_PING" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Ping - - if( ValidateLength( data ) && data.size( ) >= 8 ) - return BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - return BYTEARRAY( ); -} - -bool CBNETProtocol :: RECEIVE_SID_LOGONRESPONSE( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_LOGONRESPONSE" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Status - - if( ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY Status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - if( UTIL_ByteArrayToUInt32( Status, false ) == 1 ) - return true; - } - - return false; -} - -bool CBNETProtocol :: RECEIVE_SID_AUTH_INFO( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_AUTH_INFO" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> LogonType - // 4 bytes -> ServerToken - // 4 bytes -> ??? - // 8 bytes -> MPQFileTime - // null terminated string -> IX86VerFileName - // null terminated string -> ValueStringFormula - - if( ValidateLength( data ) && data.size( ) >= 25 ) - { - m_LogonType = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - m_ServerToken = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); - m_MPQFileTime = BYTEARRAY( data.begin( ) + 16, data.begin( ) + 24 ); - m_IX86VerFileName = UTIL_ExtractCString( data, 24 ); - m_ValueStringFormula = UTIL_ExtractCString( data, m_IX86VerFileName.size( ) + 25 ); - return true; - } - - return false; -} - -bool CBNETProtocol :: RECEIVE_SID_AUTH_CHECK( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_AUTH_CHECK" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> KeyState - // null terminated string -> KeyStateDescription - - if( ValidateLength( data ) && data.size( ) >= 9 ) - { - m_KeyState = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - m_KeyStateDescription = UTIL_ExtractCString( data, 8 ); - - if( UTIL_ByteArrayToUInt32( m_KeyState, false ) == KR_GOOD ) - return true; - } - - return false; -} - -bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGON( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGON" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Status - // if( Status == 0 ) - // 32 bytes -> Salt - // 32 bytes -> ServerPublicKey - - if( ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - if( UTIL_ByteArrayToUInt32( status, false ) == 0 && data.size( ) >= 72 ) - { - m_Salt = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 40 ); - m_ServerPublicKey = BYTEARRAY( data.begin( ) + 40, data.begin( ) + 72 ); - return true; - } - } - - return false; -} - -bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGONPROOF" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Status - - if( ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY Status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - - if( UTIL_ByteArrayToUInt32( Status, false ) == 0 ) - return true; - } - - return false; -} - -BYTEARRAY CBNETProtocol :: RECEIVE_SID_WARDEN( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_WARDEN" ); - // DEBUG_PRINT( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // n bytes -> Data - - if( ValidateLength( data ) && data.size( ) >= 4 ) - return BYTEARRAY( data.begin( ) + 4, data.end( ) ); - - return BYTEARRAY( ); -} - -vector CBNETProtocol :: RECEIVE_SID_FRIENDSLIST( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_FRIENDSLIST" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 1 byte -> Total - // for( 1 .. Total ) - // null term string -> Account - // 1 byte -> Status - // 1 byte -> Area - // 4 bytes -> ??? - // null term string -> Location - - vector Friends; - - if( ValidateLength( data ) && data.size( ) >= 5 ) - { - unsigned int i = 5; - unsigned char Total = data[4]; - - while( Total > 0 ) - { - Total--; - - if( data.size( ) < i + 1 ) - break; - - BYTEARRAY Account = UTIL_ExtractCString( data, i ); - i += Account.size( ) + 1; - - if( data.size( ) < i + 7 ) - break; - - unsigned char Status = data[i]; - unsigned char Area = data[i + 1]; - i += 6; - BYTEARRAY Location = UTIL_ExtractCString( data, i ); - i += Location.size( ) + 1; - Friends.push_back( new CIncomingFriendList( string( Account.begin( ), Account.end( ) ), - Status, - Area, - string( Location.begin( ), Location.end( ) ) ) ); - } - } - - return Friends; -} - -vector CBNETProtocol :: RECEIVE_SID_CLANMEMBERLIST( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_CLANMEMBERLIST" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> ??? - // 1 byte -> Total - // for( 1 .. Total ) - // null term string -> Name - // 1 byte -> Rank - // 1 byte -> Status - // null term string -> Location - - vector ClanList; - - if( ValidateLength( data ) && data.size( ) >= 9 ) - { - unsigned int i = 9; - unsigned char Total = data[8]; - - while( Total > 0 ) - { - Total--; - - if( data.size( ) < i + 1 ) - break; - - BYTEARRAY Name = UTIL_ExtractCString( data, i ); - i += Name.size( ) + 1; - - if( data.size( ) < i + 3 ) - break; - - unsigned char Rank = data[i]; - unsigned char Status = data[i + 1]; - i += 2; - - // in the original VB source the location string is read but discarded, so that's what I do here - - BYTEARRAY Location = UTIL_ExtractCString( data, i ); - i += Location.size( ) + 1; - ClanList.push_back( new CIncomingClanList( string( Name.begin( ), Name.end( ) ), - Rank, - Status ) ); - } - } - - return ClanList; -} - -CIncomingClanList *CBNETProtocol :: RECEIVE_SID_CLANMEMBERSTATUSCHANGE( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED SID_CLANMEMBERSTATUSCHANGE" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // null terminated string -> Name - // 1 byte -> Rank - // 1 byte -> Status - // null terminated string -> Location - - if( ValidateLength( data ) && data.size( ) >= 5 ) - { - BYTEARRAY Name = UTIL_ExtractCString( data, 4 ); - - if( data.size( ) >= Name.size( ) + 7 ) - { - unsigned char Rank = data[Name.size( ) + 5]; - unsigned char Status = data[Name.size( ) + 6]; - - // in the original VB source the location string is read but discarded, so that's what I do here - - BYTEARRAY Location = UTIL_ExtractCString( data, Name.size( ) + 7 ); - return new CIncomingClanList( string( Name.begin( ), Name.end( ) ), - Rank, - Status ); - } - } - - return NULL; -} - -//////////////////// -// SEND FUNCTIONS // -//////////////////// - -BYTEARRAY CBNETProtocol :: SEND_PROTOCOL_INITIALIZE_SELECTOR( ) -{ - BYTEARRAY packet; - packet.push_back( 1 ); - // DEBUG_Print( "SENT PROTOCOL_INITIALIZE_SELECTOR" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_NULL( ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_NULL ); // SID_NULL - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - AssignLength( packet ); - // DEBUG_Print( "SENT SID_NULL" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_STOPADV( ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_STOPADV ); // SID_STOPADV - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - AssignLength( packet ); - // DEBUG_Print( "SENT SID_STOPADV" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_GETADVLISTEX( string gameName ) -{ - unsigned char MapFilter1[] = { 255, 3, 0, 0 }; - unsigned char MapFilter2[] = { 255, 3, 0, 0 }; - unsigned char MapFilter3[] = { 0, 0, 0, 0 }; - unsigned char NumGames[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_GETADVLISTEX ); // SID_GETADVLISTEX - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, MapFilter1, 4 ); // Map Filter - UTIL_AppendByteArray( packet, MapFilter2, 4 ); // Map Filter - UTIL_AppendByteArray( packet, MapFilter3, 4 ); // Map Filter - UTIL_AppendByteArray( packet, NumGames, 4 ); // maximum number of games to list - UTIL_AppendByteArrayFast( packet, gameName ); // Game Name - packet.push_back( 0 ); // Game Password is NULL - packet.push_back( 0 ); // Game Stats is NULL - AssignLength( packet ); - // DEBUG_Print( "SENT SID_GETADVLISTEX" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_ENTERCHAT( ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_ENTERCHAT ); // SID_ENTERCHAT - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // Account Name is NULL on Warcraft III/The Frozen Throne - packet.push_back( 0 ); // Stat String is NULL on CDKEY'd products - AssignLength( packet ); - // DEBUG_Print( "SENT SID_ENTERCHAT" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_JOINCHANNEL( string channel ) -{ - unsigned char NoCreateJoin[] = { 2, 0, 0, 0 }; - unsigned char FirstJoin[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_JOINCHANNEL ); // SID_JOINCHANNEL - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - - if( channel.size( ) > 0 ) - UTIL_AppendByteArray( packet, NoCreateJoin, 4 ); // flags for no create join - else - UTIL_AppendByteArray( packet, FirstJoin, 4 ); // flags for first join - - UTIL_AppendByteArrayFast( packet, channel ); - AssignLength( packet ); - // DEBUG_Print( "SENT SID_JOINCHANNEL" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_CHATCOMMAND( string command ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_CHATCOMMAND ); // SID_CHATCOMMAND - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, command ); // Message - AssignLength( packet ); - // DEBUG_Print( "SENT SID_CHATCOMMAND" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_CHECKAD( ) -{ - unsigned char Zeros[] = { 0, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_CHECKAD ); // SID_CHECKAD - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - AssignLength( packet ); - // DEBUG_Print( "SENT SID_CHECKAD" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_STARTADVEX3( unsigned char state, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, BYTEARRAY mapSHA1, uint32_t hostCounter ) -{ - // todotodo: sort out how GameType works, the documentation is horrendous - -/* - -Game type tag: (read W3GS_GAMEINFO for this field) - 0x00000001 - Custom - 0x00000009 - Blizzard/Ladder -Map author: (mask 0x00006000) can be combined -*0x00002000 - Blizzard - 0x00004000 - Custom -Battle type: (mask 0x00018000) cant be combined - 0x00000000 - Battle -*0x00010000 - Scenario -Map size: (mask 0x000E0000) can be combined with 2 nearest values - 0x00020000 - Small - 0x00040000 - Medium -*0x00080000 - Huge -Observers: (mask 0x00700000) cant be combined - 0x00100000 - Allowed observers - 0x00200000 - Observers on defeat -*0x00400000 - No observers -Flags: - 0x00000800 - Private game flag (not used in game list) - -*/ - - unsigned char Unknown[] = { 255, 3, 0, 0 }; - unsigned char CustomGame[] = { 0, 0, 0, 0 }; - - string HostCounterString = UTIL_ToHexString( hostCounter ); - - if( HostCounterString.size( ) < 8 ) - HostCounterString.insert( 0, 8 - HostCounterString.size( ), '0' ); - - HostCounterString = string( HostCounterString.rbegin( ), HostCounterString.rend( ) ); - - BYTEARRAY packet; - - // make the stat string - - BYTEARRAY StatString; - UTIL_AppendByteArrayFast( StatString, mapFlags ); - StatString.push_back( 0 ); - UTIL_AppendByteArrayFast( StatString, mapWidth ); - UTIL_AppendByteArrayFast( StatString, mapHeight ); - UTIL_AppendByteArrayFast( StatString, mapCRC ); - UTIL_AppendByteArrayFast( StatString, mapPath ); - UTIL_AppendByteArrayFast( StatString, hostName ); - StatString.push_back( 0 ); - UTIL_AppendByteArrayFast( StatString, mapSHA1 ); - StatString = UTIL_EncodeStatString( StatString ); - - if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && !gameName.empty( ) && !hostName.empty( ) && !mapPath.empty( ) && mapCRC.size( ) == 4 && mapSHA1.size( ) == 20 && StatString.size( ) < 128 && HostCounterString.size( ) == 8 ) - { - // make the rest of the packet - - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_STARTADVEX3 ); // SID_STARTADVEX3 - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( state ); // State (16 = public, 17 = private, 18 = close) - packet.push_back( 0 ); // State continued... - packet.push_back( 0 ); // State continued... - packet.push_back( 0 ); // State continued... - UTIL_AppendByteArray( packet, upTime, false ); // time since creation - UTIL_AppendByteArrayFast( packet, mapGameType ); // Game Type, Parameter - UTIL_AppendByteArray( packet, Unknown, 4 ); // ??? - UTIL_AppendByteArray( packet, CustomGame, 4 ); // Custom Game - UTIL_AppendByteArrayFast( packet, gameName ); // Game Name - packet.push_back( 0 ); // Game Password is NULL - packet.push_back( 98 ); // Slots Free (ascii 98 = char 'b' = 11 slots free) - note: do not reduce this as this is the # of PID's Warcraft III will allocate - UTIL_AppendByteArrayFast( packet, HostCounterString, false ); // Host Counter - UTIL_AppendByteArrayFast( packet, StatString ); // Stat String - packet.push_back( 0 ); // Stat String null terminator (the stat string is encoded to remove all even numbers i.e. zeros) - AssignLength( packet ); - } - else - CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_STARTADVEX3" ); - - // DEBUG_Print( "SENT SID_STARTADVEX3" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_NOTIFYJOIN( string gameName ) -{ - unsigned char ProductID[] = { 0, 0, 0, 0 }; - unsigned char ProductVersion[] = { 14, 0, 0, 0 }; // Warcraft III is 14 - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_NOTIFYJOIN ); // SID_NOTIFYJOIN - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, ProductID, 4 ); // Product ID - UTIL_AppendByteArray( packet, ProductVersion, 4 ); // Product Version - UTIL_AppendByteArrayFast( packet, gameName ); // Game Name - packet.push_back( 0 ); // Game Password is NULL - AssignLength( packet ); - // DEBUG_Print( "SENT SID_NOTIFYJOIN" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_PING( BYTEARRAY pingValue ) -{ - BYTEARRAY packet; - - if( pingValue.size( ) == 4 ) - { - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_PING ); // SID_PING - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, pingValue ); // Ping Value - AssignLength( packet ); - } - else - CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_PING" ); - - // DEBUG_Print( "SENT SID_PING" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_LOGONRESPONSE( BYTEARRAY clientToken, BYTEARRAY serverToken, BYTEARRAY passwordHash, string accountName ) -{ - // todotodo: check that the passed BYTEARRAY sizes are correct (don't know what they should be right now so I can't do this today) - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_LOGONRESPONSE ); // SID_LOGONRESPONSE - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, clientToken ); // Client Token - UTIL_AppendByteArrayFast( packet, serverToken ); // Server Token - UTIL_AppendByteArrayFast( packet, passwordHash ); // Password Hash - UTIL_AppendByteArrayFast( packet, accountName ); // Account Name - AssignLength( packet ); - // DEBUG_Print( "SENT SID_LOGONRESPONSE" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_NETGAMEPORT( uint16_t serverPort ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_NETGAMEPORT ); // SID_NETGAMEPORT - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, serverPort, false ); // local game server port - AssignLength( packet ); - // DEBUG_Print( "SENT SID_NETGAMEPORT" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_INFO( unsigned char ver, bool TFT, uint32_t localeID, string countryAbbrev, string country ) -{ - unsigned char ProtocolID[] = { 0, 0, 0, 0 }; - unsigned char PlatformID[] = { 54, 56, 88, 73 }; // "IX86" - unsigned char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" - unsigned char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" - unsigned char Version[] = { ver, 0, 0, 0 }; - unsigned char Language[] = { 83, 85, 110, 101 }; // "enUS" - unsigned char LocalIP[] = { 127, 0, 0, 1 }; - unsigned char TimeZoneBias[] = { 44, 1, 0, 0 }; // 300 minutes (GMT -0500) - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_AUTH_INFO ); // SID_AUTH_INFO - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, ProtocolID, 4 ); // Protocol ID - UTIL_AppendByteArray( packet, PlatformID, 4 ); // Platform ID - - if( TFT ) - UTIL_AppendByteArray( packet, ProductID_TFT, 4 ); // Product ID (TFT) - else - UTIL_AppendByteArray( packet, ProductID_ROC, 4 ); // Product ID (ROC) - - UTIL_AppendByteArray( packet, Version, 4 ); // Version - UTIL_AppendByteArray( packet, Language, 4 ); // Language (hardcoded as enUS to ensure battle.net sends the bot messages in English) - UTIL_AppendByteArray( packet, LocalIP, 4 ); // Local IP for NAT compatibility - UTIL_AppendByteArray( packet, TimeZoneBias, 4 ); // Time Zone Bias - UTIL_AppendByteArray( packet, localeID, false ); // Locale ID - UTIL_AppendByteArray( packet, localeID, false ); // Language ID (copying the locale ID should be sufficient since we don't care about sublanguages) - UTIL_AppendByteArrayFast( packet, countryAbbrev ); // Country Abbreviation - UTIL_AppendByteArrayFast( packet, country ); // Country - AssignLength( packet ); - // DEBUG_Print( "SENT SID_AUTH_INFO" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_CHECK( bool TFT, BYTEARRAY clientToken, BYTEARRAY exeVersion, BYTEARRAY exeVersionHash, BYTEARRAY keyInfoROC, BYTEARRAY keyInfoTFT, string exeInfo, string keyOwnerName ) -{ - uint32_t NumKeys = 0; - - if( TFT ) - NumKeys = 2; - else - NumKeys = 1; - - BYTEARRAY packet; - - if( clientToken.size( ) == 4 && exeVersion.size( ) == 4 && exeVersionHash.size( ) == 4 && keyInfoROC.size( ) == 36 && ( !TFT || keyInfoTFT.size( ) == 36 ) ) - { - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_AUTH_CHECK ); // SID_AUTH_CHECK - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, clientToken ); // Client Token - UTIL_AppendByteArrayFast( packet, exeVersion ); // EXE Version - UTIL_AppendByteArrayFast( packet, exeVersionHash ); // EXE Version Hash - UTIL_AppendByteArray( packet, NumKeys, false ); // number of keys in this packet - UTIL_AppendByteArray( packet, (uint32_t)0, false ); // boolean Using Spawn (32 bit) - UTIL_AppendByteArrayFast( packet, keyInfoROC ); // ROC Key Info - - if( TFT ) - UTIL_AppendByteArrayFast( packet, keyInfoTFT ); // TFT Key Info - - UTIL_AppendByteArrayFast( packet, exeInfo ); // EXE Info - UTIL_AppendByteArrayFast( packet, keyOwnerName ); // CD Key Owner Name - AssignLength( packet ); - } - else - CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_CHECK" ); - - // DEBUG_Print( "SENT SID_AUTH_CHECK" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGON( BYTEARRAY clientPublicKey, string accountName ) -{ - BYTEARRAY packet; - - if( clientPublicKey.size( ) == 32 ) - { - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_AUTH_ACCOUNTLOGON ); // SID_AUTH_ACCOUNTLOGON - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, clientPublicKey ); // Client Key - UTIL_AppendByteArrayFast( packet, accountName ); // Account Name - AssignLength( packet ); - } - else - CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" ); - - // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGON" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY clientPasswordProof ) -{ - BYTEARRAY packet; - - if( clientPasswordProof.size( ) == 20 ) - { - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_AUTH_ACCOUNTLOGONPROOF ); // SID_AUTH_ACCOUNTLOGONPROOF - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, clientPasswordProof ); // Client Password Proof - AssignLength( packet ); - } - else - CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" ); - - // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGONPROOF" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_WARDEN( BYTEARRAY wardenResponse ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_WARDEN ); // SID_WARDEN - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArrayFast( packet, wardenResponse ); // warden response - AssignLength( packet ); - // DEBUG_Print( "SENT SID_WARDEN" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_FRIENDSLIST( ) -{ - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_FRIENDSLIST ); // SID_FRIENDSLIST - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - AssignLength( packet ); - // DEBUG_Print( "SENT SID_FRIENDSLIST" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CBNETProtocol :: SEND_SID_CLANMEMBERLIST( ) -{ - unsigned char Cookie[] = { 0, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant - packet.push_back( SID_CLANMEMBERLIST ); // SID_CLANMEMBERLIST - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, Cookie, 4 ); // cookie - AssignLength( packet ); - // DEBUG_Print( "SENT SID_CLANMEMBERLIST" ); - // DEBUG_Print( packet ); - return packet; -} - -///////////////////// -// OTHER FUNCTIONS // -///////////////////// - -bool CBNETProtocol :: AssignLength( BYTEARRAY &content ) -{ - // insert the actual length of the content array into bytes 3 and 4 (indices 2 and 3) - - BYTEARRAY LengthBytes; - - if( content.size( ) >= 4 && content.size( ) <= 65535 ) - { - LengthBytes = UTIL_CreateByteArray( (uint16_t)content.size( ), false ); - content[2] = LengthBytes[0]; - content[3] = LengthBytes[1]; - return true; - } - - return false; -} - -bool CBNETProtocol :: ValidateLength( BYTEARRAY &content ) -{ - // verify that bytes 3 and 4 (indices 2 and 3) of the content array describe the length - - uint16_t Length; - BYTEARRAY LengthBytes; - - if( content.size( ) >= 4 && content.size( ) <= 65535 ) - { - LengthBytes.push_back( content[2] ); - LengthBytes.push_back( content[3] ); - Length = UTIL_ByteArrayToUInt16( LengthBytes, false ); - - if( Length == content.size( ) ) - return true; - } - - return false; -} - -// -// CIncomingGameHost -// - -CIncomingGameHost :: CIncomingGameHost( BYTEARRAY &nIP, uint16_t nPort, string nGameName, BYTEARRAY &nHostCounter ) -{ - m_IP = nIP; - m_Port = nPort; - m_GameName = nGameName; - m_HostCounter = nHostCounter; -} - -CIncomingGameHost :: ~CIncomingGameHost( ) -{ - -} - -string CIncomingGameHost :: GetIPString( ) -{ - string Result; - - if( m_IP.size( ) >= 4 ) - { - for( unsigned int i = 0; i < 4; i++ ) - { - Result += UTIL_ToString( (unsigned int)m_IP[i] ); - - if( i < 3 ) - Result += "."; - } - } - - return Result; -} - -// -// CIncomingChatEvent -// - -CIncomingChatEvent :: CIncomingChatEvent( CBNETProtocol :: IncomingChatEvent nChatEvent, uint32_t nPing, string nUser, string nMessage ) -{ - m_ChatEvent = nChatEvent; - m_Ping = nPing; - m_User = nUser; - m_Message = nMessage; -} - -CIncomingChatEvent :: ~CIncomingChatEvent( ) -{ - -} - -// -// CIncomingFriendList -// - -CIncomingFriendList :: CIncomingFriendList( string nAccount, unsigned char nStatus, unsigned char nArea, string nLocation ) -{ - m_Account = nAccount; - m_Status = nStatus; - m_Area = nArea; - m_Location = nLocation; -} - -CIncomingFriendList :: ~CIncomingFriendList( ) -{ - -} - -string CIncomingFriendList :: GetDescription( ) -{ - string Description; - Description += GetAccount( ) + "\n"; - Description += ExtractStatus( GetStatus( ) ) + "\n"; - Description += ExtractArea( GetArea( ) ) + "\n"; - Description += ExtractLocation( GetLocation( ) ) + "\n\n"; - return Description; -} - -string CIncomingFriendList :: ExtractStatus( unsigned char status ) -{ - string Result; - - if( status & 1 ) - Result += ""; - - if( status & 2 ) - Result += ""; - - if( status & 4 ) - Result += ""; - - if( Result.empty( ) ) - Result = ""; - - return Result; -} - -string CIncomingFriendList :: ExtractArea( unsigned char area ) -{ - switch( area ) - { - case 0: return ""; - case 1: return ""; - case 2: return ""; - case 3: return ""; - case 4: return ""; - case 5: return ""; - } - - return ""; -} - -string CIncomingFriendList :: ExtractLocation( string location ) -{ - string Result; - - if( location.substr( 0, 4 ) == "PX3W" ) - Result = location.substr( 4 ); - - if( Result.empty( ) ) - Result = "."; - - return Result; -} - -// -// CIncomingClanList -// - -CIncomingClanList :: CIncomingClanList( string nName, unsigned char nRank, unsigned char nStatus ) -{ - m_Name = nName; - m_Rank = nRank; - m_Status = nStatus; -} - -CIncomingClanList :: ~CIncomingClanList( ) -{ - -} - -string CIncomingClanList :: GetRank( ) -{ - switch( m_Rank ) - { - case 0: return "Recruit"; - case 1: return "Peon"; - case 2: return "Grunt"; - case 3: return "Shaman"; - case 4: return "Chieftain"; - } - - return "Rank Unknown"; -} - -string CIncomingClanList :: GetStatus( ) -{ - if( m_Status == 0 ) - return "Offline"; - else - return "Online"; -} - -string CIncomingClanList :: GetDescription( ) -{ - string Description; - Description += GetName( ) + "\n"; - Description += GetStatus( ) + "\n"; - Description += GetRank( ) + "\n\n"; - return Description; -} diff --git a/ghost/bnetprotocol.h b/ghost/bnetprotocol.h deleted file mode 100644 index 4d7cfb9..0000000 --- a/ghost/bnetprotocol.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef BNETPROTOCOL_H -#define BNETPROTOCOL_H - -// -// CBNETProtocol -// - -#define BNET_HEADER_CONSTANT 255 - -class CIncomingGameHost; -class CIncomingChatEvent; -class CIncomingFriendList; -class CIncomingClanList; - -class CBNETProtocol -{ -public: - enum Protocol { - SID_NULL = 0, // 0x0 - SID_STOPADV = 2, // 0x2 - SID_GETADVLISTEX = 9, // 0x9 - SID_ENTERCHAT = 10, // 0xA - SID_JOINCHANNEL = 12, // 0xC - SID_CHATCOMMAND = 14, // 0xE - SID_CHATEVENT = 15, // 0xF - SID_CHECKAD = 21, // 0x15 - SID_STARTADVEX3 = 28, // 0x1C - SID_DISPLAYAD = 33, // 0x21 - SID_NOTIFYJOIN = 34, // 0x22 - SID_PING = 37, // 0x25 - SID_LOGONRESPONSE = 41, // 0x29 - SID_NETGAMEPORT = 69, // 0x45 - SID_AUTH_INFO = 80, // 0x50 - SID_AUTH_CHECK = 81, // 0x51 - SID_AUTH_ACCOUNTLOGON = 83, // 0x53 - SID_AUTH_ACCOUNTLOGONPROOF = 84, // 0x54 - SID_WARDEN = 94, // 0x5E - SID_FRIENDSLIST = 101, // 0x65 - SID_FRIENDSUPDATE = 102, // 0x66 - SID_CLANMEMBERLIST = 125, // 0x7D - SID_CLANMEMBERSTATUSCHANGE = 127 // 0x7F - }; - - enum KeyResult { - KR_GOOD = 0, - KR_OLD_GAME_VERSION = 256, - KR_INVALID_VERSION = 257, - KR_ROC_KEY_IN_USE = 513, - KR_TFT_KEY_IN_USE = 529 - }; - - enum IncomingChatEvent { - EID_SHOWUSER = 1, // received when you join a channel (includes users in the channel and their information) - EID_JOIN = 2, // received when someone joins the channel you're currently in - EID_LEAVE = 3, // received when someone leaves the channel you're currently in - EID_WHISPER = 4, // received a whisper message - EID_TALK = 5, // received when someone talks in the channel you're currently in - EID_BROADCAST = 6, // server broadcast - EID_CHANNEL = 7, // received when you join a channel (includes the channel's name, flags) - EID_USERFLAGS = 9, // user flags updates - EID_WHISPERSENT = 10, // sent a whisper message - EID_CHANNELFULL = 13, // channel is full - EID_CHANNELDOESNOTEXIST = 14, // channel does not exist - EID_CHANNELRESTRICTED = 15, // channel is restricted - EID_INFO = 18, // broadcast/information message - EID_ERROR = 19, // error message - EID_EMOTE = 23 // emote - }; - -private: - BYTEARRAY m_ClientToken; // set in constructor - BYTEARRAY m_LogonType; // set in RECEIVE_SID_AUTH_INFO - BYTEARRAY m_ServerToken; // set in RECEIVE_SID_AUTH_INFO - BYTEARRAY m_MPQFileTime; // set in RECEIVE_SID_AUTH_INFO - BYTEARRAY m_IX86VerFileName; // set in RECEIVE_SID_AUTH_INFO - BYTEARRAY m_ValueStringFormula; // set in RECEIVE_SID_AUTH_INFO - BYTEARRAY m_KeyState; // set in RECEIVE_SID_AUTH_CHECK - BYTEARRAY m_KeyStateDescription; // set in RECEIVE_SID_AUTH_CHECK - BYTEARRAY m_Salt; // set in RECEIVE_SID_AUTH_ACCOUNTLOGON - BYTEARRAY m_ServerPublicKey; // set in RECEIVE_SID_AUTH_ACCOUNTLOGON - BYTEARRAY m_UniqueName; // set in RECEIVE_SID_ENTERCHAT - -public: - CBNETProtocol( ); - ~CBNETProtocol( ); - - BYTEARRAY GetClientToken( ) { return m_ClientToken; } - BYTEARRAY GetLogonType( ) { return m_LogonType; } - BYTEARRAY GetServerToken( ) { return m_ServerToken; } - BYTEARRAY GetMPQFileTime( ) { return m_MPQFileTime; } - BYTEARRAY GetIX86VerFileName( ) { return m_IX86VerFileName; } - string GetIX86VerFileNameString( ) { return string( m_IX86VerFileName.begin( ), m_IX86VerFileName.end( ) ); } - BYTEARRAY GetValueStringFormula( ) { return m_ValueStringFormula; } - string GetValueStringFormulaString( ) { return string( m_ValueStringFormula.begin( ), m_ValueStringFormula.end( ) ); } - BYTEARRAY GetKeyState( ) { return m_KeyState; } - string GetKeyStateDescription( ) { return string( m_KeyStateDescription.begin( ), m_KeyStateDescription.end( ) ); } - BYTEARRAY GetSalt( ) { return m_Salt; } - BYTEARRAY GetServerPublicKey( ) { return m_ServerPublicKey; } - BYTEARRAY GetUniqueName( ) { return m_UniqueName; } - - // receive functions - - bool RECEIVE_SID_NULL( BYTEARRAY data ); - CIncomingGameHost *RECEIVE_SID_GETADVLISTEX( BYTEARRAY data ); - bool RECEIVE_SID_ENTERCHAT( BYTEARRAY data ); - CIncomingChatEvent *RECEIVE_SID_CHATEVENT( BYTEARRAY data ); - bool RECEIVE_SID_CHECKAD( BYTEARRAY data ); - bool RECEIVE_SID_STARTADVEX3( BYTEARRAY data ); - BYTEARRAY RECEIVE_SID_PING( BYTEARRAY data ); - bool RECEIVE_SID_LOGONRESPONSE( BYTEARRAY data ); - bool RECEIVE_SID_AUTH_INFO( BYTEARRAY data ); - bool RECEIVE_SID_AUTH_CHECK( BYTEARRAY data ); - bool RECEIVE_SID_AUTH_ACCOUNTLOGON( BYTEARRAY data ); - bool RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY data ); - BYTEARRAY RECEIVE_SID_WARDEN( BYTEARRAY data ); - vector RECEIVE_SID_FRIENDSLIST( BYTEARRAY data ); - vector RECEIVE_SID_CLANMEMBERLIST( BYTEARRAY data ); - CIncomingClanList *RECEIVE_SID_CLANMEMBERSTATUSCHANGE( BYTEARRAY data ); - - // send functions - - BYTEARRAY SEND_PROTOCOL_INITIALIZE_SELECTOR( ); - BYTEARRAY SEND_SID_NULL( ); - BYTEARRAY SEND_SID_STOPADV( ); - BYTEARRAY SEND_SID_GETADVLISTEX( string gameName ); - BYTEARRAY SEND_SID_ENTERCHAT( ); - BYTEARRAY SEND_SID_JOINCHANNEL( string channel ); - BYTEARRAY SEND_SID_CHATCOMMAND( string command ); - BYTEARRAY SEND_SID_CHECKAD( ); - BYTEARRAY SEND_SID_STARTADVEX3( unsigned char state, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, BYTEARRAY mapSHA1, uint32_t hostCounter ); - BYTEARRAY SEND_SID_NOTIFYJOIN( string gameName ); - BYTEARRAY SEND_SID_PING( BYTEARRAY pingValue ); - BYTEARRAY SEND_SID_LOGONRESPONSE( BYTEARRAY clientToken, BYTEARRAY serverToken, BYTEARRAY passwordHash, string accountName ); - BYTEARRAY SEND_SID_NETGAMEPORT( uint16_t serverPort ); - BYTEARRAY SEND_SID_AUTH_INFO( unsigned char ver, bool TFT, uint32_t localeID, string countryAbbrev, string country ); - BYTEARRAY SEND_SID_AUTH_CHECK( bool TFT, BYTEARRAY clientToken, BYTEARRAY exeVersion, BYTEARRAY exeVersionHash, BYTEARRAY keyInfoROC, BYTEARRAY keyInfoTFT, string exeInfo, string keyOwnerName ); - BYTEARRAY SEND_SID_AUTH_ACCOUNTLOGON( BYTEARRAY clientPublicKey, string accountName ); - BYTEARRAY SEND_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY clientPasswordProof ); - BYTEARRAY SEND_SID_WARDEN( BYTEARRAY wardenResponse ); - BYTEARRAY SEND_SID_FRIENDSLIST( ); - BYTEARRAY SEND_SID_CLANMEMBERLIST( ); - - // other functions - -private: - bool AssignLength( BYTEARRAY &content ); - bool ValidateLength( BYTEARRAY &content ); -}; - -// -// CIncomingGameHost -// - -class CIncomingGameHost -{ -private: - BYTEARRAY m_IP; - uint16_t m_Port; - string m_GameName; - BYTEARRAY m_HostCounter; - -public: - CIncomingGameHost( BYTEARRAY &nIP, uint16_t nPort, string nGameName, BYTEARRAY &nHostCounter ); - ~CIncomingGameHost( ); - - BYTEARRAY GetIP( ) { return m_IP; } - string GetIPString( ); - uint16_t GetPort( ) { return m_Port; } - string GetGameName( ) { return m_GameName; } - BYTEARRAY GetHostCounter( ) { return m_HostCounter; } -}; - -// -// CIncomingChatEvent -// - -class CIncomingChatEvent -{ -private: - CBNETProtocol :: IncomingChatEvent m_ChatEvent; - uint32_t m_Ping; - string m_User; - string m_Message; - -public: - CIncomingChatEvent( CBNETProtocol :: IncomingChatEvent nChatEvent, uint32_t nPing, string nUser, string nMessage ); - ~CIncomingChatEvent( ); - - CBNETProtocol :: IncomingChatEvent GetChatEvent( ) { return m_ChatEvent; } - uint32_t GetPing( ) { return m_Ping; } - string GetUser( ) { return m_User; } - string GetMessage( ) { return m_Message; } -}; - -// -// CIncomingFriendList -// - -class CIncomingFriendList -{ -private: - string m_Account; - unsigned char m_Status; - unsigned char m_Area; - string m_Location; - -public: - CIncomingFriendList( string nAccount, unsigned char nStatus, unsigned char nArea, string nLocation ); - ~CIncomingFriendList( ); - - string GetAccount( ) { return m_Account; } - unsigned char GetStatus( ) { return m_Status; } - unsigned char GetArea( ) { return m_Area; } - string GetLocation( ) { return m_Location; } - string GetDescription( ); - -private: - string ExtractStatus( unsigned char status ); - string ExtractArea( unsigned char area ); - string ExtractLocation( string location ); -}; - -// -// CIncomingClanList -// - -class CIncomingClanList -{ -private: - string m_Name; - unsigned char m_Rank; - unsigned char m_Status; - -public: - CIncomingClanList( string nName, unsigned char nRank, unsigned char nStatus ); - ~CIncomingClanList( ); - - string GetName( ) { return m_Name; } - string GetRank( ); - string GetStatus( ); - string GetDescription( ); -}; - -#endif diff --git a/ghost/bnlsclient.cpp b/ghost/bnlsclient.cpp deleted file mode 100644 index bce9bee..0000000 --- a/ghost/bnlsclient.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "socket.h" -#include "commandpacket.h" -#include "bnlsprotocol.h" -#include "bnlsclient.h" - -// -// CBNLSClient -// - -CBNLSClient :: CBNLSClient( string nServer, uint16_t nPort, uint32_t nWardenCookie ) -{ - m_Socket = new CTCPClient( ); - m_Protocol = new CBNLSProtocol( ); - m_WasConnected = false; - m_Server = nServer; - m_Port = nPort; - m_LastNullTime = 0; - m_WardenCookie = nWardenCookie; - m_TotalWardenIn = 0; - m_TotalWardenOut = 0; -} - -CBNLSClient :: ~CBNLSClient( ) -{ - delete m_Socket; - delete m_Protocol; - - while( !m_Packets.empty( ) ) - { - delete m_Packets.front( ); - m_Packets.pop( ); - } -} - -BYTEARRAY CBNLSClient :: GetWardenResponse( ) -{ - BYTEARRAY WardenResponse; - - if( !m_WardenResponses.empty( ) ) - { - WardenResponse = m_WardenResponses.front( ); - m_WardenResponses.pop( ); - m_TotalWardenOut++; - } - - return WardenResponse; -} - -unsigned int CBNLSClient :: SetFD( void *fd, void *send_fd, int *nfds ) -{ - if( !m_Socket->HasError( ) && m_Socket->GetConnected( ) ) - { - m_Socket->SetFD( (fd_set *)fd, (fd_set *)send_fd, nfds ); - return 1; - } - - return 0; -} - -bool CBNLSClient :: Update( void *fd, void *send_fd ) -{ - if( m_Socket->HasError( ) ) - { - CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] disconnected from BNLS server due to socket error" ); - return true; - } - - if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && m_WasConnected ) - { - CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] disconnected from BNLS server" ); - return true; - } - - if( m_Socket->GetConnected( ) ) - { - m_Socket->DoRecv( (fd_set *)fd ); - ExtractPackets( ); - ProcessPackets( ); - - if( GetTime( ) - m_LastNullTime >= 50 ) - { - m_Socket->PutBytes( m_Protocol->SEND_BNLS_NULL( ) ); - m_LastNullTime = GetTime( ); - } - - while( !m_OutPackets.empty( ) ) - { - m_Socket->PutBytes( m_OutPackets.front( ) ); - m_OutPackets.pop( ); - } - - m_Socket->DoSend( (fd_set *)send_fd ); - return false; - } - - if( m_Socket->GetConnecting( ) && m_Socket->CheckConnect( ) ) - { - CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] connected" ); - m_WasConnected = true; - m_LastNullTime = GetTime( ); - return false; - } - - if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && !m_WasConnected ) - { - CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] connecting to server [" + m_Server + "] on port " + UTIL_ToString( m_Port ) ); - m_Socket->Connect( string( ), m_Server, m_Port ); - return false; - } - - return false; -} - -void CBNLSClient :: ExtractPackets( ) -{ - string *RecvBuffer = m_Socket->GetBytes( ); - BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); - - while( Bytes.size( ) >= 3 ) - { - uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false ); - - if( Length >= 3 ) - { - if( Bytes.size( ) >= Length ) - { - m_Packets.push( new CCommandPacket( 0, Bytes[2], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); - *RecvBuffer = RecvBuffer->substr( Length ); - Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); - } - else - return; - } - else - { - CONSOLE_Print( "[BNLSC: " + m_Server + ":" + UTIL_ToString( m_Port ) + ":C" + UTIL_ToString( m_WardenCookie ) + "] error - received invalid packet from BNLS server (bad length), disconnecting" ); - m_Socket->Disconnect( ); - return; - } - } -} - -void CBNLSClient :: ProcessPackets( ) -{ - while( !m_Packets.empty( ) ) - { - CCommandPacket *Packet = m_Packets.front( ); - m_Packets.pop( ); - - if( Packet->GetID( ) == CBNLSProtocol :: BNLS_WARDEN ) - { - BYTEARRAY WardenResponse = m_Protocol->RECEIVE_BNLS_WARDEN( Packet->GetData( ) ); - - if( !WardenResponse.empty( ) ) - m_WardenResponses.push( WardenResponse ); - } - - delete Packet; - } -} - -void CBNLSClient :: QueueWardenSeed( uint32_t seed ) -{ - m_OutPackets.push( m_Protocol->SEND_BNLS_WARDEN_SEED( m_WardenCookie, seed ) ); -} - -void CBNLSClient :: QueueWardenRaw( BYTEARRAY wardenRaw ) -{ - m_OutPackets.push( m_Protocol->SEND_BNLS_WARDEN_RAW( m_WardenCookie, wardenRaw ) ); - m_TotalWardenIn++; -} diff --git a/ghost/bnlsclient.h b/ghost/bnlsclient.h deleted file mode 100644 index 0562c37..0000000 --- a/ghost/bnlsclient.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef BNLSCLIENT_H -#define BNLSCLIENT_H - -// -// CBNLSClient -// - -class CTCPClient; -class CBNLSProtocol; -class CCommandPacket; - -class CBNLSClient -{ -private: - CTCPClient *m_Socket; // the connection to the BNLS server - CBNLSProtocol *m_Protocol; // battle.net protocol - queue m_Packets; // queue of incoming packets - bool m_WasConnected; - string m_Server; - uint16_t m_Port; - uint32_t m_LastNullTime; - uint32_t m_WardenCookie; // the warden cookie - queue m_OutPackets; // queue of outgoing packets to be sent - queue m_WardenResponses; // the warden responses to be sent to battle.net - uint32_t m_TotalWardenIn; - uint32_t m_TotalWardenOut; - -public: - CBNLSClient( string nServer, uint16_t nPort, uint32_t nWardenCookie ); - ~CBNLSClient( ); - - BYTEARRAY GetWardenResponse( ); - uint32_t GetTotalWardenIn( ) { return m_TotalWardenIn; } - uint32_t GetTotalWardenOut( ) { return m_TotalWardenOut; } - - // processing functions - - unsigned int SetFD( void *fd, void *send_fd, int *nfds ); - bool Update( void *fd, void *send_fd ); - void ExtractPackets( ); - void ProcessPackets( ); - - // other functions - - void QueueWardenSeed( uint32_t seed ); - void QueueWardenRaw( BYTEARRAY wardenRaw ); -}; - -#endif diff --git a/ghost/bnlsprotocol.cpp b/ghost/bnlsprotocol.cpp deleted file mode 100644 index 8929ef9..0000000 --- a/ghost/bnlsprotocol.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "bnlsprotocol.h" - -CBNLSProtocol :: CBNLSProtocol( ) -{ - -} - -CBNLSProtocol :: ~CBNLSProtocol( ) -{ - -} - -/////////////////////// -// RECEIVE FUNCTIONS // -/////////////////////// - -BYTEARRAY CBNLSProtocol :: RECEIVE_BNLS_WARDEN( BYTEARRAY data ) -{ - // 2 bytes -> Length - // 1 byte -> ID - // (BYTE) -> Usage - // (DWORD) -> Cookie - // (BYTE) -> Result - // (WORD) -> Length of data - // (VOID) -> Data - - if( ValidateLength( data ) && data.size( ) >= 11 ) - { - unsigned char Usage = data[3]; - uint32_t Cookie = UTIL_ByteArrayToUInt32( data, false, 4 ); - unsigned char Result = data[8]; - uint16_t Length = UTIL_ByteArrayToUInt16( data, false, 10 ); - - if( Result == 0x00 ) - return BYTEARRAY( data.begin( ) + 11, data.end( ) ); - else - CONSOLE_Print( "[BNLSPROTO] received error code " + UTIL_ToString( data[8] ) ); - } - - return BYTEARRAY( ); -} - -//////////////////// -// SEND FUNCTIONS // -//////////////////// - -BYTEARRAY CBNLSProtocol :: SEND_BNLS_NULL( ) -{ - BYTEARRAY packet; - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( BNLS_NULL ); // BNLS_NULL - AssignLength( packet ); - return packet; -} - -BYTEARRAY CBNLSProtocol :: SEND_BNLS_WARDEN_SEED( uint32_t cookie, uint32_t seed ) -{ - unsigned char Client[] = { 80, 88, 51, 87 }; // "W3XP" - - BYTEARRAY packet; - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( BNLS_WARDEN ); // BNLS_WARDEN - packet.push_back( 0 ); // BNLS_WARDEN_SEED - UTIL_AppendByteArray( packet, cookie, false ); // cookie - UTIL_AppendByteArray( packet, Client, 4 ); // Client - UTIL_AppendByteArray( packet, (uint16_t)4, false ); // length of seed - UTIL_AppendByteArray( packet, seed, false ); // seed - packet.push_back( 0 ); // username is blank - UTIL_AppendByteArray( packet, (uint16_t)0, false ); // password length - // password - AssignLength( packet ); - return packet; -} - -BYTEARRAY CBNLSProtocol :: SEND_BNLS_WARDEN_RAW( uint32_t cookie, BYTEARRAY raw ) -{ - BYTEARRAY packet; - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( BNLS_WARDEN ); // BNLS_WARDEN - packet.push_back( 1 ); // BNLS_WARDEN_RAW - UTIL_AppendByteArray( packet, cookie, false ); // cookie - UTIL_AppendByteArray( packet, (uint16_t)raw.size( ), false ); // raw length - UTIL_AppendByteArray( packet, raw ); // raw - AssignLength( packet ); - return packet; -} - -BYTEARRAY CBNLSProtocol :: SEND_BNLS_WARDEN_RUNMODULE( uint32_t cookie ) -{ - return BYTEARRAY( ); -} - -///////////////////// -// OTHER FUNCTIONS // -///////////////////// - -bool CBNLSProtocol :: AssignLength( BYTEARRAY &content ) -{ - // insert the actual length of the content array into bytes 1 and 2 (indices 0 and 1) - - BYTEARRAY LengthBytes; - - if( content.size( ) >= 2 && content.size( ) <= 65535 ) - { - LengthBytes = UTIL_CreateByteArray( (uint16_t)content.size( ), false ); - content[0] = LengthBytes[0]; - content[1] = LengthBytes[1]; - return true; - } - - return false; -} - -bool CBNLSProtocol :: ValidateLength( BYTEARRAY &content ) -{ - // verify that bytes 1 and 2 (indices 0 and 1) of the content array describe the length - - uint16_t Length; - BYTEARRAY LengthBytes; - - if( content.size( ) >= 2 && content.size( ) <= 65535 ) - { - LengthBytes.push_back( content[0] ); - LengthBytes.push_back( content[1] ); - Length = UTIL_ByteArrayToUInt16( LengthBytes, false ); - - if( Length == content.size( ) ) - return true; - } - - return false; -} diff --git a/ghost/config.cpp b/ghost/config.cpp deleted file mode 100644 index 2a1276c..0000000 --- a/ghost/config.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "config.h" - -#include - -// -// CConfig -// - -CConfig :: CConfig( ) -{ - -} - -CConfig :: ~CConfig( ) -{ - -} - -void CConfig :: Read( string file ) -{ - ifstream in; - in.open( file.c_str( ) ); - - if( in.fail( ) ) - CONSOLE_Print( "[CONFIG] warning - unable to read file [" + file + "]" ); - else - { - CONSOLE_Print( "[CONFIG] loading file [" + file + "]" ); - string Line; - - while( !in.eof( ) ) - { - getline( in, Line ); - - // ignore blank lines and comments - - if( Line.empty( ) || Line[0] == '#' ) - continue; - - // remove newlines and partial newlines to help fix issues with Windows formatted config files on Linux systems - - Line.erase( remove( Line.begin( ), Line.end( ), '\r' ), Line.end( ) ); - Line.erase( remove( Line.begin( ), Line.end( ), '\n' ), Line.end( ) ); - - string :: size_type Split = Line.find( "=" ); - - if( Split == string :: npos ) - continue; - - string :: size_type KeyStart = Line.find_first_not_of( " " ); - string :: size_type KeyEnd = Line.find( " ", KeyStart ); - string :: size_type ValueStart = Line.find_first_not_of( " ", Split + 1 ); - string :: size_type ValueEnd = Line.size( ); - - if( ValueStart != string :: npos ) - m_CFG[Line.substr( KeyStart, KeyEnd - KeyStart )] = Line.substr( ValueStart, ValueEnd - ValueStart ); - } - - in.close( ); - } -} - -bool CConfig :: Exists( string key ) -{ - return m_CFG.find( key ) != m_CFG.end( ); -} - -int CConfig :: GetInt( string key, int x ) -{ - if( m_CFG.find( key ) == m_CFG.end( ) ) - return x; - else - return atoi( m_CFG[key].c_str( ) ); -} - -string CConfig :: GetString( string key, string x ) -{ - if( m_CFG.find( key ) == m_CFG.end( ) ) - return x; - else - return m_CFG[key]; -} - -void CConfig :: Set( string key, string x ) -{ - m_CFG[key] = x; -} diff --git a/ghost/crc32.h b/ghost/crc32.h deleted file mode 100644 index 00f63ae..0000000 --- a/ghost/crc32.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CRC32_H -#define CRC32_H - -#define CRC32_POLYNOMIAL 0x04c11db7 - -class CCRC32 -{ -public: - void Initialize( ); - uint32_t FullCRC( unsigned char *sData, uint32_t ulLength ); - void PartialCRC( uint32_t *ulInCRC, unsigned char *sData, uint32_t ulLength ); - -private: - uint32_t Reflect( uint32_t ulReflect, char cChar ); - uint32_t ulTable[256]; -}; - -#endif diff --git a/ghost/game.h b/ghost/game.h deleted file mode 100644 index a3b0904..0000000 --- a/ghost/game.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GAME_H -#define GAME_H - -// -// CGame -// - -class CDBBan; -class CDBGame; -class CDBGamePlayer; -class CStats; -class CCallableBanCheck; -class CCallableBanAdd; -class CCallableGameAdd; -class CCallableGamePlayerSummaryCheck; -class CCallableDotAPlayerSummaryCheck; - -typedef pair PairedBanCheck; -typedef pair PairedBanAdd; -typedef pair PairedGPSCheck; -typedef pair PairedDPSCheck; - -class CGame : public CBaseGame -{ -protected: - CDBBan *m_DBBanLast; // last ban for the !banlast command - this is a pointer to one of the items in m_DBBans - vector m_DBBans; // vector of potential ban data for the database (see the Update function for more info, it's not as straightforward as you might think) - CDBGame *m_DBGame; // potential game data for the database - vector m_DBGamePlayers; // vector of potential gameplayer data for the database - CStats *m_Stats; // class to keep track of game stats such as kills/deaths/assists in dota - CCallableGameAdd *m_CallableGameAdd; // threaded database game addition in progress - vector m_PairedBanChecks; // vector of paired threaded database ban checks in progress - vector m_PairedBanAdds; // vector of paired threaded database ban adds in progress - vector m_PairedGPSChecks; // vector of paired threaded database game player summary checks in progress - vector m_PairedDPSChecks; // vector of paired threaded database DotA player summary checks in progress - -public: - CGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nOwnerName, string nCreatorName, string nCreatorServer ); - virtual ~CGame( ); - - virtual bool Update( void *fd, void *send_fd ); - virtual void EventPlayerDeleted( CGamePlayer *player ); - virtual void EventPlayerAction( CGamePlayer *player, CIncomingAction *action ); - virtual bool EventPlayerBotCommand( CGamePlayer *player, string command, string payload ); - virtual void EventGameStarted( ); - virtual bool IsGameDataSaved( ); - virtual void SaveGameData( ); -}; - -#endif diff --git a/ghost/game_admin.cpp b/ghost/game_admin.cpp deleted file mode 100644 index 547711e..0000000 --- a/ghost/game_admin.cpp +++ /dev/null @@ -1,1305 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "config.h" -#include "language.h" -#include "socket.h" -#include "ghostdb.h" -#include "bnet.h" -#include "map.h" -#include "packed.h" -#include "savegame.h" -#include "replay.h" -#include "gameplayer.h" -#include "gameprotocol.h" -#include "game_base.h" -#include "game_admin.h" - -#include - -#include - -using namespace boost :: filesystem; - -// -// CAdminGame -// - -CAdminGame :: CAdminGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nPassword ) : CBaseGame( nGHost, nMap, nSaveGame, nHostPort, nGameState, nGameName, string( ), string( ), string( ) ) -{ - m_VirtualHostName = "|cFFC04040Admin"; - m_MuteLobby = true; - m_Password = nPassword; -} - -CAdminGame :: ~CAdminGame( ) -{ - for( vector :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - for( vector :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - /* - - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); - - */ - - for( vector :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); i++ ) - m_GHost->m_Callables.push_back( i->second ); -} - -bool CAdminGame :: Update( void *fd, void *send_fd ) -{ - // - // update callables - // - - for( vector :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); ) - { - if( i->second->GetReady( ) ) - { - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - uint32_t Count = i->second->GetResult( ); - - if( Count == 0 ) - SendChat( Player, m_GHost->m_Language->ThereAreNoAdmins( i->second->GetServer( ) ) ); - else if( Count == 1 ) - SendChat( Player, m_GHost->m_Language->ThereIsAdmin( i->second->GetServer( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ThereAreAdmins( i->second->GetServer( ), UTIL_ToString( Count ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminCounts.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - for( vector :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) - { - if( (*j)->GetServer( ) == i->second->GetServer( ) ) - (*j)->AddAdmin( i->second->GetUser( ) ); - } - } - - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - if( i->second->GetResult( ) ) - SendChat( Player, m_GHost->m_Language->AddedUserToAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ErrorAddingUserToAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminAdds.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - for( vector :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) - { - if( (*j)->GetServer( ) == i->second->GetServer( ) ) - (*j)->RemoveAdmin( i->second->GetUser( ) ); - } - } - - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - if( i->second->GetResult( ) ) - SendChat( Player, m_GHost->m_Language->DeletedUserFromAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ErrorDeletingUserFromAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedAdminRemoves.erase( i ); - } - else - i++; - } - - for( vector :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); ) - { - if( i->second->GetReady( ) ) - { - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - uint32_t Count = i->second->GetResult( ); - - if( Count == 0 ) - SendChat( Player, m_GHost->m_Language->ThereAreNoBannedUsers( i->second->GetServer( ) ) ); - else if( Count == 1 ) - SendChat( Player, m_GHost->m_Language->ThereIsBannedUser( i->second->GetServer( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ThereAreBannedUsers( i->second->GetServer( ), UTIL_ToString( Count ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanCounts.erase( i ); - } - else - i++; - } - - /* - - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - for( vector :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) - { - if( (*j)->GetServer( ) == i->second->GetServer( ) ) - (*j)->AddBan( i->second->GetUser( ), i->second->GetIP( ), i->second->GetGameName( ), i->second->GetAdmin( ), i->second->GetReason( ) ); - } - } - - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - if( i->second->GetResult( ) ) - SendChat( Player, m_GHost->m_Language->BannedUser( i->second->GetServer( ), i->second->GetUser( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ErrorBanningUser( i->second->GetServer( ), i->second->GetUser( ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanAdds.erase( i ); - } - else - i++; - } - - */ - - for( vector :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); ) - { - if( i->second->GetReady( ) ) - { - if( i->second->GetResult( ) ) - { - for( vector :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) - { - if( (*j)->GetServer( ) == i->second->GetServer( ) ) - (*j)->RemoveBan( i->second->GetUser( ) ); - } - } - - CGamePlayer *Player = GetPlayerFromName( i->first, true ); - - if( Player ) - { - if( i->second->GetResult( ) ) - SendChat( Player, m_GHost->m_Language->UnbannedUser( i->second->GetUser( ) ) ); - else - SendChat( Player, m_GHost->m_Language->ErrorUnbanningUser( i->second->GetUser( ) ) ); - } - - m_GHost->m_DB->RecoverCallable( i->second ); - delete i->second; - i = m_PairedBanRemoves.erase( i ); - } - else - i++; - } - - // reset the last reserved seen timer since the admin game should never be considered abandoned - - m_LastReservedSeen = GetTime( ); - return CBaseGame :: Update( fd, send_fd ); -} - -void CAdminGame :: SendAdminChat( string message ) -{ - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetLoggedIn( ) ) - SendChat( *i, message ); - } -} - -void CAdminGame :: SendWelcomeMessage( CGamePlayer *player ) -{ - SendChat( player, "GHost++ Admin Game http://www.codelain.com/" ); - SendChat( player, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" ); - SendChat( player, "Commands: addadmin, autohost, autohostmm, checkadmin" ); - SendChat( player, "Commands: checkban, countadmins, countbans, deladmin" ); - SendChat( player, "Commands: delban, disable, downloads, enable, end, enforcesg" ); - SendChat( player, "Commands: exit, getgame, getgames, hostsg, load, loadsg" ); - SendChat( player, "Commands: map, password, priv, privby, pub, pubby, quit" ); - SendChat( player, "Commands: reload, say, saygame, saygames, unban, unhost, w" ); -} - -void CAdminGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ) -{ - uint32_t Time = GetTime( ); - - for( vector :: iterator i = m_TempBans.begin( ); i != m_TempBans.end( ); ) - { - // remove old tempbans (after 5 seconds) - - if( Time - (*i).second >= 5 ) - i = m_TempBans.erase( i ); - else - { - if( (*i).first == potential->GetExternalIPString( ) ) - { - // tempbanned, goodbye - - potential->GetSocket( )->PutBytes( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_WRONGPASSWORD ) ); - potential->SetDeleteMe( true ); - CONSOLE_Print( "[ADMINGAME] player [" + joinPlayer->GetName( ) + "] at ip [" + (*i).first + "] is trying to join the game but is tempbanned" ); - return; - } - - i++; - } - } - - CBaseGame :: EventPlayerJoined( potential, joinPlayer ); -} - -bool CAdminGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string payload ) -{ - CBaseGame :: EventPlayerBotCommand( player, command, payload ); - - // todotodo: don't be lazy - - string User = player->GetName( ); - string Command = command; - string Payload = payload; - - if( player->GetLoggedIn( ) ) - { - CONSOLE_Print( "[ADMINGAME] admin [" + User + "] sent command [" + Command + "] with payload [" + Payload + "]" ); - - /***************** - * ADMIN COMMANDS * - ******************/ - - // - // !ADDADMIN - // - - if( Command == "addadmin" && !Payload.empty( ) ) - { - // extract the name and the server - // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" - - string Name; - string Server; - stringstream SS; - SS << Payload; - SS >> Name; - - if( SS.eof( ) ) - { - if( m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - else - CONSOLE_Print( "[ADMINGAME] missing input #2 to addadmin command" ); - } - else - SS >> Server; - - if( !Server.empty( ) ) - { - string Servers; - bool FoundServer = false; - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - if( Servers.empty( ) ) - Servers = (*i)->GetServer( ); - else - Servers += ", " + (*i)->GetServer( ); - - if( (*i)->GetServer( ) == Server ) - { - FoundServer = true; - - if( (*i)->IsAdmin( Name ) ) - SendChat( player, m_GHost->m_Language->UserIsAlreadyAnAdmin( Server, Name ) ); - else - m_PairedAdminAdds.push_back( PairedAdminAdd( player->GetName( ), m_GHost->m_DB->ThreadedAdminAdd( Server, Name ) ) ); - - break; - } - } - - if( !FoundServer ) - SendChat( player, m_GHost->m_Language->ValidServers( Servers ) ); - } - } - - // - // !AUTOHOST - // - - if( Command == "autohost" ) - { - if( Payload.empty( ) || Payload == "off" ) - { - SendChat( player, m_GHost->m_Language->AutoHostDisabled( ) ); - m_GHost->m_AutoHostGameName.clear( ); - m_GHost->m_AutoHostOwner.clear( ); - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = 0; - m_GHost->m_AutoHostAutoStartPlayers = 0; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - else - { - // extract the maximum games, auto start players, and the game name - // e.g. "5 10 BattleShips Pro" -> maximum games: "5", auto start players: "10", game name: "BattleShips Pro" - - uint32_t MaximumGames; - uint32_t AutoStartPlayers; - string GameName; - stringstream SS; - SS << Payload; - SS >> MaximumGames; - - if( SS.fail( ) || MaximumGames == 0 ) - CONSOLE_Print( "[ADMINGAME] bad input #1 to autohost command" ); - else - { - SS >> AutoStartPlayers; - - if( SS.fail( ) || AutoStartPlayers == 0 ) - CONSOLE_Print( "[ADMINGAME] bad input #2 to autohost command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[ADMINGAME] missing input #3 to autohost command" ); - else - { - getline( SS, GameName ); - string :: size_type Start = GameName.find_first_not_of( " " ); - - if( Start != string :: npos ) - GameName = GameName.substr( Start ); - - SendChat( player, m_GHost->m_Language->AutoHostEnabled( ) ); - delete m_GHost->m_AutoHostMap; - m_GHost->m_AutoHostMap = new CMap( *m_GHost->m_Map ); - m_GHost->m_AutoHostGameName = GameName; - m_GHost->m_AutoHostOwner = User; - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = MaximumGames; - m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - } - } - } - } - - // - // !AUTOHOSTMM - // - - if( Command == "autohostmm" ) - { - if( Payload.empty( ) || Payload == "off" ) - { - SendChat( player, m_GHost->m_Language->AutoHostDisabled( ) ); - m_GHost->m_AutoHostGameName.clear( ); - m_GHost->m_AutoHostOwner.clear( ); - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = 0; - m_GHost->m_AutoHostAutoStartPlayers = 0; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = false; - m_GHost->m_AutoHostMinimumScore = 0.0; - m_GHost->m_AutoHostMaximumScore = 0.0; - } - else - { - // extract the maximum games, auto start players, and the game name - // e.g. "5 10 800 1200 BattleShips Pro" -> maximum games: "5", auto start players: "10", minimum score: "800", maximum score: "1200", game name: "BattleShips Pro" - - uint32_t MaximumGames; - uint32_t AutoStartPlayers; - double MinimumScore; - double MaximumScore; - string GameName; - stringstream SS; - SS << Payload; - SS >> MaximumGames; - - if( SS.fail( ) || MaximumGames == 0 ) - CONSOLE_Print( "[ADMINGAME] bad input #1 to autohostmm command" ); - else - { - SS >> AutoStartPlayers; - - if( SS.fail( ) || AutoStartPlayers == 0 ) - CONSOLE_Print( "[ADMINGAME] bad input #2 to autohostmm command" ); - else - { - SS >> MinimumScore; - - if( SS.fail( ) ) - CONSOLE_Print( "[ADMINGAME] bad input #3 to autohostmm command" ); - else - { - SS >> MaximumScore; - - if( SS.fail( ) ) - CONSOLE_Print( "[ADMINGAME] bad input #4 to autohostmm command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[ADMINGAME] missing input #5 to autohostmm command" ); - else - { - getline( SS, GameName ); - string :: size_type Start = GameName.find_first_not_of( " " ); - - if( Start != string :: npos ) - GameName = GameName.substr( Start ); - - SendChat( player, m_GHost->m_Language->AutoHostEnabled( ) ); - delete m_GHost->m_AutoHostMap; - m_GHost->m_AutoHostMap = new CMap( *m_GHost->m_Map ); - m_GHost->m_AutoHostGameName = GameName; - m_GHost->m_AutoHostOwner = User; - m_GHost->m_AutoHostServer.clear( ); - m_GHost->m_AutoHostMaximumGames = MaximumGames; - m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; - m_GHost->m_LastAutoHostTime = GetTime( ); - m_GHost->m_AutoHostMatchMaking = true; - m_GHost->m_AutoHostMinimumScore = MinimumScore; - m_GHost->m_AutoHostMaximumScore = MaximumScore; - } - } - } - } - } - } - } - - // - // !CHECKADMIN - // - - if( Command == "checkadmin" && !Payload.empty( ) ) - { - // extract the name and the server - // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" - - string Name; - string Server; - stringstream SS; - SS << Payload; - SS >> Name; - - if( SS.eof( ) ) - { - if( m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - else - CONSOLE_Print( "[ADMINGAME] missing input #2 to checkadmin command" ); - } - else - SS >> Server; - - if( !Server.empty( ) ) - { - string Servers; - bool FoundServer = false; - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - if( Servers.empty( ) ) - Servers = (*i)->GetServer( ); - else - Servers += ", " + (*i)->GetServer( ); - - if( (*i)->GetServer( ) == Server ) - { - FoundServer = true; - - if( (*i)->IsAdmin( Name ) ) - SendChat( player, m_GHost->m_Language->UserIsAnAdmin( Server, Name ) ); - else - SendChat( player, m_GHost->m_Language->UserIsNotAnAdmin( Server, Name ) ); - - break; - } - } - - if( !FoundServer ) - SendChat( player, m_GHost->m_Language->ValidServers( Servers ) ); - } - } - - // - // !CHECKBAN - // - - if( Command == "checkban" && !Payload.empty( ) ) - { - // extract the name and the server - // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" - - string Name; - string Server; - stringstream SS; - SS << Payload; - SS >> Name; - - if( SS.eof( ) ) - { - if( m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - else - CONSOLE_Print( "[ADMINGAME] missing input #2 to checkban command" ); - } - else - SS >> Server; - - if( !Server.empty( ) ) - { - string Servers; - bool FoundServer = false; - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - if( Servers.empty( ) ) - Servers = (*i)->GetServer( ); - else - Servers += ", " + (*i)->GetServer( ); - - if( (*i)->GetServer( ) == Server ) - { - FoundServer = true; - CDBBan *Ban = (*i)->IsBannedName( Name ); - - if( Ban ) - SendChat( player, m_GHost->m_Language->UserWasBannedOnByBecause( Server, Name, Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); - else - SendChat( player, m_GHost->m_Language->UserIsNotBanned( Server, Name ) ); - - break; - } - } - - if( !FoundServer ) - SendChat( player, m_GHost->m_Language->ValidServers( Servers ) ); - } - } - - // - // !COUNTADMINS - // - - if( Command == "countadmins" ) - { - string Server = Payload; - - if( Server.empty( ) && m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - - if( !Server.empty( ) ) - m_PairedAdminCounts.push_back( PairedAdminCount( player->GetName( ), m_GHost->m_DB->ThreadedAdminCount( Server ) ) ); - } - - // - // !COUNTBANS - // - - if( Command == "countbans" ) - { - string Server = Payload; - - if( Server.empty( ) && m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - - if( !Server.empty( ) ) - m_PairedBanCounts.push_back( PairedBanCount( player->GetName( ), m_GHost->m_DB->ThreadedBanCount( Server ) ) ); - } - - // - // !DELADMIN - // - - if( Command == "deladmin" && !Payload.empty( ) ) - { - // extract the name and the server - // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" - - string Name; - string Server; - stringstream SS; - SS << Payload; - SS >> Name; - - if( SS.eof( ) ) - { - if( m_GHost->m_BNETs.size( ) == 1 ) - Server = m_GHost->m_BNETs[0]->GetServer( ); - else - CONSOLE_Print( "[ADMINGAME] missing input #2 to deladmin command" ); - } - else - SS >> Server; - - if( !Server.empty( ) ) - { - string Servers; - bool FoundServer = false; - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - if( Servers.empty( ) ) - Servers = (*i)->GetServer( ); - else - Servers += ", " + (*i)->GetServer( ); - - if( (*i)->GetServer( ) == Server ) - { - FoundServer = true; - - if( !(*i)->IsAdmin( Name ) ) - SendChat( player, m_GHost->m_Language->UserIsNotAnAdmin( Server, Name ) ); - else - m_PairedAdminRemoves.push_back( PairedAdminRemove( player->GetName( ), m_GHost->m_DB->ThreadedAdminRemove( Server, Name ) ) ); - - break; - } - } - - if( !FoundServer ) - SendChat( player, m_GHost->m_Language->ValidServers( Servers ) ); - } - } - - // - // !DELBAN - // !UNBAN - // - - if( ( Command == "delban" || Command == "unban" ) && !Payload.empty( ) ) - m_PairedBanRemoves.push_back( PairedBanRemove( player->GetName( ), m_GHost->m_DB->ThreadedBanRemove( Payload ) ) ); - - // - // !DISABLE - // - - if( Command == "disable" ) - { - SendChat( player, m_GHost->m_Language->BotDisabled( ) ); - m_GHost->m_Enabled = false; - } - - // - // !DOWNLOADS - // - - if( Command == "downloads" && !Payload.empty( ) ) - { - uint32_t Downloads = UTIL_ToUInt32( Payload ); - - if( Downloads == 0 ) - { - SendChat( player, m_GHost->m_Language->MapDownloadsDisabled( ) ); - m_GHost->m_AllowDownloads = 0; - } - else if( Downloads == 1 ) - { - SendChat( player, m_GHost->m_Language->MapDownloadsEnabled( ) ); - m_GHost->m_AllowDownloads = 1; - } - else if( Downloads == 2 ) - { - SendChat( player, m_GHost->m_Language->MapDownloadsConditional( ) ); - m_GHost->m_AllowDownloads = 2; - } - } - - // - // !ENABLE - // - - if( Command == "enable" ) - { - SendChat( player, m_GHost->m_Language->BotEnabled( ) ); - m_GHost->m_Enabled = true; - } - - // - // !END - // - - if( Command == "end" && !Payload.empty( ) ) - { - // todotodo: what if a game ends just as you're typing this command and the numbering changes? - - uint32_t GameNumber = UTIL_ToUInt32( Payload ) - 1; - - if( GameNumber < m_GHost->m_Games.size( ) ) - { - SendChat( player, m_GHost->m_Language->EndingGame( m_GHost->m_Games[GameNumber]->GetDescription( ) ) ); - CONSOLE_Print( "[GAME: " + m_GHost->m_Games[GameNumber]->GetGameName( ) + "] is over (admin ended game)" ); - m_GHost->m_Games[GameNumber]->StopPlayers( "was disconnected (admin ended game)" ); - } - else - SendChat( player, m_GHost->m_Language->GameNumberDoesntExist( Payload ) ); - } - - // - // !ENFORCESG - // - - if( Command == "enforcesg" && !Payload.empty( ) ) - { - // only load files in the current directory just to be safe - - if( Payload.find( "/" ) != string :: npos || Payload.find( "\\" ) != string :: npos ) - SendChat( player, m_GHost->m_Language->UnableToLoadReplaysOutside( ) ); - else - { - string File = m_GHost->m_ReplayPath + Payload + ".w3g"; - - if( UTIL_FileExists( File ) ) - { - SendChat( player, m_GHost->m_Language->LoadingReplay( File ) ); - CReplay *Replay = new CReplay( ); - Replay->Load( File, false ); - Replay->ParseReplay( false ); - m_GHost->m_EnforcePlayers = Replay->GetPlayers( ); - delete Replay; - } - else - SendChat( player, m_GHost->m_Language->UnableToLoadReplayDoesntExist( File ) ); - } - } - - // - // !EXIT - // !QUIT - // - - if( Command == "exit" || Command == "quit" ) - { - if( Payload == "nice" ) - m_GHost->m_ExitingNice = true; - else if( Payload == "force" ) - m_Exiting = true; - else - { - if( m_GHost->m_CurrentGame || !m_GHost->m_Games.empty( ) ) - SendChat( player, m_GHost->m_Language->AtLeastOneGameActiveUseForceToShutdown( ) ); - else - m_Exiting = true; - } - } - - // - // !GETGAME - // - - if( Command == "getgame" && !Payload.empty( ) ) - { - uint32_t GameNumber = UTIL_ToUInt32( Payload ) - 1; - - if( GameNumber < m_GHost->m_Games.size( ) ) - SendChat( player, m_GHost->m_Language->GameNumberIs( Payload, m_GHost->m_Games[GameNumber]->GetDescription( ) ) ); - else - SendChat( player, m_GHost->m_Language->GameNumberDoesntExist( Payload ) ); - } - - // - // !GETGAMES - // - - if( Command == "getgames" ) - { - if( m_GHost->m_CurrentGame ) - SendChat( player, m_GHost->m_Language->GameIsInTheLobby( m_GHost->m_CurrentGame->GetDescription( ), UTIL_ToString( m_GHost->m_Games.size( ) ), UTIL_ToString( m_GHost->m_MaxGames ) ) ); - else - SendChat( player, m_GHost->m_Language->ThereIsNoGameInTheLobby( UTIL_ToString( m_GHost->m_Games.size( ) ), UTIL_ToString( m_GHost->m_MaxGames ) ) ); - } - - // - // !HOSTSG - // - - if( Command == "hostsg" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, true, Payload, User, User, string( ), false ); - - // - // !LOAD (load config file) - // - - if( Command == "load" ) - { - if( Payload.empty( ) ) - SendChat( player, m_GHost->m_Language->CurrentlyLoadedMapCFGIs( m_GHost->m_Map->GetCFGFile( ) ) ); - else - { - string FoundMapConfigs; - - try - { - path MapCFGPath( m_GHost->m_MapCFGPath ); - string Pattern = Payload; - transform( Pattern.begin( ), Pattern.end( ), Pattern.begin( ), (int(*)(int))tolower ); - - if( !exists( MapCFGPath ) ) - { - CONSOLE_Print( "[ADMINGAME] error listing map configs - map config path doesn't exist" ); - SendChat( player, m_GHost->m_Language->ErrorListingMapConfigs( ) ); - } - else - { - directory_iterator EndIterator; - path LastMatch; - uint32_t Matches = 0; - - for( directory_iterator i( MapCFGPath ); i != EndIterator; i++ ) - { - string FileName = i->filename( ); - string Stem = i->path( ).stem( ); - transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower ); - transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower ); - - if( !is_directory( i->status( ) ) && i->path( ).extension( ) == ".cfg" && FileName.find( Pattern ) != string :: npos ) - { - LastMatch = i->path( ); - Matches++; - - if( FoundMapConfigs.empty( ) ) - FoundMapConfigs = i->filename( ); - else - FoundMapConfigs += ", " + i->filename( ); - - // if the pattern matches the filename exactly, with or without extension, stop any further matching - - if( FileName == Pattern || Stem == Pattern ) - { - Matches = 1; - break; - } - } - } - - if( Matches == 0 ) - SendChat( player, m_GHost->m_Language->NoMapConfigsFound( ) ); - else if( Matches == 1 ) - { - string File = LastMatch.filename( ); - SendChat( player, m_GHost->m_Language->LoadingConfigFile( m_GHost->m_MapCFGPath + File ) ); - CConfig MapCFG; - MapCFG.Read( LastMatch.string( ) ); - m_GHost->m_Map->Load( &MapCFG, m_GHost->m_MapCFGPath + File ); - } - else - SendChat( player, m_GHost->m_Language->FoundMapConfigs( FoundMapConfigs ) ); - } - } - catch( const exception &ex ) - { - CONSOLE_Print( string( "[ADMINGAME] error listing map configs - caught exception [" ) + ex.what( ) + "]" ); - SendChat( player, m_GHost->m_Language->ErrorListingMapConfigs( ) ); - } - } - } - - // - // !LOADSG - // - - if( Command == "loadsg" && !Payload.empty( ) ) - { - // only load files in the current directory just to be safe - - if( Payload.find( "/" ) != string :: npos || Payload.find( "\\" ) != string :: npos ) - SendChat( player, m_GHost->m_Language->UnableToLoadSaveGamesOutside( ) ); - else - { - string File = m_GHost->m_SaveGamePath + Payload + ".w3z"; - string FileNoPath = Payload + ".w3z"; - - if( UTIL_FileExists( File ) ) - { - if( m_GHost->m_CurrentGame ) - SendChat( player, m_GHost->m_Language->UnableToLoadSaveGameGameInLobby( ) ); - else - { - SendChat( player, m_GHost->m_Language->LoadingSaveGame( File ) ); - m_GHost->m_SaveGame->Load( File, false ); - m_GHost->m_SaveGame->ParseSaveGame( ); - m_GHost->m_SaveGame->SetFileName( File ); - m_GHost->m_SaveGame->SetFileNameNoPath( FileNoPath ); - } - } - else - SendChat( player, m_GHost->m_Language->UnableToLoadSaveGameDoesntExist( File ) ); - } - } - - // - // !MAP (load map file) - // - - if( Command == "map" ) - { - if( Payload.empty( ) ) - SendChat( player, m_GHost->m_Language->CurrentlyLoadedMapCFGIs( m_GHost->m_Map->GetCFGFile( ) ) ); - else - { - string FoundMaps; - - try - { - path MapPath( m_GHost->m_MapPath ); - string Pattern = Payload; - transform( Pattern.begin( ), Pattern.end( ), Pattern.begin( ), (int(*)(int))tolower ); - - if( !exists( MapPath ) ) - { - CONSOLE_Print( "[ADMINGAME] error listing maps - map path doesn't exist" ); - SendChat( player, m_GHost->m_Language->ErrorListingMaps( ) ); - } - else - { - directory_iterator EndIterator; - path LastMatch; - uint32_t Matches = 0; - - for( directory_iterator i( MapPath ); i != EndIterator; i++ ) - { - string FileName = i->filename( ); - string Stem = i->path( ).stem( ); - transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower ); - transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower ); - - if( !is_directory( i->status( ) ) && FileName.find( Pattern ) != string :: npos ) - { - LastMatch = i->path( ); - Matches++; - - if( FoundMaps.empty( ) ) - FoundMaps = i->filename( ); - else - FoundMaps += ", " + i->filename( ); - - // if the pattern matches the filename exactly, with or without extension, stop any further matching - - if( FileName == Pattern || Stem == Pattern ) - { - Matches = 1; - break; - } - } - } - - if( Matches == 0 ) - SendChat( player, m_GHost->m_Language->NoMapsFound( ) ); - else if( Matches == 1 ) - { - string File = LastMatch.filename( ); - SendChat( player, m_GHost->m_Language->LoadingConfigFile( File ) ); - - // hackhack: create a config file in memory with the required information to load the map - - CConfig MapCFG; - MapCFG.Set( "map_path", "Maps\\Download\\" + File ); - MapCFG.Set( "map_localpath", File ); - m_GHost->m_Map->Load( &MapCFG, File ); - } - else - SendChat( player, m_GHost->m_Language->FoundMaps( FoundMaps ) ); - } - } - catch( const exception &ex ) - { - CONSOLE_Print( string( "[ADMINGAME] error listing maps - caught exception [" ) + ex.what( ) + "]" ); - SendChat( player, m_GHost->m_Language->ErrorListingMaps( ) ); - } - } - } - - // - // !PRIV (host private game) - // - - if( Command == "priv" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, false, Payload, User, User, string( ), false ); - - // - // !PRIVBY (host private game by other player) - // - - if( Command == "privby" && !Payload.empty( ) ) - { - // extract the owner and the game name - // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" - - string Owner; - string GameName; - string :: size_type GameNameStart = Payload.find( " " ); - - if( GameNameStart != string :: npos ) - { - Owner = Payload.substr( 0, GameNameStart ); - GameName = Payload.substr( GameNameStart + 1 ); - m_GHost->CreateGame( m_GHost->m_Map, GAME_PRIVATE, false, GameName, Owner, User, string( ), false ); - } - } - - // - // !PUB (host public game) - // - - if( Command == "pub" && !Payload.empty( ) ) - m_GHost->CreateGame( m_GHost->m_Map, GAME_PUBLIC, false, Payload, User, User, string( ), false ); - - // - // !PUBBY (host public game by other player) - // - - if( Command == "pubby" && !Payload.empty( ) ) - { - // extract the owner and the game name - // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" - - string Owner; - string GameName; - string :: size_type GameNameStart = Payload.find( " " ); - - if( GameNameStart != string :: npos ) - { - Owner = Payload.substr( 0, GameNameStart ); - GameName = Payload.substr( GameNameStart + 1 ); - m_GHost->CreateGame( m_GHost->m_Map, GAME_PUBLIC, false, GameName, Owner, User, string( ), false ); - } - } - - // - // !RELOAD - // - - if( Command == "reload" ) - { - SendChat( player, m_GHost->m_Language->ReloadingConfigurationFiles( ) ); - m_GHost->ReloadConfigs( ); - } - - // - // !SAY - // - - if( Command == "say" && !Payload.empty( ) ) - { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - (*i)->QueueChatCommand( Payload ); - } - - // - // !SAYGAME - // - - if( Command == "saygame" && !Payload.empty( ) ) - { - // extract the game number and the message - // e.g. "3 hello everyone" -> game number: "3", message: "hello everyone" - - uint32_t GameNumber; - string Message; - stringstream SS; - SS << Payload; - SS >> GameNumber; - - if( SS.fail( ) ) - CONSOLE_Print( "[ADMINGAME] bad input #1 to saygame command" ); - else - { - if( SS.eof( ) ) - CONSOLE_Print( "[ADMINGAME] missing input #2 to saygame command" ); - else - { - getline( SS, Message ); - string :: size_type Start = Message.find_first_not_of( " " ); - - if( Start != string :: npos ) - Message = Message.substr( Start ); - - if( GameNumber - 1 < m_GHost->m_Games.size( ) ) - m_GHost->m_Games[GameNumber - 1]->SendAllChat( "ADMIN: " + Message ); - else - SendChat( player, m_GHost->m_Language->GameNumberDoesntExist( UTIL_ToString( GameNumber ) ) ); - } - } - } - - // - // !SAYGAMES - // - - if( Command == "saygames" && !Payload.empty( ) ) - { - if( m_GHost->m_CurrentGame ) - m_GHost->m_CurrentGame->SendAllChat( Payload ); - - for( vector :: iterator i = m_GHost->m_Games.begin( ); i != m_GHost->m_Games.end( ); i++ ) - (*i)->SendAllChat( "ADMIN: " + Payload ); - } - - // - // !UNHOST - // - - if( Command == "unhost" ) - { - if( m_GHost->m_CurrentGame ) - { - if( m_GHost->m_CurrentGame->GetCountDownStarted( ) ) - SendChat( player, m_GHost->m_Language->UnableToUnhostGameCountdownStarted( m_GHost->m_CurrentGame->GetDescription( ) ) ); - else - { - SendChat( player, m_GHost->m_Language->UnhostingGame( m_GHost->m_CurrentGame->GetDescription( ) ) ); - m_GHost->m_CurrentGame->SetExiting( true ); - } - } - else - SendChat( player, m_GHost->m_Language->UnableToUnhostGameNoGameInLobby( ) ); - } - - // - // !W - // - - if( Command == "w" && !Payload.empty( ) ) - { - // extract the name and the message - // e.g. "Varlock hello there!" -> name: "Varlock", message: "hello there!" - - string Name; - string Message; - string :: size_type MessageStart = Payload.find( " " ); - - if( MessageStart != string :: npos ) - { - Name = Payload.substr( 0, MessageStart ); - Message = Payload.substr( MessageStart + 1 ); - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - (*i)->QueueChatCommand( Message, Name, true ); - } - } - } - else - CONSOLE_Print( "[ADMINGAME] user [" + User + "] sent command [" + Command + "] with payload [" + Payload + "]" ); - - /********************* - * NON ADMIN COMMANDS * - *********************/ - - // - // !PASSWORD - // - - if( Command == "password" && !player->GetLoggedIn( ) ) - { - if( !m_Password.empty( ) && Payload == m_Password ) - { - CONSOLE_Print( "[ADMINGAME] user [" + User + "] logged in" ); - SendChat( player, m_GHost->m_Language->AdminLoggedIn( ) ); - player->SetLoggedIn( true ); - } - else - { - uint32_t LoginAttempts = player->GetLoginAttempts( ) + 1; - player->SetLoginAttempts( LoginAttempts ); - CONSOLE_Print( "[ADMINGAME] user [" + User + "] login attempt failed" ); - SendChat( player, m_GHost->m_Language->AdminInvalidPassword( UTIL_ToString( LoginAttempts ) ) ); - - if( LoginAttempts >= 1 ) - { - player->SetDeleteMe( true ); - player->SetLeftReason( "was kicked for too many failed login attempts" ); - player->SetLeftCode( PLAYERLEAVE_LOBBY ); - OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); - - // tempban for 5 seconds to prevent bruteforcing - - m_TempBans.push_back( TempBan( player->GetExternalIPString( ), GetTime( ) ) ); - } - } - } - - // always hide chat commands from other players in the admin game - // note: this is actually redundant because we've already set m_MuteLobby = true so this has no effect - // if you actually wanted to relay chat commands you would have to set m_MuteLobby = false AND return false here - - return true; -} diff --git a/ghost/game_admin.h b/ghost/game_admin.h deleted file mode 100644 index f59aa96..0000000 --- a/ghost/game_admin.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GAME_ADMIN_H -#define GAME_ADMIN_H - -// -// CAdminGame -// - -class CCallableAdminCount; -class CCallableAdminAdd; -class CCallableAdminRemove; -class CCallableBanCount; -// class CCallableBanAdd; -class CCallableBanRemove; - -typedef pair PairedAdminCount; -typedef pair PairedAdminAdd; -typedef pair PairedAdminRemove; -typedef pair PairedBanCount; -// typedef pair PairedBanAdd; -typedef pair PairedBanRemove; - -typedef pair TempBan; - -class CAdminGame : public CBaseGame -{ -protected: - string m_Password; - vector m_TempBans; - vector m_PairedAdminCounts; // vector of paired threaded database admin counts in progress - vector m_PairedAdminAdds; // vector of paired threaded database admin adds in progress - vector m_PairedAdminRemoves; // vector of paired threaded database admin removes in progress - vector m_PairedBanCounts; // vector of paired threaded database ban counts in progress - // vector m_PairedBanAdds; // vector of paired threaded database ban adds in progress - vector m_PairedBanRemoves; // vector of paired threaded database ban removes in progress - -public: - CAdminGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nPassword ); - virtual ~CAdminGame( ); - - virtual bool Update( void *fd, void *send_fd ); - virtual void SendAdminChat( string message ); - virtual void SendWelcomeMessage( CGamePlayer *player ); - virtual void EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ); - virtual bool EventPlayerBotCommand( CGamePlayer *player, string command, string payload ); -}; - -#endif diff --git a/ghost/game_base.h b/ghost/game_base.h deleted file mode 100644 index 1868c2f..0000000 --- a/ghost/game_base.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GAME_BASE_H -#define GAME_BASE_H - -#include "gameslot.h" - -// -// CBaseGame -// - -class CTCPServer; -class CGameProtocol; -class CPotentialPlayer; -class CGamePlayer; -class CMap; -class CSaveGame; -class CReplay; -class CIncomingJoinPlayer; -class CIncomingAction; -class CIncomingChatPlayer; -class CIncomingMapSize; -class CCallableScoreCheck; - -class CBaseGame -{ -public: - CGHost *m_GHost; - -protected: - CTCPServer *m_Socket; // listening socket - CGameProtocol *m_Protocol; // game protocol - vector m_Slots; // vector of slots - vector m_Potentials; // vector of potential players (connections that haven't sent a W3GS_REQJOIN packet yet) - vector m_Players; // vector of players - vector m_ScoreChecks; - queue m_Actions; // queue of actions to be sent - vector m_Reserved; // vector of player names with reserved slots (from the !hold command) - set m_IgnoredNames; // set of player names to NOT print ban messages for when joining because they've already been printed - set m_IPBlackList; // set of IP addresses to blacklist from joining (todotodo: convert to uint32's for efficiency) - vector m_EnforceSlots; // vector of slots to force players to use (used with saved games) - vector m_EnforcePlayers; // vector of pids to force players to use (used with saved games) - CMap *m_Map; // map data - CSaveGame *m_SaveGame; // savegame data (this is a pointer to global data) - CReplay *m_Replay; // replay - bool m_Exiting; // set to true and this class will be deleted next update - bool m_Saving; // if we're currently saving game data to the database - uint16_t m_HostPort; // the port to host games on - unsigned char m_GameState; // game state, public or private - unsigned char m_VirtualHostPID; // virtual host's PID - unsigned char m_FakePlayerPID; // the fake player's PID (if present) - unsigned char m_GProxyEmptyActions; - string m_GameName; // game name - string m_LastGameName; // last game name (the previous game name before it was rehosted) - string m_VirtualHostName; // virtual host's name - string m_OwnerName; // name of the player who owns this game (should be considered an admin) - string m_CreatorName; // name of the player who created this game - string m_CreatorServer; // battle.net server the player who created this game was on - string m_AnnounceMessage; // a message to be sent every m_AnnounceInterval seconds - string m_StatString; // the stat string when the game started (used when saving replays) - string m_KickVotePlayer; // the player to be kicked with the currently running kick vote - string m_HCLCommandString; // the "HostBot Command Library" command string, used to pass a limited amount of data to specially designed maps - uint32_t m_RandomSeed; // the random seed sent to the Warcraft III clients - uint32_t m_HostCounter; // a unique game number - uint32_t m_Latency; // the number of ms to wait between sending action packets (we queue any received during this time) - uint32_t m_SyncLimit; // the maximum number of packets a player can fall out of sync before starting the lag screen - uint32_t m_SyncCounter; // the number of actions sent so far (for determining if anyone is lagging) - uint32_t m_GameTicks; // ingame ticks - uint32_t m_CreationTime; // GetTime when the game was created - uint32_t m_LastPingTime; // GetTime when the last ping was sent - uint32_t m_LastRefreshTime; // GetTime when the last game refresh was sent - uint32_t m_LastDownloadTicks; // GetTicks when the last map download cycle was performed - uint32_t m_DownloadCounter; // # of map bytes downloaded in the last second - uint32_t m_LastDownloadCounterResetTicks; // GetTicks when the download counter was last reset - uint32_t m_LastAnnounceTime; // GetTime when the last announce message was sent - uint32_t m_AnnounceInterval; // how many seconds to wait between sending the m_AnnounceMessage - uint32_t m_LastAutoStartTime; // the last time we tried to auto start the game - uint32_t m_AutoStartPlayers; // auto start the game when there are this many players or more - uint32_t m_LastCountDownTicks; // GetTicks when the last countdown message was sent - uint32_t m_CountDownCounter; // the countdown is finished when this reaches zero - uint32_t m_StartedLoadingTicks; // GetTicks when the game started loading - uint32_t m_StartPlayers; // number of players when the game started - uint32_t m_LastLagScreenResetTime; // GetTime when the "lag" screen was last reset - uint32_t m_LastActionSentTicks; // GetTicks when the last action packet was sent - uint32_t m_LastActionLateBy; // the number of ticks we were late sending the last action packet by - uint32_t m_StartedLaggingTime; // GetTime when the last lag screen started - uint32_t m_LastLagScreenTime; // GetTime when the last lag screen was active (continuously updated) - uint32_t m_LastReservedSeen; // GetTime when the last reserved player was seen in the lobby - uint32_t m_StartedKickVoteTime; // GetTime when the kick vote was started - uint32_t m_GameOverTime; // GetTime when the game was over - uint32_t m_LastPlayerLeaveTicks; // GetTicks when the most recent player left the game - double m_MinimumScore; // the minimum allowed score for matchmaking mode - double m_MaximumScore; // the maximum allowed score for matchmaking mode - bool m_SlotInfoChanged; // if the slot info has changed and hasn't been sent to the players yet (optimization) - bool m_Locked; // if the game owner is the only one allowed to run game commands or not - bool m_RefreshMessages; // if we should display "game refreshed..." messages or not - bool m_RefreshError; // if there was an error refreshing the game - bool m_RefreshRehosted; // if we just rehosted and are waiting for confirmation that it was successful - bool m_MuteAll; // if we should stop forwarding ingame chat messages targeted for all players or not - bool m_MuteLobby; // if we should stop forwarding lobby chat messages - bool m_CountDownStarted; // if the game start countdown has started or not - bool m_GameLoading; // if the game is currently loading or not - bool m_GameLoaded; // if the game has loaded or not - bool m_LoadInGame; // if the load-in-game feature is enabled or not - bool m_Lagging; // if the lag screen is active or not - bool m_AutoSave; // if we should auto save the game before someone disconnects - bool m_MatchMaking; // if matchmaking mode is enabled - bool m_LocalAdminMessages; // if local admin messages should be relayed or not - -public: - CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nOwnerName, string nCreatorName, string nCreatorServer ); - virtual ~CBaseGame( ); - - virtual vector GetEnforceSlots( ) { return m_EnforceSlots; } - virtual vector GetEnforcePlayers( ) { return m_EnforcePlayers; } - virtual CSaveGame *GetSaveGame( ) { return m_SaveGame; } - virtual uint16_t GetHostPort( ) { return m_HostPort; } - virtual unsigned char GetGameState( ) { return m_GameState; } - virtual unsigned char GetGProxyEmptyActions( ) { return m_GProxyEmptyActions; } - virtual string GetGameName( ) { return m_GameName; } - virtual string GetLastGameName( ) { return m_LastGameName; } - virtual string GetVirtualHostName( ) { return m_VirtualHostName; } - virtual string GetOwnerName( ) { return m_OwnerName; } - virtual string GetCreatorName( ) { return m_CreatorName; } - virtual string GetCreatorServer( ) { return m_CreatorServer; } - virtual uint32_t GetHostCounter( ) { return m_HostCounter; } - virtual uint32_t GetLastLagScreenTime( ) { return m_LastLagScreenTime; } - virtual bool GetLocked( ) { return m_Locked; } - virtual bool GetRefreshMessages( ) { return m_RefreshMessages; } - virtual bool GetCountDownStarted( ) { return m_CountDownStarted; } - virtual bool GetGameLoading( ) { return m_GameLoading; } - virtual bool GetGameLoaded( ) { return m_GameLoaded; } - virtual bool GetLagging( ) { return m_Lagging; } - - virtual void SetEnforceSlots( vector nEnforceSlots ) { m_EnforceSlots = nEnforceSlots; } - virtual void SetEnforcePlayers( vector nEnforcePlayers ) { m_EnforcePlayers = nEnforcePlayers; } - virtual void SetExiting( bool nExiting ) { m_Exiting = nExiting; } - virtual void SetAutoStartPlayers( uint32_t nAutoStartPlayers ) { m_AutoStartPlayers = nAutoStartPlayers; } - virtual void SetMinimumScore( double nMinimumScore ) { m_MinimumScore = nMinimumScore; } - virtual void SetMaximumScore( double nMaximumScore ) { m_MaximumScore = nMaximumScore; } - virtual void SetRefreshError( bool nRefreshError ) { m_RefreshError = nRefreshError; } - virtual void SetMatchMaking( bool nMatchMaking ) { m_MatchMaking = nMatchMaking; } - - virtual uint32_t GetNextTimedActionTicks( ); - virtual uint32_t GetSlotsOccupied( ); - virtual uint32_t GetSlotsOpen( ); - virtual uint32_t GetNumPlayers( ); - virtual uint32_t GetNumHumanPlayers( ); - virtual string GetDescription( ); - - virtual void SetAnnounce( uint32_t interval, string message ); - - // processing functions - - virtual unsigned int SetFD( void *fd, void *send_fd, int *nfds ); - virtual bool Update( void *fd, void *send_fd ); - virtual void UpdatePost( void *send_fd ); - - // generic functions to send packets to players - - virtual void Send( CGamePlayer *player, BYTEARRAY data ); - virtual void Send( unsigned char PID, BYTEARRAY data ); - virtual void Send( BYTEARRAY PIDs, BYTEARRAY data ); - virtual void SendAll( BYTEARRAY data ); - - // functions to send packets to players - - virtual void SendChat( unsigned char fromPID, CGamePlayer *player, string message ); - virtual void SendChat( unsigned char fromPID, unsigned char toPID, string message ); - virtual void SendChat( CGamePlayer *player, string message ); - virtual void SendChat( unsigned char toPID, string message ); - virtual void SendAllChat( unsigned char fromPID, string message ); - virtual void SendAllChat( string message ); - virtual void SendLocalAdminChat( string message ); - virtual void SendAllSlotInfo( ); - virtual void SendVirtualHostPlayerInfo( CGamePlayer *player ); - virtual void SendFakePlayerInfo( CGamePlayer *player ); - virtual void SendAllActions( ); - virtual void SendWelcomeMessage( CGamePlayer *player ); - virtual void SendEndMessage( ); - - // events - // note: these are only called while iterating through the m_Potentials or m_Players vectors - // therefore you can't modify those vectors and must use the player's m_DeleteMe member to flag for deletion - - virtual void EventPlayerDeleted( CGamePlayer *player ); - virtual void EventPlayerDisconnectTimedOut( CGamePlayer *player ); - virtual void EventPlayerDisconnectPlayerError( CGamePlayer *player ); - virtual void EventPlayerDisconnectSocketError( CGamePlayer *player ); - virtual void EventPlayerDisconnectConnectionClosed( CGamePlayer *player ); - virtual void EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ); - virtual void EventPlayerJoinedWithScore( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer, double score ); - virtual void EventPlayerLeft( CGamePlayer *player, uint32_t reason ); - virtual void EventPlayerLoaded( CGamePlayer *player ); - virtual void EventPlayerAction( CGamePlayer *player, CIncomingAction *action ); - virtual void EventPlayerKeepAlive( CGamePlayer *player, uint32_t checkSum ); - virtual void EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlayer *chatPlayer ); - virtual bool EventPlayerBotCommand( CGamePlayer *player, string command, string payload ); - virtual void EventPlayerChangeTeam( CGamePlayer *player, unsigned char team ); - virtual void EventPlayerChangeColour( CGamePlayer *player, unsigned char colour ); - virtual void EventPlayerChangeRace( CGamePlayer *player, unsigned char race ); - virtual void EventPlayerChangeHandicap( CGamePlayer *player, unsigned char handicap ); - virtual void EventPlayerDropRequest( CGamePlayer *player ); - virtual void EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *mapSize ); - virtual void EventPlayerPongToHost( CGamePlayer *player, uint32_t pong ); - - // these events are called outside of any iterations - - virtual void EventGameRefreshed( string server ); - virtual void EventGameStarted( ); - virtual void EventGameLoaded( ); - - // other functions - - virtual unsigned char GetSIDFromPID( unsigned char PID ); - virtual CGamePlayer *GetPlayerFromPID( unsigned char PID ); - virtual CGamePlayer *GetPlayerFromSID( unsigned char SID ); - virtual CGamePlayer *GetPlayerFromName( string name, bool sensitive ); - virtual uint32_t GetPlayerFromNamePartial( string name, CGamePlayer **player ); - virtual CGamePlayer *GetPlayerFromColour( unsigned char colour ); - virtual unsigned char GetNewPID( ); - virtual unsigned char GetNewColour( ); - virtual BYTEARRAY GetPIDs( ); - virtual BYTEARRAY GetPIDs( unsigned char excludePID ); - virtual unsigned char GetHostPID( ); - virtual unsigned char GetEmptySlot( bool reserved ); - virtual unsigned char GetEmptySlot( unsigned char team, unsigned char PID ); - virtual void SwapSlots( unsigned char SID1, unsigned char SID2 ); - virtual void OpenSlot( unsigned char SID, bool kick ); - virtual void CloseSlot( unsigned char SID, bool kick ); - virtual void ComputerSlot( unsigned char SID, unsigned char skill, bool kick ); - virtual void ColourSlot( unsigned char SID, unsigned char colour ); - virtual void OpenAllSlots( ); - virtual void CloseAllSlots( ); - virtual void ShuffleSlots( ); - virtual vector BalanceSlotsRecursive( vector PlayerIDs, unsigned char *TeamSizes, double *PlayerScores, unsigned char StartTeam ); - virtual void BalanceSlots( ); - virtual void AddToSpoofed( string server, string name, bool sendMessage ); - virtual void AddToReserved( string name ); - virtual bool IsOwner( string name ); - virtual bool IsReserved( string name ); - virtual bool IsDownloading( ); - virtual bool IsGameDataSaved( ); - virtual void SaveGameData( ); - virtual void StartCountDown( bool force ); - virtual void StartCountDownAuto( bool requireSpoofChecks ); - virtual void StopPlayers( string reason ); - virtual void StopLaggers( string reason ); - virtual void CreateVirtualHost( ); - virtual void DeleteVirtualHost( ); - virtual void CreateFakePlayer( ); - virtual void DeleteFakePlayer( ); -}; - -#endif diff --git a/ghost/gameplayer.h b/ghost/gameplayer.h deleted file mode 100644 index 262d948..0000000 --- a/ghost/gameplayer.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GAMEPLAYER_H -#define GAMEPLAYER_H - -class CTCPSocket; -class CCommandPacket; -class CGameProtocol; -class CGame; -class CIncomingJoinPlayer; - -// -// CPotentialPlayer -// - -class CPotentialPlayer -{ -public: - CGameProtocol *m_Protocol; - CBaseGame *m_Game; - -protected: - // note: we permit m_Socket to be NULL in this class to allow for the virtual host player which doesn't really exist - // it also allows us to convert CPotentialPlayers to CGamePlayers without the CPotentialPlayer's destructor closing the socket - - CTCPSocket *m_Socket; - queue m_Packets; - bool m_DeleteMe; - bool m_Error; - string m_ErrorString; - CIncomingJoinPlayer *m_IncomingJoinPlayer; - -public: - CPotentialPlayer( CGameProtocol *nProtocol, CBaseGame *nGame, CTCPSocket *nSocket ); - virtual ~CPotentialPlayer( ); - - virtual CTCPSocket *GetSocket( ) { return m_Socket; } - virtual BYTEARRAY GetExternalIP( ); - virtual string GetExternalIPString( ); - virtual queue GetPackets( ) { return m_Packets; } - virtual bool GetDeleteMe( ) { return m_DeleteMe; } - virtual bool GetError( ) { return m_Error; } - virtual string GetErrorString( ) { return m_ErrorString; } - virtual CIncomingJoinPlayer *GetJoinPlayer( ) { return m_IncomingJoinPlayer; } - - virtual void SetSocket( CTCPSocket *nSocket ) { m_Socket = nSocket; } - virtual void SetDeleteMe( bool nDeleteMe ) { m_DeleteMe = nDeleteMe; } - - // processing functions - - virtual bool Update( void *fd ); - virtual void ExtractPackets( ); - virtual void ProcessPackets( ); - - // other functions - - virtual void Send( BYTEARRAY data ); -}; - -// -// CGamePlayer -// - -class CGamePlayer : public CPotentialPlayer -{ -private: - unsigned char m_PID; - string m_Name; // the player's name - BYTEARRAY m_InternalIP; // the player's internal IP address as reported by the player when connecting - vector m_Pings; // store the last few (20) pings received so we can take an average - queue m_CheckSums; // the last few checksums the player has sent (for detecting desyncs) - string m_LeftReason; // the reason the player left the game - string m_SpoofedRealm; // the realm the player last spoof checked on - string m_JoinedRealm; // the realm the player joined on (probable, can be spoofed) - uint32_t m_TotalPacketsSent; - uint32_t m_TotalPacketsReceived; - uint32_t m_LeftCode; // the code to be sent in W3GS_PLAYERLEAVE_OTHERS for why this player left the game - uint32_t m_LoginAttempts; // the number of attempts to login (used with CAdminGame only) - uint32_t m_SyncCounter; // the number of keepalive packets received from this player - uint32_t m_JoinTime; // GetTime when the player joined the game (used to delay sending the /whois a few seconds to allow for some lag) - uint32_t m_LastMapPartSent; // the last mappart sent to the player (for sending more than one part at a time) - uint32_t m_LastMapPartAcked; // the last mappart acknowledged by the player - uint32_t m_StartedDownloadingTicks; // GetTicks when the player started downloading the map - uint32_t m_FinishedDownloadingTime; // GetTime when the player finished downloading the map - uint32_t m_FinishedLoadingTicks; // GetTicks when the player finished loading the game - uint32_t m_StartedLaggingTicks; // GetTicks when the player started lagging - uint32_t m_StatsSentTime; // GetTime when we sent this player's stats to the chat (to prevent players from spamming !stats) - uint32_t m_StatsDotASentTime; // GetTime when we sent this player's dota stats to the chat (to prevent players from spamming !statsdota) - uint32_t m_LastGProxyWaitNoticeSentTime; - queue m_LoadInGameData; // queued data to be sent when the player finishes loading when using "load in game" - double m_Score; // the player's generic "score" for the matchmaking algorithm - bool m_LoggedIn; // if the player has logged in or not (used with CAdminGame only) - bool m_Spoofed; // if the player has spoof checked or not - bool m_Reserved; // if the player is reserved (VIP) or not - bool m_WhoisShouldBeSent; // if a battle.net /whois should be sent for this player or not - bool m_WhoisSent; // if we've sent a battle.net /whois for this player yet (for spoof checking) - bool m_DownloadAllowed; // if we're allowed to download the map or not (used with permission based map downloads) - bool m_DownloadStarted; // if we've started downloading the map or not - bool m_DownloadFinished; // if we've finished downloading the map or not - bool m_FinishedLoading; // if the player has finished loading or not - bool m_Lagging; // if the player is lagging or not (on the lag screen) - bool m_DropVote; // if the player voted to drop the laggers or not (on the lag screen) - bool m_KickVote; // if the player voted to kick a player or not - bool m_Muted; // if the player is muted or not - bool m_LeftMessageSent; // if the playerleave message has been sent or not - bool m_GProxy; // if the player is using GProxy++ - bool m_GProxyDisconnectNoticeSent; // if a disconnection notice has been sent or not when using GProxy++ - queue m_GProxyBuffer; - uint32_t m_GProxyReconnectKey; - uint32_t m_LastGProxyAckTime; - -public: - CGamePlayer( CGameProtocol *nProtocol, CBaseGame *nGame, CTCPSocket *nSocket, unsigned char nPID, string nJoinedRealm, string nName, BYTEARRAY nInternalIP, bool nReserved ); - CGamePlayer( CPotentialPlayer *potential, unsigned char nPID, string nJoinedRealm, string nName, BYTEARRAY nInternalIP, bool nReserved ); - virtual ~CGamePlayer( ); - - unsigned char GetPID( ) { return m_PID; } - string GetName( ) { return m_Name; } - BYTEARRAY GetInternalIP( ) { return m_InternalIP; } - unsigned int GetNumPings( ) { return m_Pings.size( ); } - unsigned int GetNumCheckSums( ) { return m_CheckSums.size( ); } - queue *GetCheckSums( ) { return &m_CheckSums; } - string GetLeftReason( ) { return m_LeftReason; } - string GetSpoofedRealm( ) { return m_SpoofedRealm; } - string GetJoinedRealm( ) { return m_JoinedRealm; } - uint32_t GetLeftCode( ) { return m_LeftCode; } - uint32_t GetLoginAttempts( ) { return m_LoginAttempts; } - uint32_t GetSyncCounter( ) { return m_SyncCounter; } - uint32_t GetJoinTime( ) { return m_JoinTime; } - uint32_t GetLastMapPartSent( ) { return m_LastMapPartSent; } - uint32_t GetLastMapPartAcked( ) { return m_LastMapPartAcked; } - uint32_t GetStartedDownloadingTicks( ) { return m_StartedDownloadingTicks; } - uint32_t GetFinishedDownloadingTime( ) { return m_FinishedDownloadingTime; } - uint32_t GetFinishedLoadingTicks( ) { return m_FinishedLoadingTicks; } - uint32_t GetStartedLaggingTicks( ) { return m_StartedLaggingTicks; } - uint32_t GetStatsSentTime( ) { return m_StatsSentTime; } - uint32_t GetStatsDotASentTime( ) { return m_StatsDotASentTime; } - uint32_t GetLastGProxyWaitNoticeSentTime( ) { return m_LastGProxyWaitNoticeSentTime; } - queue *GetLoadInGameData( ) { return &m_LoadInGameData; } - double GetScore( ) { return m_Score; } - bool GetLoggedIn( ) { return m_LoggedIn; } - bool GetSpoofed( ) { return m_Spoofed; } - bool GetReserved( ) { return m_Reserved; } - bool GetWhoisShouldBeSent( ) { return m_WhoisShouldBeSent; } - bool GetWhoisSent( ) { return m_WhoisSent; } - bool GetDownloadAllowed( ) { return m_DownloadAllowed; } - bool GetDownloadStarted( ) { return m_DownloadStarted; } - bool GetDownloadFinished( ) { return m_DownloadFinished; } - bool GetFinishedLoading( ) { return m_FinishedLoading; } - bool GetLagging( ) { return m_Lagging; } - bool GetDropVote( ) { return m_DropVote; } - bool GetKickVote( ) { return m_KickVote; } - bool GetMuted( ) { return m_Muted; } - bool GetLeftMessageSent( ) { return m_LeftMessageSent; } - bool GetGProxy( ) { return m_GProxy; } - bool GetGProxyDisconnectNoticeSent( ) { return m_GProxyDisconnectNoticeSent; } - uint32_t GetGProxyReconnectKey( ) { return m_GProxyReconnectKey; } - - void SetLeftReason( string nLeftReason ) { m_LeftReason = nLeftReason; } - void SetSpoofedRealm( string nSpoofedRealm ) { m_SpoofedRealm = nSpoofedRealm; } - void SetLeftCode( uint32_t nLeftCode ) { m_LeftCode = nLeftCode; } - void SetLoginAttempts( uint32_t nLoginAttempts ) { m_LoginAttempts = nLoginAttempts; } - void SetSyncCounter( uint32_t nSyncCounter ) { m_SyncCounter = nSyncCounter; } - void SetLastMapPartSent( uint32_t nLastMapPartSent ) { m_LastMapPartSent = nLastMapPartSent; } - void SetLastMapPartAcked( uint32_t nLastMapPartAcked ) { m_LastMapPartAcked = nLastMapPartAcked; } - void SetStartedDownloadingTicks( uint32_t nStartedDownloadingTicks ) { m_StartedDownloadingTicks = nStartedDownloadingTicks; } - void SetFinishedDownloadingTime( uint32_t nFinishedDownloadingTime ) { m_FinishedDownloadingTime = nFinishedDownloadingTime; } - void SetStartedLaggingTicks( uint32_t nStartedLaggingTicks ) { m_StartedLaggingTicks = nStartedLaggingTicks; } - void SetStatsSentTime( uint32_t nStatsSentTime ) { m_StatsSentTime = nStatsSentTime; } - void SetStatsDotASentTime( uint32_t nStatsDotASentTime ) { m_StatsDotASentTime = nStatsDotASentTime; } - void SetLastGProxyWaitNoticeSentTime( uint32_t nLastGProxyWaitNoticeSentTime ) { m_LastGProxyWaitNoticeSentTime = nLastGProxyWaitNoticeSentTime; } - void SetScore( double nScore ) { m_Score = nScore; } - void SetLoggedIn( bool nLoggedIn ) { m_LoggedIn = nLoggedIn; } - void SetSpoofed( bool nSpoofed ) { m_Spoofed = nSpoofed; } - void SetReserved( bool nReserved ) { m_Reserved = nReserved; } - void SetWhoisShouldBeSent( bool nWhoisShouldBeSent ) { m_WhoisShouldBeSent = nWhoisShouldBeSent; } - void SetDownloadAllowed( bool nDownloadAllowed ) { m_DownloadAllowed = nDownloadAllowed; } - void SetDownloadStarted( bool nDownloadStarted ) { m_DownloadStarted = nDownloadStarted; } - void SetDownloadFinished( bool nDownloadFinished ) { m_DownloadFinished = nDownloadFinished; } - void SetLagging( bool nLagging ) { m_Lagging = nLagging; } - void SetDropVote( bool nDropVote ) { m_DropVote = nDropVote; } - void SetKickVote( bool nKickVote ) { m_KickVote = nKickVote; } - void SetMuted( bool nMuted ) { m_Muted = nMuted; } - void SetLeftMessageSent( bool nLeftMessageSent ) { m_LeftMessageSent = nLeftMessageSent; } - void SetGProxyDisconnectNoticeSent( bool nGProxyDisconnectNoticeSent ) { m_GProxyDisconnectNoticeSent = nGProxyDisconnectNoticeSent; } - - string GetNameTerminated( ); - uint32_t GetPing( bool LCPing ); - - void AddLoadInGameData( BYTEARRAY nLoadInGameData ) { m_LoadInGameData.push( nLoadInGameData ); } - - // processing functions - - virtual bool Update( void *fd ); - virtual void ExtractPackets( ); - virtual void ProcessPackets( ); - - // other functions - - virtual void Send( BYTEARRAY data ); - virtual void EventGProxyReconnect( CTCPSocket *NewSocket, uint32_t LastPacket ); -}; - -#endif diff --git a/ghost/gameprotocol.cpp b/ghost/gameprotocol.cpp deleted file mode 100644 index 5f505f2..0000000 --- a/ghost/gameprotocol.cpp +++ /dev/null @@ -1,1050 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "crc32.h" -#include "gameplayer.h" -#include "gameprotocol.h" -#include "game_base.h" - -// -// CGameProtocol -// - -CGameProtocol :: CGameProtocol( CGHost *nGHost ) -{ - m_GHost = nGHost; -} - -CGameProtocol :: ~CGameProtocol( ) -{ - -} - -/////////////////////// -// RECEIVE FUNCTIONS // -/////////////////////// - -CIncomingJoinPlayer *CGameProtocol :: RECEIVE_W3GS_REQJOIN( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_REQJOIN" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Host Counter (Game ID) - // 4 bytes -> Entry Key (used in LAN) - // 1 byte -> ??? - // 2 bytes -> Listen Port - // 4 bytes -> Peer Key - // null terminated string -> Name - // 4 bytes -> ??? - // 2 bytes -> InternalPort (???) - // 4 bytes -> InternalIP - - if( ValidateLength( data ) && data.size( ) >= 20 ) - { - uint32_t HostCounter = UTIL_ByteArrayToUInt32( data, false, 4 ); - BYTEARRAY Name = UTIL_ExtractCString( data, 19 ); - - if( !Name.empty( ) && data.size( ) >= Name.size( ) + 30 ) - { - BYTEARRAY InternalIP = BYTEARRAY( data.begin( ) + Name.size( ) + 26, data.begin( ) + Name.size( ) + 30 ); - return new CIncomingJoinPlayer( HostCounter, string( Name.begin( ), Name.end( ) ), InternalIP ); - } - } - - return NULL; -} - -uint32_t CGameProtocol :: RECEIVE_W3GS_LEAVEGAME( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_LEAVEGAME" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Reason - - if( ValidateLength( data ) && data.size( ) >= 8 ) - return UTIL_ByteArrayToUInt32( data, false, 4 ); - - return 0; -} - -bool CGameProtocol :: RECEIVE_W3GS_GAMELOADED_SELF( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_GAMELOADED_SELF" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - - if( ValidateLength( data ) ) - return true; - - return false; -} - -CIncomingAction *CGameProtocol :: RECEIVE_W3GS_OUTGOING_ACTION( BYTEARRAY data, unsigned char PID ) -{ - // DEBUG_Print( "RECEIVED W3GS_OUTGOING_ACTION" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> CRC - // remainder of packet -> Action - - if( PID != 255 && ValidateLength( data ) && data.size( ) >= 8 ) - { - BYTEARRAY CRC = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); - BYTEARRAY Action = BYTEARRAY( data.begin( ) + 8, data.end( ) ); - return new CIncomingAction( PID, CRC, Action ); - } - - return NULL; -} - -uint32_t CGameProtocol :: RECEIVE_W3GS_OUTGOING_KEEPALIVE( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_OUTGOING_KEEPALIVE" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 1 byte -> ??? - // 4 bytes -> CheckSum??? (used in replays) - - if( ValidateLength( data ) && data.size( ) == 9 ) - return UTIL_ByteArrayToUInt32( data, false, 5 ); - - return 0; -} - -CIncomingChatPlayer *CGameProtocol :: RECEIVE_W3GS_CHAT_TO_HOST( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_CHAT_TO_HOST" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 1 byte -> Total - // for( 1 .. Total ) - // 1 byte -> ToPID - // 1 byte -> FromPID - // 1 byte -> Flag - // if( Flag == 16 ) - // null term string -> Message - // elseif( Flag == 17 ) - // 1 byte -> Team - // elseif( Flag == 18 ) - // 1 byte -> Colour - // elseif( Flag == 19 ) - // 1 byte -> Race - // elseif( Flag == 20 ) - // 1 byte -> Handicap - // elseif( Flag == 32 ) - // 4 bytes -> ExtraFlags - // null term string -> Message - - if( ValidateLength( data ) ) - { - unsigned int i = 5; - unsigned char Total = data[4]; - - if( Total > 0 && data.size( ) >= i + Total ) - { - BYTEARRAY ToPIDs = BYTEARRAY( data.begin( ) + i, data.begin( ) + i + Total ); - i += Total; - unsigned char FromPID = data[i]; - unsigned char Flag = data[i + 1]; - i += 2; - - if( Flag == 16 && data.size( ) >= i + 1 ) - { - // chat message - - BYTEARRAY Message = UTIL_ExtractCString( data, i ); - return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, string( Message.begin( ), Message.end( ) ) ); - } - else if( ( Flag >= 17 && Flag <= 20 ) && data.size( ) >= i + 1 ) - { - // team/colour/race/handicap change request - - unsigned char Byte = data[i]; - return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, Byte ); - } - else if( Flag == 32 && data.size( ) >= i + 5 ) - { - // chat message with extra flags - - BYTEARRAY ExtraFlags = BYTEARRAY( data.begin( ) + i, data.begin( ) + i + 4 ); - BYTEARRAY Message = UTIL_ExtractCString( data, i + 4 ); - return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, string( Message.begin( ), Message.end( ) ), ExtraFlags ); - } - } - } - - return NULL; -} - -bool CGameProtocol :: RECEIVE_W3GS_SEARCHGAME( BYTEARRAY data, unsigned char war3Version ) -{ - uint32_t ProductID = 1462982736; // "W3XP" - uint32_t Version = war3Version; - - // DEBUG_Print( "RECEIVED W3GS_SEARCHGAME" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> ProductID - // 4 bytes -> Version - // 4 bytes -> ??? (Zero) - - if( ValidateLength( data ) && data.size( ) >= 16 ) - { - if( UTIL_ByteArrayToUInt32( data, false, 4 ) == ProductID ) - { - if( UTIL_ByteArrayToUInt32( data, false, 8 ) == Version ) - { - if( UTIL_ByteArrayToUInt32( data, false, 12 ) == 0 ) - return true; - } - } - } - - return false; -} - -CIncomingMapSize *CGameProtocol :: RECEIVE_W3GS_MAPSIZE( BYTEARRAY data, BYTEARRAY mapSize ) -{ - // DEBUG_Print( "RECEIVED W3GS_MAPSIZE" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> ??? - // 1 byte -> SizeFlag (1 = have map, 3 = continue download) - // 4 bytes -> MapSize - - if( ValidateLength( data ) && data.size( ) >= 13 ) - return new CIncomingMapSize( data[8], UTIL_ByteArrayToUInt32( data, false, 9 ) ); - - return NULL; -} - -uint32_t CGameProtocol :: RECEIVE_W3GS_MAPPARTOK( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_MAPPARTOK" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 1 byte -> SenderPID - // 1 byte -> ReceiverPID - // 4 bytes -> ??? - // 4 bytes -> MapSize - - if( ValidateLength( data ) && data.size( ) >= 14 ) - return UTIL_ByteArrayToUInt32( data, false, 10 ); - - return 0; -} - -uint32_t CGameProtocol :: RECEIVE_W3GS_PONG_TO_HOST( BYTEARRAY data ) -{ - // DEBUG_Print( "RECEIVED W3GS_PONG_TO_HOST" ); - // DEBUG_Print( data ); - - // 2 bytes -> Header - // 2 bytes -> Length - // 4 bytes -> Pong - - // the pong value is just a copy of whatever was sent in SEND_W3GS_PING_FROM_HOST which was GetTicks( ) at the time of sending - // so as long as we trust that the client isn't trying to fake us out and mess with the pong value we can find the round trip time by simple subtraction - // (the subtraction is done elsewhere because the very first pong value seems to be 1 and we want to discard that one) - - if( ValidateLength( data ) && data.size( ) >= 8 ) - return UTIL_ByteArrayToUInt32( data, false, 4 ); - - return 1; -} - -//////////////////// -// SEND FUNCTIONS // -//////////////////// - -BYTEARRAY CGameProtocol :: SEND_W3GS_PING_FROM_HOST( ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_PING_FROM_HOST ); // W3GS_PING_FROM_HOST - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, GetTicks( ), false ); // ping value - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_PING_FROM_HOST" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_SLOTINFOJOIN( unsigned char PID, BYTEARRAY port, BYTEARRAY externalIP, vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) -{ - unsigned char Zeros[] = { 0, 0, 0, 0 }; - - BYTEARRAY SlotInfo = EncodeSlotInfo( slots, randomSeed, layoutStyle, playerSlots ); - BYTEARRAY packet; - - if( port.size( ) == 2 && externalIP.size( ) == 4 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_SLOTINFOJOIN ); // W3GS_SLOTINFOJOIN - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, (uint16_t)SlotInfo.size( ), false ); // SlotInfo length - UTIL_AppendByteArrayFast( packet, SlotInfo ); // SlotInfo - packet.push_back( PID ); // PID - packet.push_back( 2 ); // AF_INET - packet.push_back( 0 ); // AF_INET continued... - UTIL_AppendByteArray( packet, port ); // port - UTIL_AppendByteArrayFast( packet, externalIP ); // external IP - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_SLOTINFOJOIN" ); - - // DEBUG_Print( "SENT W3GS_SLOTINFOJOIN" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_REJECTJOIN( uint32_t reason ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_REJECTJOIN ); // W3GS_REJECTJOIN - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, reason, false ); // reason - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_REJECTJOIN" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_PLAYERINFO( unsigned char PID, string name, BYTEARRAY externalIP, BYTEARRAY internalIP ) -{ - unsigned char PlayerJoinCounter[] = { 2, 0, 0, 0 }; - unsigned char Zeros[] = { 0, 0, 0, 0 }; - - BYTEARRAY packet; - - if( !name.empty( ) && name.size( ) <= 15 && externalIP.size( ) == 4 && internalIP.size( ) == 4 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_PLAYERINFO ); // W3GS_PLAYERINFO - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, PlayerJoinCounter, 4 ); // player join counter - packet.push_back( PID ); // PID - UTIL_AppendByteArrayFast( packet, name ); // player name - packet.push_back( 1 ); // ??? - packet.push_back( 0 ); // ??? - packet.push_back( 2 ); // AF_INET - packet.push_back( 0 ); // AF_INET continued... - packet.push_back( 0 ); // port - packet.push_back( 0 ); // port continued... - UTIL_AppendByteArrayFast( packet, externalIP ); // external IP - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - packet.push_back( 2 ); // AF_INET - packet.push_back( 0 ); // AF_INET continued... - packet.push_back( 0 ); // port - packet.push_back( 0 ); // port continued... - UTIL_AppendByteArrayFast( packet, internalIP ); // internal IP - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - UTIL_AppendByteArray( packet, Zeros, 4 ); // ??? - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_PLAYERINFO" ); - - // DEBUG_Print( "SENT W3GS_PLAYERINFO" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_PLAYERLEAVE_OTHERS( unsigned char PID, uint32_t leftCode ) -{ - BYTEARRAY packet; - - if( PID != 255 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_PLAYERLEAVE_OTHERS ); // W3GS_PLAYERLEAVE_OTHERS - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( PID ); // PID - UTIL_AppendByteArray( packet, leftCode, false ); // left code (see PLAYERLEAVE_ constants in gameprotocol.h) - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_PLAYERLEAVE_OTHERS" ); - - // DEBUG_Print( "SENT W3GS_PLAYERLEAVE_OTHERS" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_GAMELOADED_OTHERS( unsigned char PID ) -{ - BYTEARRAY packet; - - if( PID != 255 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_GAMELOADED_OTHERS ); // W3GS_GAMELOADED_OTHERS - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( PID ); // PID - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMELOADED_OTHERS" ); - - // DEBUG_Print( "SENT W3GS_GAMELOADED_OTHERS" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_SLOTINFO( vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) -{ - BYTEARRAY SlotInfo = EncodeSlotInfo( slots, randomSeed, layoutStyle, playerSlots ); - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_SLOTINFO ); // W3GS_SLOTINFO - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, (uint16_t)SlotInfo.size( ), false ); // SlotInfo length - UTIL_AppendByteArrayFast( packet, SlotInfo ); // SlotInfo - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_SLOTINFO" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_COUNTDOWN_START( ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_COUNTDOWN_START ); // W3GS_COUNTDOWN_START - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_COUNTDOWN_START" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_COUNTDOWN_END( ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_COUNTDOWN_END ); // W3GS_COUNTDOWN_END - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_COUNTDOWN_END" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_INCOMING_ACTION( queue actions, uint16_t sendInterval ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_INCOMING_ACTION ); // W3GS_INCOMING_ACTION - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, sendInterval, false ); // send interval - - // create subpacket - - if( !actions.empty( ) ) - { - BYTEARRAY subpacket; - - while( !actions.empty( ) ) - { - CIncomingAction *Action = actions.front( ); - actions.pop( ); - subpacket.push_back( Action->GetPID( ) ); - UTIL_AppendByteArray( subpacket, (uint16_t)Action->GetAction( )->size( ), false ); - UTIL_AppendByteArrayFast( subpacket, *Action->GetAction( ) ); - } - - // calculate crc (we only care about the first 2 bytes though) - - BYTEARRAY crc32 = UTIL_CreateByteArray( m_GHost->m_CRC->FullCRC( (unsigned char *)string( subpacket.begin( ), subpacket.end( ) ).c_str( ), subpacket.size( ) ), false ); - crc32.resize( 2 ); - - // finish subpacket - - UTIL_AppendByteArrayFast( packet, crc32 ); // crc - UTIL_AppendByteArrayFast( packet, subpacket ); // subpacket - } - - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_INCOMING_ACTION" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_CHAT_FROM_HOST( unsigned char fromPID, BYTEARRAY toPIDs, unsigned char flag, BYTEARRAY flagExtra, string message ) -{ - BYTEARRAY packet; - - if( !toPIDs.empty( ) && !message.empty( ) && message.size( ) < 255 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_CHAT_FROM_HOST ); // W3GS_CHAT_FROM_HOST - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( toPIDs.size( ) ); // number of receivers - UTIL_AppendByteArrayFast( packet, toPIDs ); // receivers - packet.push_back( fromPID ); // sender - packet.push_back( flag ); // flag - UTIL_AppendByteArrayFast( packet, flagExtra ); // extra flag - UTIL_AppendByteArrayFast( packet, message ); // message - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_CHAT_FROM_HOST" ); - - // DEBUG_Print( "SENT W3GS_CHAT_FROM_HOST" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_START_LAG( vector players, bool loadInGame ) -{ - BYTEARRAY packet; - - unsigned char NumLaggers = 0; - - for( vector :: iterator i = players.begin( ); i != players.end( ); i++ ) - { - if( loadInGame ) - { - if( !(*i)->GetFinishedLoading( ) ) - NumLaggers++; - } - else - { - if( (*i)->GetLagging( ) ) - NumLaggers++; - } - } - - if( NumLaggers > 0 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_START_LAG ); // W3GS_START_LAG - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( NumLaggers ); - - for( vector :: iterator i = players.begin( ); i != players.end( ); i++ ) - { - if( loadInGame ) - { - if( !(*i)->GetFinishedLoading( ) ) - { - packet.push_back( (*i)->GetPID( ) ); - UTIL_AppendByteArray( packet, (uint32_t)0, false ); - } - } - else - { - if( (*i)->GetLagging( ) ) - { - packet.push_back( (*i)->GetPID( ) ); - UTIL_AppendByteArray( packet, GetTicks( ) - (*i)->GetStartedLaggingTicks( ), false ); - } - } - } - - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] no laggers passed to SEND_W3GS_START_LAG" ); - - // DEBUG_Print( "SENT W3GS_START_LAG" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_STOP_LAG( CGamePlayer *player, bool loadInGame ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_STOP_LAG ); // W3GS_STOP_LAG - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( player->GetPID( ) ); - - if( loadInGame ) - UTIL_AppendByteArray( packet, (uint32_t)0, false ); - else - UTIL_AppendByteArray( packet, GetTicks( ) - player->GetStartedLaggingTicks( ), false ); - - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_STOP_LAG" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_SEARCHGAME( bool TFT, unsigned char war3Version ) -{ - unsigned char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" - unsigned char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" - unsigned char Version[] = { war3Version, 0, 0, 0 }; - unsigned char Unknown[] = { 0, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_SEARCHGAME ); // W3GS_SEARCHGAME - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - - if( TFT ) - UTIL_AppendByteArray( packet, ProductID_TFT, 4 ); // Product ID (TFT) - else - UTIL_AppendByteArray( packet, ProductID_ROC, 4 ); // Product ID (ROC) - - UTIL_AppendByteArray( packet, Version, 4 ); // Version - UTIL_AppendByteArray( packet, Unknown, 4 ); // ??? - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_SEARCHGAME" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_GAMEINFO( bool TFT, unsigned char war3Version, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter ) -{ - unsigned char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" - unsigned char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" - unsigned char Version[] = { war3Version, 0, 0, 0 }; - unsigned char Unknown1[] = { 1, 2, 3, 4 }; - unsigned char Unknown2[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - - if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && !gameName.empty( ) && !hostName.empty( ) && !mapPath.empty( ) && mapCRC.size( ) == 4 ) - { - // make the stat string - - BYTEARRAY StatString; - UTIL_AppendByteArrayFast( StatString, mapFlags ); - StatString.push_back( 0 ); - UTIL_AppendByteArrayFast( StatString, mapWidth ); - UTIL_AppendByteArrayFast( StatString, mapHeight ); - UTIL_AppendByteArrayFast( StatString, mapCRC ); - UTIL_AppendByteArrayFast( StatString, mapPath ); - UTIL_AppendByteArrayFast( StatString, hostName ); - StatString.push_back( 0 ); - StatString = UTIL_EncodeStatString( StatString ); - - // make the rest of the packet - - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_GAMEINFO ); // W3GS_GAMEINFO - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - - if( TFT ) - UTIL_AppendByteArray( packet, ProductID_TFT, 4 ); // Product ID (TFT) - else - UTIL_AppendByteArray( packet, ProductID_ROC, 4 ); // Product ID (ROC) - - UTIL_AppendByteArray( packet, Version, 4 ); // Version - UTIL_AppendByteArray( packet, hostCounter, false ); // Host Counter - UTIL_AppendByteArray( packet, Unknown1, 4 ); // ??? (this varies wildly even between two identical games created one after another) - UTIL_AppendByteArrayFast( packet, gameName ); // Game Name - packet.push_back( 0 ); // ??? (maybe game password) - UTIL_AppendByteArrayFast( packet, StatString ); // Stat String - packet.push_back( 0 ); // Stat String null terminator (the stat string is encoded to remove all even numbers i.e. zeros) - UTIL_AppendByteArray( packet, slotsTotal, false ); // Slots Total - UTIL_AppendByteArrayFast( packet, mapGameType ); // Game Type - UTIL_AppendByteArray( packet, Unknown2, 4 ); // ??? - UTIL_AppendByteArray( packet, slotsOpen, false ); // Slots Open - UTIL_AppendByteArray( packet, upTime, false ); // time since creation - UTIL_AppendByteArray( packet, port, false ); // port - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO" ); - - // DEBUG_Print( "SENT W3GS_GAMEINFO" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_CREATEGAME( bool TFT, unsigned char war3Version ) -{ - unsigned char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" - unsigned char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" - unsigned char Version[] = { war3Version, 0, 0, 0 }; - unsigned char HostCounter[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_CREATEGAME ); // W3GS_CREATEGAME - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - - if( TFT ) - UTIL_AppendByteArray( packet, ProductID_TFT, 4 ); // Product ID (TFT) - else - UTIL_AppendByteArray( packet, ProductID_ROC, 4 ); // Product ID (ROC) - - UTIL_AppendByteArray( packet, Version, 4 ); // Version - UTIL_AppendByteArray( packet, HostCounter, 4 ); // Host Counter - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_CREATEGAME" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_REFRESHGAME( uint32_t players, uint32_t playerSlots ) -{ - unsigned char HostCounter[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_REFRESHGAME ); // W3GS_REFRESHGAME - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, HostCounter, 4 ); // Host Counter - UTIL_AppendByteArray( packet, players, false ); // Players - UTIL_AppendByteArray( packet, playerSlots, false ); // Player Slots - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_REFRESHGAME" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_DECREATEGAME( ) -{ - unsigned char HostCounter[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_DECREATEGAME ); // W3GS_DECREATEGAME - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, HostCounter, 4 ); // Host Counter - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_DECREATEGAME" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_MAPCHECK( string mapPath, BYTEARRAY mapSize, BYTEARRAY mapInfo, BYTEARRAY mapCRC, BYTEARRAY mapSHA1 ) -{ - unsigned char Unknown[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - - if( !mapPath.empty( ) && mapSize.size( ) == 4 && mapInfo.size( ) == 4 && mapCRC.size( ) == 4 && mapSHA1.size( ) == 20 ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_MAPCHECK ); // W3GS_MAPCHECK - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, Unknown, 4 ); // ??? - UTIL_AppendByteArrayFast( packet, mapPath ); // map path - UTIL_AppendByteArrayFast( packet, mapSize ); // map size - UTIL_AppendByteArrayFast( packet, mapInfo ); // map info - UTIL_AppendByteArrayFast( packet, mapCRC ); // map crc - UTIL_AppendByteArrayFast( packet, mapSHA1 ); // map sha1 - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_MAPCHECK" ); - - // DEBUG_Print( "SENT W3GS_MAPCHECK" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_STARTDOWNLOAD( unsigned char fromPID ) -{ - unsigned char Unknown[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_STARTDOWNLOAD ); // W3GS_STARTDOWNLOAD - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - UTIL_AppendByteArray( packet, Unknown, 4 ); // ??? - packet.push_back( fromPID ); // from PID - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_STARTDOWNLOAD" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_MAPPART( unsigned char fromPID, unsigned char toPID, uint32_t start, string *mapData ) -{ - unsigned char Unknown[] = { 1, 0, 0, 0 }; - - BYTEARRAY packet; - - if( start < mapData->size( ) ) - { - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_MAPPART ); // W3GS_MAPPART - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( toPID ); // to PID - packet.push_back( fromPID ); // from PID - UTIL_AppendByteArray( packet, Unknown, 4 ); // ??? - UTIL_AppendByteArray( packet, start, false ); // start position - - // calculate end position (don't send more than 1442 map bytes in one packet) - - uint32_t End = start + 1442; - - if( End > mapData->size( ) ) - End = mapData->size( ); - - // calculate crc - - BYTEARRAY crc32 = UTIL_CreateByteArray( m_GHost->m_CRC->FullCRC( (unsigned char *)mapData->c_str( ) + start, End - start ), false ); - UTIL_AppendByteArrayFast( packet, crc32 ); - - // map data - - BYTEARRAY Data = UTIL_CreateByteArray( (unsigned char *)mapData->c_str( ) + start, End - start ); - UTIL_AppendByteArrayFast( packet, Data ); - AssignLength( packet ); - } - else - CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_MAPPART" ); - - // DEBUG_Print( "SENT W3GS_MAPPART" ); - // DEBUG_Print( packet ); - return packet; -} - -BYTEARRAY CGameProtocol :: SEND_W3GS_INCOMING_ACTION2( queue actions ) -{ - BYTEARRAY packet; - packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant - packet.push_back( W3GS_INCOMING_ACTION2 ); // W3GS_INCOMING_ACTION2 - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // packet length will be assigned later - packet.push_back( 0 ); // ??? (send interval?) - packet.push_back( 0 ); // ??? (send interval?) - - // create subpacket - - if( !actions.empty( ) ) - { - BYTEARRAY subpacket; - - while( !actions.empty( ) ) - { - CIncomingAction *Action = actions.front( ); - actions.pop( ); - subpacket.push_back( Action->GetPID( ) ); - UTIL_AppendByteArray( subpacket, (uint16_t)Action->GetAction( )->size( ), false ); - UTIL_AppendByteArrayFast( subpacket, *Action->GetAction( ) ); - } - - // calculate crc (we only care about the first 2 bytes though) - - BYTEARRAY crc32 = UTIL_CreateByteArray( m_GHost->m_CRC->FullCRC( (unsigned char *)string( subpacket.begin( ), subpacket.end( ) ).c_str( ), subpacket.size( ) ), false ); - crc32.resize( 2 ); - - // finish subpacket - - UTIL_AppendByteArrayFast( packet, crc32 ); // crc - UTIL_AppendByteArrayFast( packet, subpacket ); // subpacket - } - - AssignLength( packet ); - // DEBUG_Print( "SENT W3GS_INCOMING_ACTION2" ); - // DEBUG_Print( packet ); - return packet; -} - -///////////////////// -// OTHER FUNCTIONS // -///////////////////// - -bool CGameProtocol :: AssignLength( BYTEARRAY &content ) -{ - // insert the actual length of the content array into bytes 3 and 4 (indices 2 and 3) - - BYTEARRAY LengthBytes; - - if( content.size( ) >= 4 && content.size( ) <= 65535 ) - { - LengthBytes = UTIL_CreateByteArray( (uint16_t)content.size( ), false ); - content[2] = LengthBytes[0]; - content[3] = LengthBytes[1]; - return true; - } - - return false; -} - -bool CGameProtocol :: ValidateLength( BYTEARRAY &content ) -{ - // verify that bytes 3 and 4 (indices 2 and 3) of the content array describe the length - - uint16_t Length; - BYTEARRAY LengthBytes; - - if( content.size( ) >= 4 && content.size( ) <= 65535 ) - { - LengthBytes.push_back( content[2] ); - LengthBytes.push_back( content[3] ); - Length = UTIL_ByteArrayToUInt16( LengthBytes, false ); - - if( Length == content.size( ) ) - return true; - } - - return false; -} - -BYTEARRAY CGameProtocol :: EncodeSlotInfo( vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) -{ - BYTEARRAY SlotInfo; - SlotInfo.push_back( (unsigned char)slots.size( ) ); // number of slots - - for( unsigned int i = 0; i < slots.size( ); i++ ) - UTIL_AppendByteArray( SlotInfo, slots[i].GetByteArray( ) ); - - UTIL_AppendByteArray( SlotInfo, randomSeed, false ); // random seed - SlotInfo.push_back( layoutStyle ); // LayoutStyle (0 = melee, 1 = custom forces, 3 = custom forces + fixed player settings) - SlotInfo.push_back( playerSlots ); // number of player slots (non observer) - return SlotInfo; -} - -// -// CIncomingJoinPlayer -// - -CIncomingJoinPlayer :: CIncomingJoinPlayer( uint32_t nHostCounter, string nName, BYTEARRAY &nInternalIP ) -{ - m_HostCounter = nHostCounter; - m_Name = nName; - m_InternalIP = nInternalIP; -} - -CIncomingJoinPlayer :: ~CIncomingJoinPlayer( ) -{ - -} - -// -// CIncomingAction -// - -CIncomingAction :: CIncomingAction( unsigned char nPID, BYTEARRAY &nCRC, BYTEARRAY &nAction ) -{ - m_PID = nPID; - m_CRC = nCRC; - m_Action = nAction; -} - -CIncomingAction :: ~CIncomingAction( ) -{ - -} - -// -// CIncomingChatPlayer -// - -CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, string nMessage ) -{ - m_Type = CTH_MESSAGE; - m_FromPID = nFromPID; - m_ToPIDs = nToPIDs; - m_Flag = nFlag; - m_Message = nMessage; -} - -CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, string nMessage, BYTEARRAY &nExtraFlags ) -{ - m_Type = CTH_MESSAGEEXTRA; - m_FromPID = nFromPID; - m_ToPIDs = nToPIDs; - m_Flag = nFlag; - m_Message = nMessage; - m_ExtraFlags = nExtraFlags; -} - -CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, unsigned char nByte ) -{ - if( nFlag == 17 ) - m_Type = CTH_TEAMCHANGE; - else if( nFlag == 18 ) - m_Type = CTH_COLOURCHANGE; - else if( nFlag == 19 ) - m_Type = CTH_RACECHANGE; - else if( nFlag == 20 ) - m_Type = CTH_HANDICAPCHANGE; - - m_FromPID = nFromPID; - m_ToPIDs = nToPIDs; - m_Flag = nFlag; - m_Byte = nByte; -} - -CIncomingChatPlayer :: ~CIncomingChatPlayer( ) -{ - -} - -// -// CIncomingMapSize -// - -CIncomingMapSize :: CIncomingMapSize( unsigned char nSizeFlag, uint32_t nMapSize ) -{ - m_SizeFlag = nSizeFlag; - m_MapSize = nMapSize; -} - -CIncomingMapSize :: ~CIncomingMapSize( ) -{ - -} diff --git a/ghost/gameprotocol.h b/ghost/gameprotocol.h deleted file mode 100644 index 93ce2cd..0000000 --- a/ghost/gameprotocol.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GAMEPROTOCOL_H -#define GAMEPROTOCOL_H - -// -// CGameProtocol -// - -#define W3GS_HEADER_CONSTANT 247 - -#define GAME_NONE 0 // this case isn't part of the protocol, it's for internal use only -#define GAME_FULL 2 -#define GAME_PUBLIC 16 -#define GAME_PRIVATE 17 - -#define GAMETYPE_CUSTOM 1 -#define GAMETYPE_BLIZZARD 9 - -#define PLAYERLEAVE_DISCONNECT 1 -#define PLAYERLEAVE_LOST 7 -#define PLAYERLEAVE_LOSTBUILDINGS 8 -#define PLAYERLEAVE_WON 9 -#define PLAYERLEAVE_DRAW 10 -#define PLAYERLEAVE_OBSERVER 11 -#define PLAYERLEAVE_LOBBY 13 -#define PLAYERLEAVE_GPROXY 100 - -#define REJECTJOIN_FULL 9 -#define REJECTJOIN_STARTED 10 -#define REJECTJOIN_WRONGPASSWORD 27 - -#include "gameslot.h" - -class CGamePlayer; -class CIncomingJoinPlayer; -class CIncomingAction; -class CIncomingChatPlayer; -class CIncomingMapSize; - -class CGameProtocol -{ -public: - CGHost *m_GHost; - - enum Protocol { - W3GS_PING_FROM_HOST = 1, // 0x01 - W3GS_SLOTINFOJOIN = 4, // 0x04 - W3GS_REJECTJOIN = 5, // 0x05 - W3GS_PLAYERINFO = 6, // 0x06 - W3GS_PLAYERLEAVE_OTHERS = 7, // 0x07 - W3GS_GAMELOADED_OTHERS = 8, // 0x08 - W3GS_SLOTINFO = 9, // 0x09 - W3GS_COUNTDOWN_START = 10, // 0x0A - W3GS_COUNTDOWN_END = 11, // 0x0B - W3GS_INCOMING_ACTION = 12, // 0x0C - W3GS_CHAT_FROM_HOST = 15, // 0x0F - W3GS_START_LAG = 16, // 0x10 - W3GS_STOP_LAG = 17, // 0x11 - W3GS_HOST_KICK_PLAYER = 28, // 0x1C - W3GS_REQJOIN = 30, // 0x1E - W3GS_LEAVEGAME = 33, // 0x21 - W3GS_GAMELOADED_SELF = 35, // 0x23 - W3GS_OUTGOING_ACTION = 38, // 0x26 - W3GS_OUTGOING_KEEPALIVE = 39, // 0x27 - W3GS_CHAT_TO_HOST = 40, // 0x28 - W3GS_DROPREQ = 41, // 0x29 - W3GS_SEARCHGAME = 47, // 0x2F (UDP/LAN) - W3GS_GAMEINFO = 48, // 0x30 (UDP/LAN) - W3GS_CREATEGAME = 49, // 0x31 (UDP/LAN) - W3GS_REFRESHGAME = 50, // 0x32 (UDP/LAN) - W3GS_DECREATEGAME = 51, // 0x33 (UDP/LAN) - W3GS_CHAT_OTHERS = 52, // 0x34 - W3GS_PING_FROM_OTHERS = 53, // 0x35 - W3GS_PONG_TO_OTHERS = 54, // 0x36 - W3GS_MAPCHECK = 61, // 0x3D - W3GS_STARTDOWNLOAD = 63, // 0x3F - W3GS_MAPSIZE = 66, // 0x42 - W3GS_MAPPART = 67, // 0x43 - W3GS_MAPPARTOK = 68, // 0x44 - W3GS_MAPPARTNOTOK = 69, // 0x45 - just a guess, received this packet after forgetting to send a crc in W3GS_MAPPART (f7 45 0a 00 01 02 01 00 00 00) - W3GS_PONG_TO_HOST = 70, // 0x46 - W3GS_INCOMING_ACTION2 = 72 // 0x48 - received this packet when there are too many actions to fit in W3GS_INCOMING_ACTION - }; - - CGameProtocol( CGHost *nGHost ); - ~CGameProtocol( ); - - // receive functions - - CIncomingJoinPlayer *RECEIVE_W3GS_REQJOIN( BYTEARRAY data ); - uint32_t RECEIVE_W3GS_LEAVEGAME( BYTEARRAY data ); - bool RECEIVE_W3GS_GAMELOADED_SELF( BYTEARRAY data ); - CIncomingAction *RECEIVE_W3GS_OUTGOING_ACTION( BYTEARRAY data, unsigned char PID ); - uint32_t RECEIVE_W3GS_OUTGOING_KEEPALIVE( BYTEARRAY data ); - CIncomingChatPlayer *RECEIVE_W3GS_CHAT_TO_HOST( BYTEARRAY data ); - bool RECEIVE_W3GS_SEARCHGAME( BYTEARRAY data, unsigned char war3Version ); - CIncomingMapSize *RECEIVE_W3GS_MAPSIZE( BYTEARRAY data, BYTEARRAY mapSize ); - uint32_t RECEIVE_W3GS_MAPPARTOK( BYTEARRAY data ); - uint32_t RECEIVE_W3GS_PONG_TO_HOST( BYTEARRAY data ); - - // send functions - - BYTEARRAY SEND_W3GS_PING_FROM_HOST( ); - BYTEARRAY SEND_W3GS_SLOTINFOJOIN( unsigned char PID, BYTEARRAY port, BYTEARRAY externalIP, vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); - BYTEARRAY SEND_W3GS_REJECTJOIN( uint32_t reason ); - BYTEARRAY SEND_W3GS_PLAYERINFO( unsigned char PID, string name, BYTEARRAY externalIP, BYTEARRAY internalIP ); - BYTEARRAY SEND_W3GS_PLAYERLEAVE_OTHERS( unsigned char PID, uint32_t leftCode ); - BYTEARRAY SEND_W3GS_GAMELOADED_OTHERS( unsigned char PID ); - BYTEARRAY SEND_W3GS_SLOTINFO( vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); - BYTEARRAY SEND_W3GS_COUNTDOWN_START( ); - BYTEARRAY SEND_W3GS_COUNTDOWN_END( ); - BYTEARRAY SEND_W3GS_INCOMING_ACTION( queue actions, uint16_t sendInterval ); - BYTEARRAY SEND_W3GS_CHAT_FROM_HOST( unsigned char fromPID, BYTEARRAY toPIDs, unsigned char flag, BYTEARRAY flagExtra, string message ); - BYTEARRAY SEND_W3GS_START_LAG( vector players, bool loadInGame = false ); - BYTEARRAY SEND_W3GS_STOP_LAG( CGamePlayer *player, bool loadInGame = false ); - BYTEARRAY SEND_W3GS_SEARCHGAME( bool TFT, unsigned char war3Version ); - BYTEARRAY SEND_W3GS_GAMEINFO( bool TFT, unsigned char war3Version, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter ); - BYTEARRAY SEND_W3GS_CREATEGAME( bool TFT, unsigned char war3Version ); - BYTEARRAY SEND_W3GS_REFRESHGAME( uint32_t players, uint32_t playerSlots ); - BYTEARRAY SEND_W3GS_DECREATEGAME( ); - BYTEARRAY SEND_W3GS_MAPCHECK( string mapPath, BYTEARRAY mapSize, BYTEARRAY mapInfo, BYTEARRAY mapCRC, BYTEARRAY mapSHA1 ); - BYTEARRAY SEND_W3GS_STARTDOWNLOAD( unsigned char fromPID ); - BYTEARRAY SEND_W3GS_MAPPART( unsigned char fromPID, unsigned char toPID, uint32_t start, string *mapData ); - BYTEARRAY SEND_W3GS_INCOMING_ACTION2( queue actions ); - - // other functions - -private: - bool AssignLength( BYTEARRAY &content ); - bool ValidateLength( BYTEARRAY &content ); - BYTEARRAY EncodeSlotInfo( vector &slots, uint32_t randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); -}; - -// -// CIncomingJoinPlayer -// - -class CIncomingJoinPlayer -{ -private: - uint32_t m_HostCounter; - string m_Name; - BYTEARRAY m_InternalIP; - -public: - CIncomingJoinPlayer( uint32_t nHostCounter, string nName, BYTEARRAY &nInternalIP ); - ~CIncomingJoinPlayer( ); - - uint32_t GetHostCounter( ) { return m_HostCounter; } - string GetName( ) { return m_Name; } - BYTEARRAY GetInternalIP( ) { return m_InternalIP; } -}; - -// -// CIncomingAction -// - -class CIncomingAction -{ -private: - unsigned char m_PID; - BYTEARRAY m_CRC; - BYTEARRAY m_Action; - -public: - CIncomingAction( unsigned char nPID, BYTEARRAY &nCRC, BYTEARRAY &nAction ); - ~CIncomingAction( ); - - unsigned char GetPID( ) { return m_PID; } - BYTEARRAY GetCRC( ) { return m_CRC; } - BYTEARRAY *GetAction( ) { return &m_Action; } - uint32_t GetLength( ) { return m_Action.size( ) + 3; } -}; - -// -// CIncomingChatPlayer -// - -class CIncomingChatPlayer -{ -public: - enum ChatToHostType - { - CTH_MESSAGE = 0, // a chat message - CTH_MESSAGEEXTRA = 1, // a chat message with extra flags - CTH_TEAMCHANGE = 2, // a team change request - CTH_COLOURCHANGE = 3, // a colour change request - CTH_RACECHANGE = 4, // a race change request - CTH_HANDICAPCHANGE = 5 // a handicap change request - }; - -private: - ChatToHostType m_Type; - unsigned char m_FromPID; - BYTEARRAY m_ToPIDs; - unsigned char m_Flag; - string m_Message; - unsigned char m_Byte; - BYTEARRAY m_ExtraFlags; - -public: - CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, string nMessage ); - CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, string nMessage, BYTEARRAY &nExtraFlags ); - CIncomingChatPlayer( unsigned char nFromPID, BYTEARRAY &nToPIDs, unsigned char nFlag, unsigned char nByte ); - ~CIncomingChatPlayer( ); - - ChatToHostType GetType( ) { return m_Type; } - unsigned char GetFromPID( ) { return m_FromPID; } - BYTEARRAY GetToPIDs( ) { return m_ToPIDs; } - unsigned char GetFlag( ) { return m_Flag; } - string GetMessage( ) { return m_Message; } - unsigned char GetByte( ) { return m_Byte; } - BYTEARRAY GetExtraFlags( ) { return m_ExtraFlags; } -}; - -class CIncomingMapSize -{ -private: - unsigned char m_SizeFlag; - uint32_t m_MapSize; - -public: - CIncomingMapSize( unsigned char nSizeFlag, uint32_t nMapSize ); - ~CIncomingMapSize( ); - - unsigned char GetSizeFlag( ) { return m_SizeFlag; } - uint32_t GetMapSize( ) { return m_MapSize; } -}; - -#endif diff --git a/ghost/ghost.cpp b/ghost/ghost.cpp deleted file mode 100644 index 95a1f80..0000000 --- a/ghost/ghost.cpp +++ /dev/null @@ -1,1721 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "crc32.h" -#include "sha1.h" -#include "csvparser.h" -#include "config.h" -#include "language.h" -#include "socket.h" -#include "ghostdb.h" -#include "ghostdbsqlite.h" -#include "ghostdbmysql.h" -#include "bnet.h" -#include "map.h" -#include "packed.h" -#include "savegame.h" -#include "gameplayer.h" -#include "gameprotocol.h" -#include "gpsprotocol.h" -#include "game_base.h" -#include "game.h" -#include "game_admin.h" - -#include -#include - -#ifdef WIN32 - #include // for WSAIoctl -#endif - -#define __STORMLIB_SELF__ -#include - -/* - -#include "ghost.h" -#include "util.h" -#include "crc32.h" -#include "sha1.h" -#include "csvparser.h" -#include "config.h" -#include "language.h" -#include "socket.h" -#include "commandpacket.h" -#include "ghostdb.h" -#include "ghostdbsqlite.h" -#include "ghostdbmysql.h" -#include "bncsutilinterface.h" -#include "warden.h" -#include "bnlsprotocol.h" -#include "bnlsclient.h" -#include "bnetprotocol.h" -#include "bnet.h" -#include "map.h" -#include "packed.h" -#include "savegame.h" -#include "replay.h" -#include "gameslot.h" -#include "gameplayer.h" -#include "gameprotocol.h" -#include "gpsprotocol.h" -#include "game_base.h" -#include "game.h" -#include "game_admin.h" -#include "stats.h" -#include "statsdota.h" -#include "sqlite3.h" - -*/ - -#ifdef WIN32 - #include - #include -#endif - -#include - -#ifndef WIN32 - #include -#endif - -#ifdef __APPLE__ - #include -#endif - -string gCFGFile; -string gLogFile; -uint32_t gLogMethod; -ofstream *gLog = NULL; -CGHost *gGHost = NULL; - -uint32_t GetTime( ) -{ - return GetTicks( ) / 1000; -} - -uint32_t GetTicks( ) -{ -#ifdef WIN32 - // don't use GetTickCount anymore because it's not accurate enough (~16ms resolution) - // don't use QueryPerformanceCounter anymore because it isn't guaranteed to be strictly increasing on some systems and thus requires "smoothing" code - // use timeGetTime instead, which typically has a high resolution (5ms or more) but we request a lower resolution on startup - - return timeGetTime( ); -#elif __APPLE__ - uint64_t current = mach_absolute_time( ); - static mach_timebase_info_data_t info = { 0, 0 }; - // get timebase info - if( info.denom == 0 ) - mach_timebase_info( &info ); - uint64_t elapsednano = current * ( info.numer / info.denom ); - // convert ns to ms - return elapsednano / 1e6; -#else - uint32_t ticks; - struct timespec t; - clock_gettime( CLOCK_MONOTONIC, &t ); - ticks = t.tv_sec * 1000; - ticks += t.tv_nsec / 1000000; - return ticks; -#endif -} - -void SignalCatcher2( int s ) -{ - CONSOLE_Print( "[!!!] caught signal " + UTIL_ToString( s ) + ", exiting NOW" ); - - if( gGHost ) - { - if( gGHost->m_Exiting ) - exit( 1 ); - else - gGHost->m_Exiting = true; - } - else - exit( 1 ); -} - -void SignalCatcher( int s ) -{ - // signal( SIGABRT, SignalCatcher2 ); - signal( SIGINT, SignalCatcher2 ); - - CONSOLE_Print( "[!!!] caught signal " + UTIL_ToString( s ) + ", exiting nicely" ); - - if( gGHost ) - gGHost->m_ExitingNice = true; - else - exit( 1 ); -} - -void CONSOLE_Print( string message ) -{ - cout << message << endl; - - // logging - - if( !gLogFile.empty( ) ) - { - if( gLogMethod == 1 ) - { - ofstream Log; - Log.open( gLogFile.c_str( ), ios :: app ); - - if( !Log.fail( ) ) - { - time_t Now = time( NULL ); - string Time = asctime( localtime( &Now ) ); - - // erase the newline - - Time.erase( Time.size( ) - 1 ); - Log << "[" << Time << "] " << message << endl; - Log.close( ); - } - } - else if( gLogMethod == 2 ) - { - if( gLog && !gLog->fail( ) ) - { - time_t Now = time( NULL ); - string Time = asctime( localtime( &Now ) ); - - // erase the newline - - Time.erase( Time.size( ) - 1 ); - *gLog << "[" << Time << "] " << message << endl; - gLog->flush( ); - } - } - } -} - -void DEBUG_Print( string message ) -{ - cout << message << endl; -} - -void DEBUG_Print( BYTEARRAY b ) -{ - cout << "{ "; - - for( unsigned int i = 0; i < b.size( ); i++ ) - cout << hex << (int)b[i] << " "; - - cout << "}" << endl; -} - -// -// main -// - -int main( int argc, char **argv ) -{ - gCFGFile = "ghost.cfg"; - - if( argc > 1 && argv[1] ) - gCFGFile = argv[1]; - - // read config file - - CConfig CFG; - CFG.Read( "default.cfg" ); - CFG.Read( gCFGFile ); - gLogFile = CFG.GetString( "bot_log", string( ) ); - gLogMethod = CFG.GetInt( "bot_logmethod", 1 ); - - if( !gLogFile.empty( ) ) - { - if( gLogMethod == 1 ) - { - // log method 1: open, append, and close the log for every message - // this works well on Linux but poorly on Windows, particularly as the log file grows in size - // the log file can be edited/moved/deleted while GHost++ is running - } - else if( gLogMethod == 2 ) - { - // log method 2: open the log on startup, flush the log for every message, close the log on shutdown - // the log file CANNOT be edited/moved/deleted while GHost++ is running - - gLog = new ofstream( ); - gLog->open( gLogFile.c_str( ), ios :: app ); - } - } - - CONSOLE_Print( "[GHOST] starting up" ); - - if( !gLogFile.empty( ) ) - { - if( gLogMethod == 1 ) - CONSOLE_Print( "[GHOST] using log method 1, logging is enabled and [" + gLogFile + "] will not be locked" ); - else if( gLogMethod == 2 ) - { - if( gLog->fail( ) ) - CONSOLE_Print( "[GHOST] using log method 2 but unable to open [" + gLogFile + "] for appending, logging is disabled" ); - else - CONSOLE_Print( "[GHOST] using log method 2, logging is enabled and [" + gLogFile + "] is now locked" ); - } - } - else - CONSOLE_Print( "[GHOST] no log file specified, logging is disabled" ); - - // catch SIGABRT and SIGINT - - // signal( SIGABRT, SignalCatcher ); - signal( SIGINT, SignalCatcher ); - -#ifndef WIN32 - // disable SIGPIPE since some systems like OS X don't define MSG_NOSIGNAL - - signal( SIGPIPE, SIG_IGN ); -#endif - -#ifdef WIN32 - // initialize timer resolution - // attempt to set the resolution as low as possible from 1ms to 5ms - - unsigned int TimerResolution = 0; - - for( unsigned int i = 1; i <= 5; i++ ) - { - if( timeBeginPeriod( i ) == TIMERR_NOERROR ) - { - TimerResolution = i; - break; - } - else if( i < 5 ) - CONSOLE_Print( "[GHOST] error setting Windows timer resolution to " + UTIL_ToString( i ) + " milliseconds, trying a higher resolution" ); - else - { - CONSOLE_Print( "[GHOST] error setting Windows timer resolution" ); - return 1; - } - } - - CONSOLE_Print( "[GHOST] using Windows timer with resolution " + UTIL_ToString( TimerResolution ) + " milliseconds" ); -#elif __APPLE__ - // not sure how to get the resolution -#else - // print the timer resolution - - struct timespec Resolution; - - if( clock_getres( CLOCK_MONOTONIC, &Resolution ) == -1 ) - CONSOLE_Print( "[GHOST] error getting monotonic timer resolution" ); - else - CONSOLE_Print( "[GHOST] using monotonic timer with resolution " + UTIL_ToString( (double)( Resolution.tv_nsec / 1000 ), 2 ) + " microseconds" ); -#endif - -#ifdef WIN32 - // initialize winsock - - CONSOLE_Print( "[GHOST] starting winsock" ); - WSADATA wsadata; - - if( WSAStartup( MAKEWORD( 2, 2 ), &wsadata ) != 0 ) - { - CONSOLE_Print( "[GHOST] error starting winsock" ); - return 1; - } - - // increase process priority - - CONSOLE_Print( "[GHOST] setting process priority to \"above normal\"" ); - SetPriorityClass( GetCurrentProcess( ), ABOVE_NORMAL_PRIORITY_CLASS ); -#endif - - // initialize ghost - - gGHost = new CGHost( &CFG ); - - while( 1 ) - { - // block for 50ms on all sockets - if you intend to perform any timed actions more frequently you should change this - // that said it's likely we'll loop more often than this due to there being data waiting on one of the sockets but there aren't any guarantees - - if( gGHost->Update( 50000 ) ) - break; - } - - // shutdown ghost - - CONSOLE_Print( "[GHOST] shutting down" ); - delete gGHost; - gGHost = NULL; - -#ifdef WIN32 - // shutdown winsock - - CONSOLE_Print( "[GHOST] shutting down winsock" ); - WSACleanup( ); - - // shutdown timer - - timeEndPeriod( TimerResolution ); -#endif - - if( gLog ) - { - if( !gLog->fail( ) ) - gLog->close( ); - - delete gLog; - } - - return 0; -} - -// -// CGHost -// - -CGHost :: CGHost( CConfig *CFG ) -{ - m_UDPSocket = new CUDPSocket( ); - m_UDPSocket->SetBroadcastTarget( CFG->GetString( "udp_broadcasttarget", string( ) ) ); - m_UDPSocket->SetDontRoute( CFG->GetInt( "udp_dontroute", 0 ) == 0 ? false : true ); - m_ReconnectSocket = NULL; - m_GPSProtocol = new CGPSProtocol( ); - m_CRC = new CCRC32( ); - m_CRC->Initialize( ); - m_SHA = new CSHA1( ); - m_CurrentGame = NULL; - string DBType = CFG->GetString( "db_type", "sqlite3" ); - CONSOLE_Print( "[GHOST] opening primary database" ); - - if( DBType == "mysql" ) - { -#ifdef GHOST_MYSQL - m_DB = new CGHostDBMySQL( CFG ); -#else - CONSOLE_Print( "[GHOST] warning - this binary was not compiled with MySQL database support, using SQLite database instead" ); - m_DB = new CGHostDBSQLite( CFG ); -#endif - } - else - m_DB = new CGHostDBSQLite( CFG ); - - CONSOLE_Print( "[GHOST] opening secondary (local) database" ); - m_DBLocal = new CGHostDBSQLite( CFG ); - - // get a list of local IP addresses - // this list is used elsewhere to determine if a player connecting to the bot is local or not - - CONSOLE_Print( "[GHOST] attempting to find local IP addresses" ); - -#ifdef WIN32 - // use a more reliable Windows specific method since the portable method doesn't always work properly on Windows - // code stolen from: http://tangentsoft.net/wskfaq/examples/getifaces.html - - SOCKET sd = WSASocket( AF_INET, SOCK_DGRAM, 0, 0, 0, 0 ); - - if( sd == SOCKET_ERROR ) - CONSOLE_Print( "[GHOST] error finding local IP addresses - failed to create socket (error code " + UTIL_ToString( WSAGetLastError( ) ) + ")" ); - else - { - INTERFACE_INFO InterfaceList[20]; - unsigned long nBytesReturned; - - if( WSAIoctl( sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0 ) == SOCKET_ERROR ) - CONSOLE_Print( "[GHOST] error finding local IP addresses - WSAIoctl failed (error code " + UTIL_ToString( WSAGetLastError( ) ) + ")" ); - else - { - int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); - - for( int i = 0; i < nNumInterfaces; i++ ) - { - sockaddr_in *pAddress; - pAddress = (sockaddr_in *)&(InterfaceList[i].iiAddress); - CONSOLE_Print( "[GHOST] local IP address #" + UTIL_ToString( i + 1 ) + " is [" + string( inet_ntoa( pAddress->sin_addr ) ) + "]" ); - m_LocalAddresses.push_back( UTIL_CreateByteArray( (uint32_t)pAddress->sin_addr.s_addr, false ) ); - } - } - - closesocket( sd ); - } -#else - // use a portable method - - char HostName[255]; - - if( gethostname( HostName, 255 ) == SOCKET_ERROR ) - CONSOLE_Print( "[GHOST] error finding local IP addresses - failed to get local hostname" ); - else - { - CONSOLE_Print( "[GHOST] local hostname is [" + string( HostName ) + "]" ); - struct hostent *HostEnt = gethostbyname( HostName ); - - if( !HostEnt ) - CONSOLE_Print( "[GHOST] error finding local IP addresses - gethostbyname failed" ); - else - { - for( int i = 0; HostEnt->h_addr_list[i] != NULL; i++ ) - { - struct in_addr Address; - memcpy( &Address, HostEnt->h_addr_list[i], sizeof(struct in_addr) ); - CONSOLE_Print( "[GHOST] local IP address #" + UTIL_ToString( i + 1 ) + " is [" + string( inet_ntoa( Address ) ) + "]" ); - m_LocalAddresses.push_back( UTIL_CreateByteArray( (uint32_t)Address.s_addr, false ) ); - } - } - } -#endif - - m_Language = NULL; - m_Exiting = false; - m_ExitingNice = false; - m_Enabled = true; - m_Version = "17.0"; - m_HostCounter = 1; - m_AutoHostMaximumGames = CFG->GetInt( "autohost_maxgames", 0 ); - m_AutoHostAutoStartPlayers = CFG->GetInt( "autohost_startplayers", 0 ); - m_AutoHostGameName = CFG->GetString( "autohost_gamename", string( ) ); - m_AutoHostOwner = CFG->GetString( "autohost_owner", string( ) ); - m_LastAutoHostTime = GetTime( ); - m_AutoHostMatchMaking = false; - m_AutoHostMinimumScore = 0.0; - m_AutoHostMaximumScore = 0.0; - m_AllGamesFinished = false; - m_AllGamesFinishedTime = 0; - m_TFT = CFG->GetInt( "bot_tft", 1 ) == 0 ? false : true; - - if( m_TFT ) - CONSOLE_Print( "[GHOST] acting as Warcraft III: The Frozen Throne" ); - else - CONSOLE_Print( "[GHOST] acting as Warcraft III: Reign of Chaos" ); - - m_HostPort = CFG->GetInt( "bot_hostport", 6112 ); - m_Reconnect = CFG->GetInt( "bot_reconnect", 1 ) == 0 ? false : true; - m_ReconnectPort = CFG->GetInt( "bot_reconnectport", 6114 ); - m_DefaultMap = CFG->GetString( "bot_defaultmap", "map" ); - m_AdminGameCreate = CFG->GetInt( "admingame_create", 0 ) == 0 ? false : true; - m_AdminGamePort = CFG->GetInt( "admingame_port", 6113 ); - m_AdminGamePassword = CFG->GetString( "admingame_password", string( ) ); - m_AdminGameMap = CFG->GetString( "admingame_map", string( ) ); - m_LANWar3Version = CFG->GetInt( "lan_war3version", 24 ); - m_ReplayWar3Version = CFG->GetInt( "replay_war3version", 24 ); - m_ReplayBuildNumber = CFG->GetInt( "replay_buildnumber", 6059 ); - SetConfigs( CFG ); - - // load the battle.net connections - // we're just loading the config data and creating the CBNET classes here, the connections are established later (in the Update function) - - for( uint32_t i = 1; i < 10; i++ ) - { - string Prefix; - - if( i == 1 ) - Prefix = "bnet_"; - else - Prefix = "bnet" + UTIL_ToString( i ) + "_"; - - string Server = CFG->GetString( Prefix + "server", string( ) ); - string ServerAlias = CFG->GetString( Prefix + "serveralias", string( ) ); - string CDKeyROC = CFG->GetString( Prefix + "cdkeyroc", string( ) ); - string CDKeyTFT = CFG->GetString( Prefix + "cdkeytft", string( ) ); - string CountryAbbrev = CFG->GetString( Prefix + "countryabbrev", "USA" ); - string Country = CFG->GetString( Prefix + "country", "United States" ); - string Locale = CFG->GetString( Prefix + "locale", "system" ); - uint32_t LocaleID; - - if( Locale == "system" ) - { -#ifdef WIN32 - LocaleID = GetUserDefaultLangID( ); -#else - LocaleID = 1033; -#endif - } - else - LocaleID = UTIL_ToUInt32( Locale ); - - string UserName = CFG->GetString( Prefix + "username", string( ) ); - string UserPassword = CFG->GetString( Prefix + "password", string( ) ); - string FirstChannel = CFG->GetString( Prefix + "firstchannel", "The Void" ); - string RootAdmin = CFG->GetString( Prefix + "rootadmin", string( ) ); - string BNETCommandTrigger = CFG->GetString( Prefix + "commandtrigger", "!" ); - - if( BNETCommandTrigger.empty( ) ) - BNETCommandTrigger = "!"; - - bool HoldFriends = CFG->GetInt( Prefix + "holdfriends", 1 ) == 0 ? false : true; - bool HoldClan = CFG->GetInt( Prefix + "holdclan", 1 ) == 0 ? false : true; - bool PublicCommands = CFG->GetInt( Prefix + "publiccommands", 1 ) == 0 ? false : true; - string BNLSServer = CFG->GetString( Prefix + "bnlsserver", string( ) ); - int BNLSPort = CFG->GetInt( Prefix + "bnlsport", 9367 ); - int BNLSWardenCookie = CFG->GetInt( Prefix + "bnlswardencookie", 0 ); - unsigned char War3Version = CFG->GetInt( Prefix + "custom_war3version", 24 ); - BYTEARRAY EXEVersion = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversion", string( ) ), 4 ); - BYTEARRAY EXEVersionHash = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversionhash", string( ) ), 4 ); - string PasswordHashType = CFG->GetString( Prefix + "custom_passwordhashtype", string( ) ); - string PVPGNRealmName = CFG->GetString( Prefix + "custom_pvpgnrealmname", "PvPGN Realm" ); - uint32_t MaxMessageLength = CFG->GetInt( Prefix + "custom_maxmessagelength", 200 ); - - if( Server.empty( ) ) - break; - - if( CDKeyROC.empty( ) ) - { - CONSOLE_Print( "[GHOST] missing " + Prefix + "cdkeyroc, skipping this battle.net connection" ); - continue; - } - - if( m_TFT && CDKeyTFT.empty( ) ) - { - CONSOLE_Print( "[GHOST] missing " + Prefix + "cdkeytft, skipping this battle.net connection" ); - continue; - } - - if( UserName.empty( ) ) - { - CONSOLE_Print( "[GHOST] missing " + Prefix + "username, skipping this battle.net connection" ); - continue; - } - - if( UserPassword.empty( ) ) - { - CONSOLE_Print( "[GHOST] missing " + Prefix + "password, skipping this battle.net connection" ); - continue; - } - - CONSOLE_Print( "[GHOST] found battle.net connection #" + UTIL_ToString( i ) + " for server [" + Server + "]" ); - - if( Locale == "system" ) - { -#ifdef WIN32 - CONSOLE_Print( "[GHOST] using system locale of " + UTIL_ToString( LocaleID ) ); -#else - CONSOLE_Print( "[GHOST] unable to get system locale, using default locale of 1033" ); -#endif - } - - m_BNETs.push_back( new CBNET( this, Server, ServerAlias, BNLSServer, (uint16_t)BNLSPort, (uint32_t)BNLSWardenCookie, CDKeyROC, CDKeyTFT, CountryAbbrev, Country, LocaleID, UserName, UserPassword, FirstChannel, RootAdmin, BNETCommandTrigger[0], HoldFriends, HoldClan, PublicCommands, War3Version, EXEVersion, EXEVersionHash, PasswordHashType, PVPGNRealmName, MaxMessageLength, i ) ); - } - - if( m_BNETs.empty( ) ) - CONSOLE_Print( "[GHOST] warning - no battle.net connections found in config file" ); - - // extract common.j and blizzard.j from War3Patch.mpq if we can - // these two files are necessary for calculating "map_crc" when loading maps so we make sure to do it before loading the default map - // see CMap :: Load for more information - - ExtractScripts( ); - - // load the default maps (note: make sure to run ExtractScripts first) - - if( m_DefaultMap.size( ) < 4 || m_DefaultMap.substr( m_DefaultMap.size( ) - 4 ) != ".cfg" ) - { - m_DefaultMap += ".cfg"; - CONSOLE_Print( "[GHOST] adding \".cfg\" to default map -> new default is [" + m_DefaultMap + "]" ); - } - - CConfig MapCFG; - MapCFG.Read( m_MapCFGPath + m_DefaultMap ); - m_Map = new CMap( this, &MapCFG, m_MapCFGPath + m_DefaultMap ); - - if( !m_AdminGameMap.empty( ) ) - { - if( m_AdminGameMap.size( ) < 4 || m_AdminGameMap.substr( m_AdminGameMap.size( ) - 4 ) != ".cfg" ) - { - m_AdminGameMap += ".cfg"; - CONSOLE_Print( "[GHOST] adding \".cfg\" to default admin game map -> new default is [" + m_AdminGameMap + "]" ); - } - - CONSOLE_Print( "[GHOST] trying to load default admin game map" ); - CConfig AdminMapCFG; - AdminMapCFG.Read( m_MapCFGPath + m_AdminGameMap ); - m_AdminMap = new CMap( this, &AdminMapCFG, m_MapCFGPath + m_AdminGameMap ); - - if( !m_AdminMap->GetValid( ) ) - { - CONSOLE_Print( "[GHOST] default admin game map isn't valid, using hardcoded admin game map instead" ); - delete m_AdminMap; - m_AdminMap = new CMap( this ); - } - } - else - { - CONSOLE_Print( "[GHOST] using hardcoded admin game map" ); - m_AdminMap = new CMap( this ); - } - - m_AutoHostMap = new CMap( *m_Map ); - m_SaveGame = new CSaveGame( ); - - // load the iptocountry data - - LoadIPToCountryData( ); - - // create the admin game - - if( m_AdminGameCreate ) - { - CONSOLE_Print( "[GHOST] creating admin game" ); - m_AdminGame = new CAdminGame( this, m_AdminMap, NULL, m_AdminGamePort, 0, "GHost++ Admin Game", m_AdminGamePassword ); - - if( m_AdminGamePort == m_HostPort ) - CONSOLE_Print( "[GHOST] warning - admingame_port and bot_hostport are set to the same value, you won't be able to host any games" ); - } - else - m_AdminGame = NULL; - - if( m_BNETs.empty( ) && !m_AdminGame ) - CONSOLE_Print( "[GHOST] warning - no battle.net connections found and no admin game created" ); - -#ifdef GHOST_MYSQL - CONSOLE_Print( "[GHOST] GHost++ Version " + m_Version + " (with MySQL support)" ); -#else - CONSOLE_Print( "[GHOST] GHost++ Version " + m_Version + " (without MySQL support)" ); -#endif -} - -CGHost :: ~CGHost( ) -{ - delete m_UDPSocket; - delete m_ReconnectSocket; - - for( vector :: iterator i = m_ReconnectSockets.begin( ); i != m_ReconnectSockets.end( ); i++ ) - delete *i; - - delete m_GPSProtocol; - delete m_CRC; - delete m_SHA; - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - delete *i; - - delete m_CurrentGame; - delete m_AdminGame; - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - delete *i; - - delete m_DB; - delete m_DBLocal; - - // warning: we don't delete any entries of m_Callables here because we can't be guaranteed that the associated threads have terminated - // this is fine if the program is currently exiting because the OS will clean up after us - // but if you try to recreate the CGHost object within a single session you will probably leak resources! - - if( !m_Callables.empty( ) ) - CONSOLE_Print( "[GHOST] warning - " + UTIL_ToString( m_Callables.size( ) ) + " orphaned callables were leaked (this is not an error)" ); - - delete m_Language; - delete m_Map; - delete m_AdminMap; - delete m_AutoHostMap; - delete m_SaveGame; -} - -bool CGHost :: Update( long usecBlock ) -{ - // todotodo: do we really want to shutdown if there's a database error? is there any way to recover from this? - - if( m_DB->HasError( ) ) - { - CONSOLE_Print( "[GHOST] database error - " + m_DB->GetError( ) ); - return true; - } - - if( m_DBLocal->HasError( ) ) - { - CONSOLE_Print( "[GHOST] local database error - " + m_DBLocal->GetError( ) ); - return true; - } - - // try to exit nicely if requested to do so - - if( m_ExitingNice ) - { - if( !m_BNETs.empty( ) ) - { - CONSOLE_Print( "[GHOST] deleting all battle.net connections in preparation for exiting nicely" ); - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - delete *i; - - m_BNETs.clear( ); - } - - if( m_CurrentGame ) - { - CONSOLE_Print( "[GHOST] deleting current game in preparation for exiting nicely" ); - delete m_CurrentGame; - m_CurrentGame = NULL; - } - - if( m_AdminGame ) - { - CONSOLE_Print( "[GHOST] deleting admin game in preparation for exiting nicely" ); - delete m_AdminGame; - m_AdminGame = NULL; - } - - if( m_Games.empty( ) ) - { - if( !m_AllGamesFinished ) - { - CONSOLE_Print( "[GHOST] all games finished, waiting 60 seconds for threads to finish" ); - CONSOLE_Print( "[GHOST] there are " + UTIL_ToString( m_Callables.size( ) ) + " threads in progress" ); - m_AllGamesFinished = true; - m_AllGamesFinishedTime = GetTime( ); - } - else - { - if( m_Callables.empty( ) ) - { - CONSOLE_Print( "[GHOST] all threads finished, exiting nicely" ); - m_Exiting = true; - } - else if( GetTime( ) - m_AllGamesFinishedTime >= 60 ) - { - CONSOLE_Print( "[GHOST] waited 60 seconds for threads to finish, exiting anyway" ); - CONSOLE_Print( "[GHOST] there are " + UTIL_ToString( m_Callables.size( ) ) + " threads still in progress which will be terminated" ); - m_Exiting = true; - } - } - } - } - - // update callables - - for( vector :: iterator i = m_Callables.begin( ); i != m_Callables.end( ); ) - { - if( (*i)->GetReady( ) ) - { - m_DB->RecoverCallable( *i ); - delete *i; - i = m_Callables.erase( i ); - } - else - i++; - } - - // create the GProxy++ reconnect listener - - if( m_Reconnect ) - { - if( !m_ReconnectSocket ) - { - m_ReconnectSocket = new CTCPServer( ); - - if( m_ReconnectSocket->Listen( m_BindAddress, m_ReconnectPort ) ) - CONSOLE_Print( "[GHOST] listening for GProxy++ reconnects on port " + UTIL_ToString( m_ReconnectPort ) ); - else - { - CONSOLE_Print( "[GHOST] error listening for GProxy++ reconnects on port " + UTIL_ToString( m_ReconnectPort ) ); - delete m_ReconnectSocket; - m_ReconnectSocket = NULL; - m_Reconnect = false; - } - } - else if( m_ReconnectSocket->HasError( ) ) - { - CONSOLE_Print( "[GHOST] GProxy++ reconnect listener error (" + m_ReconnectSocket->GetErrorString( ) + ")" ); - delete m_ReconnectSocket; - m_ReconnectSocket = NULL; - m_Reconnect = false; - } - } - - unsigned int NumFDs = 0; - - // take every socket we own and throw it in one giant select statement so we can block on all sockets - - int nfds = 0; - fd_set fd; - fd_set send_fd; - FD_ZERO( &fd ); - FD_ZERO( &send_fd ); - - // 1. all battle.net sockets - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - NumFDs += (*i)->SetFD( &fd, &send_fd, &nfds ); - - // 2. the current game's server and player sockets - - if( m_CurrentGame ) - NumFDs += m_CurrentGame->SetFD( &fd, &send_fd, &nfds ); - - // 3. the admin game's server and player sockets - - if( m_AdminGame ) - NumFDs += m_AdminGame->SetFD( &fd, &send_fd, &nfds ); - - // 4. all running games' player sockets - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - NumFDs += (*i)->SetFD( &fd, &send_fd, &nfds ); - - // 5. the GProxy++ reconnect socket(s) - - if( m_Reconnect && m_ReconnectSocket ) - { - m_ReconnectSocket->SetFD( &fd, &send_fd, &nfds ); - NumFDs++; - } - - for( vector :: iterator i = m_ReconnectSockets.begin( ); i != m_ReconnectSockets.end( ); i++ ) - { - (*i)->SetFD( &fd, &send_fd, &nfds ); - NumFDs++; - } - - // before we call select we need to determine how long to block for - // previously we just blocked for a maximum of the passed usecBlock microseconds - // however, in an effort to make game updates happen closer to the desired latency setting we now use a dynamic block interval - // note: we still use the passed usecBlock as a hard maximum - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - { - if( (*i)->GetNextTimedActionTicks( ) * 1000 < usecBlock ) - usecBlock = (*i)->GetNextTimedActionTicks( ) * 1000; - } - - // always block for at least 1ms just in case something goes wrong - // this prevents the bot from sucking up all the available CPU if a game keeps asking for immediate updates - // it's a bit ridiculous to include this check since, in theory, the bot is programmed well enough to never make this mistake - // however, considering who programmed it, it's worthwhile to do it anyway - - if( usecBlock < 1000 ) - usecBlock = 1000; - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = usecBlock; - - struct timeval send_tv; - send_tv.tv_sec = 0; - send_tv.tv_usec = 0; - -#ifdef WIN32 - select( 1, &fd, NULL, NULL, &tv ); - select( 1, NULL, &send_fd, NULL, &send_tv ); -#else - select( nfds + 1, &fd, NULL, NULL, &tv ); - select( nfds + 1, NULL, &send_fd, NULL, &send_tv ); -#endif - - if( NumFDs == 0 ) - { - // we don't have any sockets (i.e. we aren't connected to battle.net maybe due to a lost connection and there aren't any games running) - // select will return immediately and we'll chew up the CPU if we let it loop so just sleep for 50ms to kill some time - - MILLISLEEP( 50 ); - } - - bool AdminExit = false; - bool BNETExit = false; - - // update current game - - if( m_CurrentGame ) - { - if( m_CurrentGame->Update( &fd, &send_fd ) ) - { - CONSOLE_Print( "[GHOST] deleting current game [" + m_CurrentGame->GetGameName( ) + "]" ); - delete m_CurrentGame; - m_CurrentGame = NULL; - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - (*i)->QueueGameUncreate( ); - (*i)->QueueEnterChat( ); - } - } - else if( m_CurrentGame ) - m_CurrentGame->UpdatePost( &send_fd ); - } - - // update admin game - - if( m_AdminGame ) - { - if( m_AdminGame->Update( &fd, &send_fd ) ) - { - CONSOLE_Print( "[GHOST] deleting admin game" ); - delete m_AdminGame; - m_AdminGame = NULL; - AdminExit = true; - } - else if( m_AdminGame ) - m_AdminGame->UpdatePost( &send_fd ); - } - - // update running games - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); ) - { - if( (*i)->Update( &fd, &send_fd ) ) - { - CONSOLE_Print( "[GHOST] deleting game [" + (*i)->GetGameName( ) + "]" ); - EventGameDeleted( *i ); - delete *i; - i = m_Games.erase( i ); - } - else - { - (*i)->UpdatePost( &send_fd ); - i++; - } - } - - // update battle.net connections - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->Update( &fd, &send_fd ) ) - BNETExit = true; - } - - // update GProxy++ reliable reconnect sockets - - if( m_Reconnect && m_ReconnectSocket ) - { - CTCPSocket *NewSocket = m_ReconnectSocket->Accept( &fd ); - - if( NewSocket ) - m_ReconnectSockets.push_back( NewSocket ); - } - - for( vector :: iterator i = m_ReconnectSockets.begin( ); i != m_ReconnectSockets.end( ); ) - { - if( (*i)->HasError( ) || !(*i)->GetConnected( ) || GetTime( ) - (*i)->GetLastRecv( ) >= 10 ) - { - delete *i; - i = m_ReconnectSockets.erase( i ); - continue; - } - - (*i)->DoRecv( &fd ); - string *RecvBuffer = (*i)->GetBytes( ); - BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); - - // a packet is at least 4 bytes - - if( Bytes.size( ) >= 4 ) - { - if( Bytes[0] == GPS_HEADER_CONSTANT ) - { - // bytes 2 and 3 contain the length of the packet - - uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); - - if( Length >= 4 ) - { - if( Bytes.size( ) >= Length ) - { - if( Bytes[1] == CGPSProtocol :: GPS_RECONNECT && Length == 13 ) - { - unsigned char PID = Bytes[4]; - uint32_t ReconnectKey = UTIL_ByteArrayToUInt32( Bytes, false, 5 ); - uint32_t LastPacket = UTIL_ByteArrayToUInt32( Bytes, false, 9 ); - - // look for a matching player in a running game - - CGamePlayer *Match = NULL; - - for( vector :: iterator j = m_Games.begin( ); j != m_Games.end( ); j++ ) - { - if( (*j)->GetGameLoaded( ) ) - { - CGamePlayer *Player = (*j)->GetPlayerFromPID( PID ); - - if( Player && Player->GetGProxy( ) && Player->GetGProxyReconnectKey( ) == ReconnectKey ) - { - Match = Player; - break; - } - } - } - - if( Match ) - { - // reconnect successful! - - *RecvBuffer = RecvBuffer->substr( Length ); - Match->EventGProxyReconnect( *i, LastPacket ); - i = m_ReconnectSockets.erase( i ); - continue; - } - else - { - (*i)->PutBytes( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_NOTFOUND ) ); - (*i)->DoSend( &send_fd ); - delete *i; - i = m_ReconnectSockets.erase( i ); - continue; - } - } - else - { - (*i)->PutBytes( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_INVALID ) ); - (*i)->DoSend( &send_fd ); - delete *i; - i = m_ReconnectSockets.erase( i ); - continue; - } - } - } - else - { - (*i)->PutBytes( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_INVALID ) ); - (*i)->DoSend( &send_fd ); - delete *i; - i = m_ReconnectSockets.erase( i ); - continue; - } - } - else - { - (*i)->PutBytes( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_INVALID ) ); - (*i)->DoSend( &send_fd ); - delete *i; - i = m_ReconnectSockets.erase( i ); - continue; - } - } - - (*i)->DoSend( &send_fd ); - i++; - } - - // autohost - - if( !m_AutoHostGameName.empty( ) && m_AutoHostMaximumGames != 0 && m_AutoHostAutoStartPlayers != 0 && GetTime( ) - m_LastAutoHostTime >= 30 ) - { - // copy all the checks from CGHost :: CreateGame here because we don't want to spam the chat when there's an error - // instead we fail silently and try again soon - - if( !m_ExitingNice && m_Enabled && !m_CurrentGame && m_Games.size( ) < m_MaxGames && m_Games.size( ) < m_AutoHostMaximumGames ) - { - if( m_AutoHostMap->GetValid( ) ) - { - string GameName = m_AutoHostGameName + " #" + UTIL_ToString( m_HostCounter ); - - if( GameName.size( ) <= 31 ) - { - CreateGame( m_AutoHostMap, GAME_PUBLIC, false, GameName, m_AutoHostOwner, m_AutoHostOwner, m_AutoHostServer, false ); - - if( m_CurrentGame ) - { - m_CurrentGame->SetAutoStartPlayers( m_AutoHostAutoStartPlayers ); - - if( m_AutoHostMatchMaking ) - { - if( !m_Map->GetMapMatchMakingCategory( ).empty( ) ) - { - if( !( m_Map->GetMapOptions( ) & MAPOPT_FIXEDPLAYERSETTINGS ) ) - CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory [" + m_Map->GetMapMatchMakingCategory( ) + "] found but matchmaking can only be used with fixed player settings, matchmaking disabled" ); - else - { - CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory [" + m_Map->GetMapMatchMakingCategory( ) + "] found, matchmaking enabled" ); - - m_CurrentGame->SetMatchMaking( true ); - m_CurrentGame->SetMinimumScore( m_AutoHostMinimumScore ); - m_CurrentGame->SetMaximumScore( m_AutoHostMaximumScore ); - } - } - else - CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory not found, matchmaking disabled" ); - } - } - } - else - { - CONSOLE_Print( "[GHOST] stopped auto hosting, next game name [" + GameName + "] is too long (the maximum is 31 characters)" ); - m_AutoHostGameName.clear( ); - m_AutoHostOwner.clear( ); - m_AutoHostServer.clear( ); - m_AutoHostMaximumGames = 0; - m_AutoHostAutoStartPlayers = 0; - m_AutoHostMatchMaking = false; - m_AutoHostMinimumScore = 0.0; - m_AutoHostMaximumScore = 0.0; - } - } - else - { - CONSOLE_Print( "[GHOST] stopped auto hosting, map config file [" + m_AutoHostMap->GetCFGFile( ) + "] is invalid" ); - m_AutoHostGameName.clear( ); - m_AutoHostOwner.clear( ); - m_AutoHostServer.clear( ); - m_AutoHostMaximumGames = 0; - m_AutoHostAutoStartPlayers = 0; - m_AutoHostMatchMaking = false; - m_AutoHostMinimumScore = 0.0; - m_AutoHostMaximumScore = 0.0; - } - } - - m_LastAutoHostTime = GetTime( ); - } - - return m_Exiting || AdminExit || BNETExit; -} - -void CGHost :: EventBNETConnecting( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->ConnectingToBNET( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->SendAllChat( m_Language->ConnectingToBNET( bnet->GetServer( ) ) ); -} - -void CGHost :: EventBNETConnected( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->ConnectedToBNET( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->SendAllChat( m_Language->ConnectedToBNET( bnet->GetServer( ) ) ); -} - -void CGHost :: EventBNETDisconnected( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->DisconnectedFromBNET( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->SendAllChat( m_Language->DisconnectedFromBNET( bnet->GetServer( ) ) ); -} - -void CGHost :: EventBNETLoggedIn( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->LoggedInToBNET( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->SendAllChat( m_Language->LoggedInToBNET( bnet->GetServer( ) ) ); -} - -void CGHost :: EventBNETGameRefreshed( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->BNETGameHostingSucceeded( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->EventGameRefreshed( bnet->GetServer( ) ); -} - -void CGHost :: EventBNETGameRefreshFailed( CBNET *bnet ) -{ - if( m_CurrentGame ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - (*i)->QueueChatCommand( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); - - if( (*i)->GetServer( ) == m_CurrentGame->GetCreatorServer( ) ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ), m_CurrentGame->GetCreatorName( ), true ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->BNETGameHostingFailed( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); - - m_CurrentGame->SendAllChat( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); - - // we take the easy route and simply close the lobby if a refresh fails - // it's possible at least one refresh succeeded and therefore the game is still joinable on at least one battle.net (plus on the local network) but we don't keep track of that - // we only close the game if it has no players since we support game rehosting (via !priv and !pub in the lobby) - - if( m_CurrentGame->GetNumHumanPlayers( ) == 0 ) - m_CurrentGame->SetExiting( true ); - - m_CurrentGame->SetRefreshError( true ); - } -} - -void CGHost :: EventBNETConnectTimedOut( CBNET *bnet ) -{ - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->ConnectingToBNETTimedOut( bnet->GetServer( ) ) ); - - if( m_CurrentGame ) - m_CurrentGame->SendAllChat( m_Language->ConnectingToBNETTimedOut( bnet->GetServer( ) ) ); -} - -void CGHost :: EventBNETWhisper( CBNET *bnet, string user, string message ) -{ - if( m_AdminGame ) - { - m_AdminGame->SendAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - if( m_CurrentGame ) - m_CurrentGame->SendLocalAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - (*i)->SendLocalAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - } -} - -void CGHost :: EventBNETChat( CBNET *bnet, string user, string message ) -{ - if( m_AdminGame ) - { - m_AdminGame->SendAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - if( m_CurrentGame ) - m_CurrentGame->SendLocalAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - (*i)->SendLocalAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - } -} - -void CGHost :: EventBNETEmote( CBNET *bnet, string user, string message ) -{ - if( m_AdminGame ) - { - m_AdminGame->SendAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - if( m_CurrentGame ) - m_CurrentGame->SendLocalAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - - for( vector :: iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) - (*i)->SendLocalAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); - } -} - -void CGHost :: EventGameDeleted( CBaseGame *game ) -{ - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - (*i)->QueueChatCommand( m_Language->GameIsOver( game->GetDescription( ) ) ); - - if( (*i)->GetServer( ) == game->GetCreatorServer( ) ) - (*i)->QueueChatCommand( m_Language->GameIsOver( game->GetDescription( ) ), game->GetCreatorName( ), true ); - } -} - -void CGHost :: ReloadConfigs( ) -{ - CConfig CFG; - CFG.Read( "default.cfg" ); - CFG.Read( gCFGFile ); - SetConfigs( &CFG ); -} - -void CGHost :: SetConfigs( CConfig *CFG ) -{ - // this doesn't set EVERY config value since that would potentially require reconfiguring the battle.net connections - // it just set the easily reloadable values - - m_LanguageFile = CFG->GetString( "bot_language", "language.cfg" ); - delete m_Language; - m_Language = new CLanguage( m_LanguageFile ); - m_Warcraft3Path = UTIL_AddPathSeperator( CFG->GetString( "bot_war3path", "C:\\Program Files\\Warcraft III\\" ) ); - m_BindAddress = CFG->GetString( "bot_bindaddress", string( ) ); - m_ReconnectWaitTime = CFG->GetInt( "bot_reconnectwaittime", 3 ); - m_MaxGames = CFG->GetInt( "bot_maxgames", 5 ); - string BotCommandTrigger = CFG->GetString( "bot_commandtrigger", "!" ); - - if( BotCommandTrigger.empty( ) ) - BotCommandTrigger = "!"; - - m_CommandTrigger = BotCommandTrigger[0]; - m_MapCFGPath = UTIL_AddPathSeperator( CFG->GetString( "bot_mapcfgpath", string( ) ) ); - m_SaveGamePath = UTIL_AddPathSeperator( CFG->GetString( "bot_savegamepath", string( ) ) ); - m_MapPath = UTIL_AddPathSeperator( CFG->GetString( "bot_mappath", string( ) ) ); - m_SaveReplays = CFG->GetInt( "bot_savereplays", 0 ) == 0 ? false : true; - m_ReplayPath = UTIL_AddPathSeperator( CFG->GetString( "bot_replaypath", string( ) ) ); - m_VirtualHostName = CFG->GetString( "bot_virtualhostname", "|cFF4080C0GHost" ); - m_HideIPAddresses = CFG->GetInt( "bot_hideipaddresses", 0 ) == 0 ? false : true; - m_CheckMultipleIPUsage = CFG->GetInt( "bot_checkmultipleipusage", 1 ) == 0 ? false : true; - - if( m_VirtualHostName.size( ) > 15 ) - { - m_VirtualHostName = "|cFF4080C0GHost"; - CONSOLE_Print( "[GHOST] warning - bot_virtualhostname is longer than 15 characters, using default virtual host name" ); - } - - m_SpoofChecks = CFG->GetInt( "bot_spoofchecks", 2 ); - m_RequireSpoofChecks = CFG->GetInt( "bot_requirespoofchecks", 0 ) == 0 ? false : true; - m_ReserveAdmins = CFG->GetInt( "bot_reserveadmins", 1 ) == 0 ? false : true; - m_RefreshMessages = CFG->GetInt( "bot_refreshmessages", 0 ) == 0 ? false : true; - m_AutoLock = CFG->GetInt( "bot_autolock", 0 ) == 0 ? false : true; - m_AutoSave = CFG->GetInt( "bot_autosave", 0 ) == 0 ? false : true; - m_AllowDownloads = CFG->GetInt( "bot_allowdownloads", 0 ); - m_PingDuringDownloads = CFG->GetInt( "bot_pingduringdownloads", 0 ) == 0 ? false : true; - m_MaxDownloaders = CFG->GetInt( "bot_maxdownloaders", 3 ); - m_MaxDownloadSpeed = CFG->GetInt( "bot_maxdownloadspeed", 100 ); - m_LCPings = CFG->GetInt( "bot_lcpings", 1 ) == 0 ? false : true; - m_AutoKickPing = CFG->GetInt( "bot_autokickping", 400 ); - m_BanMethod = CFG->GetInt( "bot_banmethod", 1 ); - m_IPBlackListFile = CFG->GetString( "bot_ipblacklistfile", "ipblacklist.txt" ); - m_LobbyTimeLimit = CFG->GetInt( "bot_lobbytimelimit", 10 ); - m_Latency = CFG->GetInt( "bot_latency", 100 ); - m_SyncLimit = CFG->GetInt( "bot_synclimit", 50 ); - m_VoteKickAllowed = CFG->GetInt( "bot_votekickallowed", 1 ) == 0 ? false : true; - m_VoteKickPercentage = CFG->GetInt( "bot_votekickpercentage", 100 ); - - if( m_VoteKickPercentage > 100 ) - { - m_VoteKickPercentage = 100; - CONSOLE_Print( "[GHOST] warning - bot_votekickpercentage is greater than 100, using 100 instead" ); - } - - m_MOTDFile = CFG->GetString( "bot_motdfile", "motd.txt" ); - m_GameLoadedFile = CFG->GetString( "bot_gameloadedfile", "gameloaded.txt" ); - m_GameOverFile = CFG->GetString( "bot_gameoverfile", "gameover.txt" ); - m_LocalAdminMessages = CFG->GetInt( "bot_localadminmessages", 1 ) == 0 ? false : true; - m_TCPNoDelay = CFG->GetInt( "tcp_nodelay", 0 ) == 0 ? false : true; - m_MatchMakingMethod = CFG->GetInt( "bot_matchmakingmethod", 1 ); -} - -void CGHost :: ExtractScripts( ) -{ - string PatchMPQFileName = m_Warcraft3Path + "War3Patch.mpq"; - HANDLE PatchMPQ; - - if( SFileOpenArchive( PatchMPQFileName.c_str( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &PatchMPQ ) ) - { - CONSOLE_Print( "[GHOST] loading MPQ file [" + PatchMPQFileName + "]" ); - HANDLE SubFile; - - // common.j - - if( SFileOpenFileEx( PatchMPQ, "Scripts\\common.j", 0, &SubFile ) ) - { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); - - if( FileLength > 0 && FileLength != 0xFFFFFFFF ) - { - char *SubFileData = new char[FileLength]; - DWORD BytesRead = 0; - - if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) - { - CONSOLE_Print( "[GHOST] extracting Scripts\\common.j from MPQ file to [" + m_MapCFGPath + "common.j]" ); - UTIL_FileWrite( m_MapCFGPath + "common.j", (unsigned char *)SubFileData, BytesRead ); - } - else - CONSOLE_Print( "[GHOST] warning - unable to extract Scripts\\common.j from MPQ file" ); - - delete [] SubFileData; - } - - SFileCloseFile( SubFile ); - } - else - CONSOLE_Print( "[GHOST] couldn't find Scripts\\common.j in MPQ file" ); - - // blizzard.j - - if( SFileOpenFileEx( PatchMPQ, "Scripts\\blizzard.j", 0, &SubFile ) ) - { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); - - if( FileLength > 0 && FileLength != 0xFFFFFFFF ) - { - char *SubFileData = new char[FileLength]; - DWORD BytesRead = 0; - - if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) - { - CONSOLE_Print( "[GHOST] extracting Scripts\\blizzard.j from MPQ file to [" + m_MapCFGPath + "blizzard.j]" ); - UTIL_FileWrite( m_MapCFGPath + "blizzard.j", (unsigned char *)SubFileData, BytesRead ); - } - else - CONSOLE_Print( "[GHOST] warning - unable to extract Scripts\\blizzard.j from MPQ file" ); - - delete [] SubFileData; - } - - SFileCloseFile( SubFile ); - } - else - CONSOLE_Print( "[GHOST] couldn't find Scripts\\blizzard.j in MPQ file" ); - - SFileCloseArchive( PatchMPQ ); - } - else - CONSOLE_Print( "[GHOST] warning - unable to load MPQ file [" + PatchMPQFileName + "] - error code " + UTIL_ToString( GetLastError( ) ) ); -} - -void CGHost :: LoadIPToCountryData( ) -{ - ifstream in; - in.open( "ip-to-country.csv" ); - - if( in.fail( ) ) - CONSOLE_Print( "[GHOST] warning - unable to read file [ip-to-country.csv], iptocountry data not loaded" ); - else - { - CONSOLE_Print( "[GHOST] started loading [ip-to-country.csv]" ); - - // the begin and commit statements are optimizations - // we're about to insert ~4 MB of data into the database so if we allow the database to treat each insert as a transaction it will take a LONG time - // todotodo: handle begin/commit failures a bit more gracefully - - if( !m_DBLocal->Begin( ) ) - CONSOLE_Print( "[GHOST] warning - failed to begin local database transaction, iptocountry data not loaded" ); - else - { - unsigned char Percent = 0; - string Line; - string IP1; - string IP2; - string Country; - CSVParser parser; - - // get length of file for the progress meter - - in.seekg( 0, ios :: end ); - uint32_t FileLength = in.tellg( ); - in.seekg( 0, ios :: beg ); - - while( !in.eof( ) ) - { - getline( in, Line ); - - if( Line.empty( ) ) - continue; - - parser << Line; - parser >> IP1; - parser >> IP2; - parser >> Country; - m_DBLocal->FromAdd( UTIL_ToUInt32( IP1 ), UTIL_ToUInt32( IP2 ), Country ); - - // it's probably going to take awhile to load the iptocountry data (~10 seconds on my 3.2 GHz P4 when using SQLite3) - // so let's print a progress meter just to keep the user from getting worried - - unsigned char NewPercent = (unsigned char)( (float)in.tellg( ) / FileLength * 100 ); - - if( NewPercent != Percent && NewPercent % 10 == 0 ) - { - Percent = NewPercent; - CONSOLE_Print( "[GHOST] iptocountry data: " + UTIL_ToString( Percent ) + "% loaded" ); - } - } - - if( !m_DBLocal->Commit( ) ) - CONSOLE_Print( "[GHOST] warning - failed to commit local database transaction, iptocountry data not loaded" ); - else - CONSOLE_Print( "[GHOST] finished loading [ip-to-country.csv]" ); - } - - in.close( ); - } -} - -void CGHost :: CreateGame( CMap *map, unsigned char gameState, bool saveGame, string gameName, string ownerName, string creatorName, string creatorServer, bool whisper ) -{ - if( !m_Enabled ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameDisabled( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameDisabled( gameName ) ); - - return; - } - - if( gameName.size( ) > 31 ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameNameTooLong( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameNameTooLong( gameName ) ); - - return; - } - - if( !map->GetValid( ) ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameInvalidMap( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameInvalidMap( gameName ) ); - - return; - } - - if( saveGame ) - { - if( !m_SaveGame->GetValid( ) ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameInvalidSaveGame( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameInvalidSaveGame( gameName ) ); - - return; - } - - string MapPath1 = m_SaveGame->GetMapPath( ); - string MapPath2 = map->GetMapPath( ); - transform( MapPath1.begin( ), MapPath1.end( ), MapPath1.begin( ), (int(*)(int))tolower ); - transform( MapPath2.begin( ), MapPath2.end( ), MapPath2.begin( ), (int(*)(int))tolower ); - - if( MapPath1 != MapPath2 ) - { - CONSOLE_Print( "[GHOST] path mismatch, saved game path is [" + MapPath1 + "] but map path is [" + MapPath2 + "]" ); - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameSaveGameMapMismatch( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameSaveGameMapMismatch( gameName ) ); - - return; - } - - if( m_EnforcePlayers.empty( ) ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameMustEnforceFirst( gameName ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameMustEnforceFirst( gameName ) ); - - return; - } - } - - if( m_CurrentGame ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameAnotherGameInLobby( gameName, m_CurrentGame->GetDescription( ) ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameAnotherGameInLobby( gameName, m_CurrentGame->GetDescription( ) ) ); - - return; - } - - if( m_Games.size( ) >= m_MaxGames ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == creatorServer ) - (*i)->QueueChatCommand( m_Language->UnableToCreateGameMaxGamesReached( gameName, UTIL_ToString( m_MaxGames ) ), creatorName, whisper ); - } - - if( m_AdminGame ) - m_AdminGame->SendAllChat( m_Language->UnableToCreateGameMaxGamesReached( gameName, UTIL_ToString( m_MaxGames ) ) ); - - return; - } - - CONSOLE_Print( "[GHOST] creating game [" + gameName + "]" ); - - if( saveGame ) - m_CurrentGame = new CGame( this, map, m_SaveGame, m_HostPort, gameState, gameName, ownerName, creatorName, creatorServer ); - else - m_CurrentGame = new CGame( this, map, NULL, m_HostPort, gameState, gameName, ownerName, creatorName, creatorServer ); - - // todotodo: check if listening failed and report the error to the user - - if( m_SaveGame ) - { - m_CurrentGame->SetEnforcePlayers( m_EnforcePlayers ); - m_EnforcePlayers.clear( ); - } - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( whisper && (*i)->GetServer( ) == creatorServer ) - { - // note that we send this whisper only on the creator server - - if( gameState == GAME_PRIVATE ) - (*i)->QueueChatCommand( m_Language->CreatingPrivateGame( gameName, ownerName ), creatorName, whisper ); - else if( gameState == GAME_PUBLIC ) - (*i)->QueueChatCommand( m_Language->CreatingPublicGame( gameName, ownerName ), creatorName, whisper ); - } - else - { - // note that we send this chat message on all other bnet servers - - if( gameState == GAME_PRIVATE ) - (*i)->QueueChatCommand( m_Language->CreatingPrivateGame( gameName, ownerName ) ); - else if( gameState == GAME_PUBLIC ) - (*i)->QueueChatCommand( m_Language->CreatingPublicGame( gameName, ownerName ) ); - } - - if( saveGame ) - (*i)->QueueGameCreate( gameState, gameName, string( ), map, m_SaveGame, m_CurrentGame->GetHostCounter( ) ); - else - (*i)->QueueGameCreate( gameState, gameName, string( ), map, NULL, m_CurrentGame->GetHostCounter( ) ); - } - - if( m_AdminGame ) - { - if( gameState == GAME_PRIVATE ) - m_AdminGame->SendAllChat( m_Language->CreatingPrivateGame( gameName, ownerName ) ); - else if( gameState == GAME_PUBLIC ) - m_AdminGame->SendAllChat( m_Language->CreatingPublicGame( gameName, ownerName ) ); - } - - // if we're creating a private game we don't need to send any game refresh messages so we can rejoin the chat immediately - // unfortunately this doesn't work on PVPGN servers because they consider an enterchat message to be a gameuncreate message when in a game - // so don't rejoin the chat if we're using PVPGN - - if( gameState == GAME_PRIVATE ) - { - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetPasswordHashType( ) != "pvpgn" ) - (*i)->QueueEnterChat( ); - } - } - - // hold friends and/or clan members - - for( vector :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) - { - if( (*i)->GetHoldFriends( ) ) - (*i)->HoldFriends( m_CurrentGame ); - - if( (*i)->GetHoldClan( ) ) - (*i)->HoldClan( m_CurrentGame ); - } -} diff --git a/ghost/ghost.h b/ghost/ghost.h deleted file mode 100644 index 7e84ce3..0000000 --- a/ghost/ghost.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GHOST_H -#define GHOST_H - -#include "includes.h" - -// -// CGHost -// - -class CUDPSocket; -class CTCPServer; -class CTCPSocket; -class CGPSProtocol; -class CCRC32; -class CSHA1; -class CBNET; -class CBaseGame; -class CAdminGame; -class CGHostDB; -class CBaseCallable; -class CLanguage; -class CMap; -class CSaveGame; -class CConfig; - -class CGHost -{ -public: - CUDPSocket *m_UDPSocket; // a UDP socket for sending broadcasts and other junk (used with !sendlan) - CTCPServer *m_ReconnectSocket; // listening socket for GProxy++ reliable reconnects - vector m_ReconnectSockets;// vector of sockets attempting to reconnect (connected but not identified yet) - CGPSProtocol *m_GPSProtocol; - CCRC32 *m_CRC; // for calculating CRC's - CSHA1 *m_SHA; // for calculating SHA1's - vector m_BNETs; // all our battle.net connections (there can be more than one) - CBaseGame *m_CurrentGame; // this game is still in the lobby state - CAdminGame *m_AdminGame; // this "fake game" allows an admin who knows the password to control the bot from the local network - vector m_Games; // these games are in progress - CGHostDB *m_DB; // database - CGHostDB *m_DBLocal; // local database (for temporary data) - vector m_Callables; // vector of orphaned callables waiting to die - vector m_LocalAddresses; // vector of local IP addresses - CLanguage *m_Language; // language - CMap *m_Map; // the currently loaded map - CMap *m_AdminMap; // the map to use in the admin game - CMap *m_AutoHostMap; // the map to use when autohosting - CSaveGame *m_SaveGame; // the save game to use - vector m_EnforcePlayers; // vector of pids to force players to use in the next game (used with saved games) - bool m_Exiting; // set to true to force ghost to shutdown next update (used by SignalCatcher) - bool m_ExitingNice; // set to true to force ghost to disconnect from all battle.net connections and wait for all games to finish before shutting down - bool m_Enabled; // set to false to prevent new games from being created - string m_Version; // GHost++ version string - uint32_t m_HostCounter; // the current host counter (a unique number to identify a game, incremented each time a game is created) - string m_AutoHostGameName; // the base game name to auto host with - string m_AutoHostOwner; - string m_AutoHostServer; - uint32_t m_AutoHostMaximumGames; // maximum number of games to auto host - uint32_t m_AutoHostAutoStartPlayers; // when using auto hosting auto start the game when this many players have joined - uint32_t m_LastAutoHostTime; // GetTime when the last auto host was attempted - bool m_AutoHostMatchMaking; - double m_AutoHostMinimumScore; - double m_AutoHostMaximumScore; - bool m_AllGamesFinished; // if all games finished (used when exiting nicely) - uint32_t m_AllGamesFinishedTime; // GetTime when all games finished (used when exiting nicely) - string m_LanguageFile; // config value: language file - string m_Warcraft3Path; // config value: Warcraft 3 path - bool m_TFT; // config value: TFT enabled or not - string m_BindAddress; // config value: the address to host games on - uint16_t m_HostPort; // config value: the port to host games on - bool m_Reconnect; // config value: GProxy++ reliable reconnects enabled or not - uint16_t m_ReconnectPort; // config value: the port to listen for GProxy++ reliable reconnects on - uint32_t m_ReconnectWaitTime; // config value: the maximum number of minutes to wait for a GProxy++ reliable reconnect - uint32_t m_MaxGames; // config value: maximum number of games in progress - char m_CommandTrigger; // config value: the command trigger inside games - string m_MapCFGPath; // config value: map cfg path - string m_SaveGamePath; // config value: savegame path - string m_MapPath; // config value: map path - bool m_SaveReplays; // config value: save replays - string m_ReplayPath; // config value: replay path - string m_VirtualHostName; // config value: virtual host name - bool m_HideIPAddresses; // config value: hide IP addresses from players - bool m_CheckMultipleIPUsage; // config value: check for multiple IP address usage - uint32_t m_SpoofChecks; // config value: do automatic spoof checks or not - bool m_RequireSpoofChecks; // config value: require spoof checks or not - bool m_ReserveAdmins; // config value: consider admins to be reserved players or not - bool m_RefreshMessages; // config value: display refresh messages or not (by default) - bool m_AutoLock; // config value: auto lock games when the owner is present - bool m_AutoSave; // config value: auto save before someone disconnects - uint32_t m_AllowDownloads; // config value: allow map downloads or not - bool m_PingDuringDownloads; // config value: ping during map downloads or not - uint32_t m_MaxDownloaders; // config value: maximum number of map downloaders at the same time - uint32_t m_MaxDownloadSpeed; // config value: maximum total map download speed in KB/sec - bool m_LCPings; // config value: use LC style pings (divide actual pings by two) - uint32_t m_AutoKickPing; // config value: auto kick players with ping higher than this - uint32_t m_BanMethod; // config value: ban method (ban by name/ip/both) - string m_IPBlackListFile; // config value: IP blacklist file (ipblacklist.txt) - uint32_t m_LobbyTimeLimit; // config value: auto close the game lobby after this many minutes without any reserved players - uint32_t m_Latency; // config value: the latency (by default) - uint32_t m_SyncLimit; // config value: the maximum number of packets a player can fall out of sync before starting the lag screen (by default) - bool m_VoteKickAllowed; // config value: if votekicks are allowed or not - uint32_t m_VoteKickPercentage; // config value: percentage of players required to vote yes for a votekick to pass - string m_DefaultMap; // config value: default map (map.cfg) - string m_MOTDFile; // config value: motd.txt - string m_GameLoadedFile; // config value: gameloaded.txt - string m_GameOverFile; // config value: gameover.txt - bool m_LocalAdminMessages; // config value: send local admin messages or not - bool m_AdminGameCreate; // config value: create the admin game or not - uint16_t m_AdminGamePort; // config value: the port to host the admin game on - string m_AdminGamePassword; // config value: the admin game password - string m_AdminGameMap; // config value: the admin game map config to use - unsigned char m_LANWar3Version; // config value: LAN warcraft 3 version - uint32_t m_ReplayWar3Version; // config value: replay warcraft 3 version (for saving replays) - uint32_t m_ReplayBuildNumber; // config value: replay build number (for saving replays) - bool m_TCPNoDelay; // config value: use Nagle's algorithm or not - uint32_t m_MatchMakingMethod; // config value: the matchmaking method - - CGHost( CConfig *CFG ); - ~CGHost( ); - - // processing functions - - bool Update( long usecBlock ); - - // events - - void EventBNETConnecting( CBNET *bnet ); - void EventBNETConnected( CBNET *bnet ); - void EventBNETDisconnected( CBNET *bnet ); - void EventBNETLoggedIn( CBNET *bnet ); - void EventBNETGameRefreshed( CBNET *bnet ); - void EventBNETGameRefreshFailed( CBNET *bnet ); - void EventBNETConnectTimedOut( CBNET *bnet ); - void EventBNETWhisper( CBNET *bnet, string user, string message ); - void EventBNETChat( CBNET *bnet, string user, string message ); - void EventBNETEmote( CBNET *bnet, string user, string message ); - void EventGameDeleted( CBaseGame *game ); - - // other functions - - void ReloadConfigs( ); - void SetConfigs( CConfig *CFG ); - void ExtractScripts( ); - void LoadIPToCountryData( ); - void CreateGame( CMap *map, unsigned char gameState, bool saveGame, string gameName, string ownerName, string creatorName, string creatorServer, bool whisper ); -}; - -#endif diff --git a/ghost/ghostdb.cpp b/ghost/ghostdb.cpp deleted file mode 100644 index 43ec7df..0000000 --- a/ghost/ghostdb.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "config.h" -#include "ghostdb.h" - -// -// CGHostDB -// - -CGHostDB :: CGHostDB( CConfig *CFG ) -{ - m_HasError = false; -} - -CGHostDB :: ~CGHostDB( ) -{ - -} - -void CGHostDB :: RecoverCallable( CBaseCallable *callable ) -{ - -} - -bool CGHostDB :: Begin( ) -{ - return true; -} - -bool CGHostDB :: Commit( ) -{ - return true; -} - -uint32_t CGHostDB :: AdminCount( string server ) -{ - return 0; -} - -bool CGHostDB :: AdminCheck( string server, string user ) -{ - return false; -} - -bool CGHostDB :: AdminAdd( string server, string user ) -{ - return false; -} - -bool CGHostDB :: AdminRemove( string server, string user ) -{ - return false; -} - -vector CGHostDB :: AdminList( string server ) -{ - return vector( ); -} - -uint32_t CGHostDB :: BanCount( string server ) -{ - return 0; -} - -CDBBan *CGHostDB :: BanCheck( string server, string user, string ip ) -{ - return NULL; -} - -bool CGHostDB :: BanAdd( string server, string user, string ip, string gamename, string admin, string reason ) -{ - return false; -} - -bool CGHostDB :: BanRemove( string server, string user ) -{ - return false; -} - -bool CGHostDB :: BanRemove( string user ) -{ - return false; -} - -vector CGHostDB :: BanList( string server ) -{ - return vector( ); -} - -uint32_t CGHostDB :: GameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) -{ - return 0; -} - -uint32_t CGHostDB :: GamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) -{ - return 0; -} - -uint32_t CGHostDB :: GamePlayerCount( string name ) -{ - return 0; -} - -CDBGamePlayerSummary *CGHostDB :: GamePlayerSummaryCheck( string name ) -{ - return NULL; -} - -uint32_t CGHostDB :: DotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) -{ - return 0; -} - -uint32_t CGHostDB :: DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) -{ - return 0; -} - -uint32_t CGHostDB :: DotAPlayerCount( string name ) -{ - return 0; -} - -CDBDotAPlayerSummary *CGHostDB :: DotAPlayerSummaryCheck( string name ) -{ - return NULL; -} - -string CGHostDB :: FromCheck( uint32_t ip ) -{ - return "??"; -} - -bool CGHostDB :: FromAdd( uint32_t ip1, uint32_t ip2, string country ) -{ - return false; -} - -bool CGHostDB :: DownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) -{ - return false; -} - -uint32_t CGHostDB :: W3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) -{ - return 0; -} - -bool CGHostDB :: W3MMDVarAdd( uint32_t gameid, map var_ints ) -{ - return false; -} - -bool CGHostDB :: W3MMDVarAdd( uint32_t gameid, map var_reals ) -{ - return false; -} - -bool CGHostDB :: W3MMDVarAdd( uint32_t gameid, map var_strings ) -{ - return false; -} - -void CGHostDB :: CreateThread( CBaseCallable *callable ) -{ - callable->SetReady( true ); -} - -CCallableAdminCount *CGHostDB :: ThreadedAdminCount( string server ) -{ - return NULL; -} - -CCallableAdminCheck *CGHostDB :: ThreadedAdminCheck( string server, string user ) -{ - return NULL; -} - -CCallableAdminAdd *CGHostDB :: ThreadedAdminAdd( string server, string user ) -{ - return NULL; -} - -CCallableAdminRemove *CGHostDB :: ThreadedAdminRemove( string server, string user ) -{ - return NULL; -} - -CCallableAdminList *CGHostDB :: ThreadedAdminList( string server ) -{ - return NULL; -} - -CCallableBanCount *CGHostDB :: ThreadedBanCount( string server ) -{ - return NULL; -} - -CCallableBanCheck *CGHostDB :: ThreadedBanCheck( string server, string user, string ip ) -{ - return NULL; -} - -CCallableBanAdd *CGHostDB :: ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ) -{ - return NULL; -} - -CCallableBanRemove *CGHostDB :: ThreadedBanRemove( string server, string user ) -{ - return NULL; -} - -CCallableBanRemove *CGHostDB :: ThreadedBanRemove( string user ) -{ - return NULL; -} - -CCallableBanList *CGHostDB :: ThreadedBanList( string server ) -{ - return NULL; -} - -CCallableGameAdd *CGHostDB :: ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) -{ - return NULL; -} - -CCallableGamePlayerAdd *CGHostDB :: ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) -{ - return NULL; -} - -CCallableGamePlayerSummaryCheck *CGHostDB :: ThreadedGamePlayerSummaryCheck( string name ) -{ - return NULL; -} - -CCallableDotAGameAdd *CGHostDB :: ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) -{ - return NULL; -} - -CCallableDotAPlayerAdd *CGHostDB :: ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) -{ - return NULL; -} - -CCallableDotAPlayerSummaryCheck *CGHostDB :: ThreadedDotAPlayerSummaryCheck( string name ) -{ - return NULL; -} - -CCallableDownloadAdd *CGHostDB :: ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) -{ - return NULL; -} - -CCallableScoreCheck *CGHostDB :: ThreadedScoreCheck( string category, string name, string server ) -{ - return NULL; -} - -CCallableW3MMDPlayerAdd *CGHostDB :: ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) -{ - return NULL; -} - -CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ) -{ - return NULL; -} - -CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ) -{ - return NULL; -} - -CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ) -{ - return NULL; -} - -// -// Callables -// - -void CBaseCallable :: Init( ) -{ - m_StartTicks = GetTicks( ); -} - -void CBaseCallable :: Close( ) -{ - m_EndTicks = GetTicks( ); - m_Ready = true; -} - -CCallableAdminCount :: ~CCallableAdminCount( ) -{ - -} - -CCallableAdminCheck :: ~CCallableAdminCheck( ) -{ - -} - -CCallableAdminAdd :: ~CCallableAdminAdd( ) -{ - -} - -CCallableAdminRemove :: ~CCallableAdminRemove( ) -{ - -} - -CCallableAdminList :: ~CCallableAdminList( ) -{ - -} - -CCallableBanCount :: ~CCallableBanCount( ) -{ - -} - -CCallableBanCheck :: ~CCallableBanCheck( ) -{ - delete m_Result; -} - -CCallableBanAdd :: ~CCallableBanAdd( ) -{ - -} - -CCallableBanRemove :: ~CCallableBanRemove( ) -{ - -} - -CCallableBanList :: ~CCallableBanList( ) -{ - // don't delete anything in m_Result here, it's the caller's responsibility -} - -CCallableGameAdd :: ~CCallableGameAdd( ) -{ - -} - -CCallableGamePlayerAdd :: ~CCallableGamePlayerAdd( ) -{ - -} - -CCallableGamePlayerSummaryCheck :: ~CCallableGamePlayerSummaryCheck( ) -{ - delete m_Result; -} - -CCallableDotAGameAdd :: ~CCallableDotAGameAdd( ) -{ - -} - -CCallableDotAPlayerAdd :: ~CCallableDotAPlayerAdd( ) -{ - -} - -CCallableDotAPlayerSummaryCheck :: ~CCallableDotAPlayerSummaryCheck( ) -{ - delete m_Result; -} - -CCallableDownloadAdd :: ~CCallableDownloadAdd( ) -{ - -} - -CCallableScoreCheck :: ~CCallableScoreCheck( ) -{ - -} - -CCallableW3MMDPlayerAdd :: ~CCallableW3MMDPlayerAdd( ) -{ - -} - -CCallableW3MMDVarAdd :: ~CCallableW3MMDVarAdd( ) -{ - -} - -// -// CDBBan -// - -CDBBan :: CDBBan( string nServer, string nName, string nIP, string nDate, string nGameName, string nAdmin, string nReason ) -{ - m_Server = nServer; - m_Name = nName; - m_IP = nIP; - m_Date = nDate; - m_GameName = nGameName; - m_Admin = nAdmin; - m_Reason = nReason; -} - -CDBBan :: ~CDBBan( ) -{ - -} - -// -// CDBGame -// - -CDBGame :: CDBGame( uint32_t nID, string nServer, string nMap, string nDateTime, string nGameName, string nOwnerName, uint32_t nDuration ) -{ - m_ID = nID; - m_Server = nServer; - m_Map = nMap; - m_DateTime = nDateTime; - m_GameName = nGameName; - m_OwnerName = nOwnerName; - m_Duration = nDuration; -} - -CDBGame :: ~CDBGame( ) -{ - -} - -// -// CDBGamePlayer -// - -CDBGamePlayer :: CDBGamePlayer( uint32_t nID, uint32_t nGameID, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nReserved, uint32_t nLoadingTime, uint32_t nLeft, string nLeftReason, uint32_t nTeam, uint32_t nColour ) -{ - m_ID = nID; - m_GameID = nGameID; - m_Name = nName; - m_IP = nIP; - m_Spoofed = nSpoofed; - m_SpoofedRealm = nSpoofedRealm; - m_Reserved = nReserved; - m_LoadingTime = nLoadingTime; - m_Left = nLeft; - m_LeftReason = nLeftReason; - m_Team = nTeam; - m_Colour = nColour; -} - -CDBGamePlayer :: ~CDBGamePlayer( ) -{ - -} - -// -// CDBGamePlayerSummary -// - -CDBGamePlayerSummary :: CDBGamePlayerSummary( string nServer, string nName, string nFirstGameDateTime, string nLastGameDateTime, uint32_t nTotalGames, uint32_t nMinLoadingTime, uint32_t nAvgLoadingTime, uint32_t nMaxLoadingTime, uint32_t nMinLeftPercent, uint32_t nAvgLeftPercent, uint32_t nMaxLeftPercent, uint32_t nMinDuration, uint32_t nAvgDuration, uint32_t nMaxDuration ) -{ - m_Server = nServer; - m_Name = nName; - m_FirstGameDateTime = nFirstGameDateTime; - m_LastGameDateTime = nLastGameDateTime; - m_TotalGames = nTotalGames; - m_MinLoadingTime = nMinLoadingTime; - m_AvgLoadingTime = nAvgLoadingTime; - m_MaxLoadingTime = nMaxLoadingTime; - m_MinLeftPercent = nMinLeftPercent; - m_AvgLeftPercent = nAvgLeftPercent; - m_MaxLeftPercent = nMaxLeftPercent; - m_MinDuration = nMinDuration; - m_AvgDuration = nAvgDuration; - m_MaxDuration = nMaxDuration; -} - -CDBGamePlayerSummary :: ~CDBGamePlayerSummary( ) -{ - -} - -// -// CDBDotAGame -// - -CDBDotAGame :: CDBDotAGame( uint32_t nID, uint32_t nGameID, uint32_t nWinner, uint32_t nMin, uint32_t nSec ) -{ - m_ID = nID; - m_GameID = nGameID; - m_Winner = nWinner; - m_Min = nMin; - m_Sec = nSec; -} - -CDBDotAGame :: ~CDBDotAGame( ) -{ - -} - -// -// CDBDotAPlayer -// - -CDBDotAPlayer :: CDBDotAPlayer( ) -{ - m_ID = 0; - m_GameID = 0; - m_Colour = 0; - m_Kills = 0; - m_Deaths = 0; - m_CreepKills = 0; - m_CreepDenies = 0; - m_Assists = 0; - m_Gold = 0; - m_NeutralKills = 0; - m_NewColour = 0; - m_TowerKills = 0; - m_RaxKills = 0; - m_CourierKills = 0; -} - -CDBDotAPlayer :: CDBDotAPlayer( uint32_t nID, uint32_t nGameID, uint32_t nColour, uint32_t nKills, uint32_t nDeaths, uint32_t nCreepKills, uint32_t nCreepDenies, uint32_t nAssists, uint32_t nGold, uint32_t nNeutralKills, string nItem1, string nItem2, string nItem3, string nItem4, string nItem5, string nItem6, string nHero, uint32_t nNewColour, uint32_t nTowerKills, uint32_t nRaxKills, uint32_t nCourierKills ) -{ - m_ID = nID; - m_GameID = nGameID; - m_Colour = nColour; - m_Kills = nKills; - m_Deaths = nDeaths; - m_CreepKills = nCreepKills; - m_CreepDenies = nCreepDenies; - m_Assists = nAssists; - m_Gold = nGold; - m_NeutralKills = nNeutralKills; - m_Items[0] = nItem1; - m_Items[1] = nItem2; - m_Items[2] = nItem3; - m_Items[3] = nItem4; - m_Items[4] = nItem5; - m_Items[5] = nItem6; - m_Hero = nHero; - m_NewColour = nNewColour; - m_TowerKills = nTowerKills; - m_RaxKills = nRaxKills; - m_CourierKills = nCourierKills; -} - -CDBDotAPlayer :: ~CDBDotAPlayer( ) -{ - -} - -string CDBDotAPlayer :: GetItem( unsigned int i ) -{ - if( i < 6 ) - return m_Items[i]; - - return string( ); -} - -void CDBDotAPlayer :: SetItem( unsigned int i, string item ) -{ - if( i < 6 ) - m_Items[i] = item; -} - -// -// CDBDotAPlayerSummary -// - -CDBDotAPlayerSummary :: CDBDotAPlayerSummary( string nServer, string nName, uint32_t nTotalGames, uint32_t nTotalWins, uint32_t nTotalLosses, uint32_t nTotalKills, uint32_t nTotalDeaths, uint32_t nTotalCreepKills, uint32_t nTotalCreepDenies, uint32_t nTotalAssists, uint32_t nTotalNeutralKills, uint32_t nTotalTowerKills, uint32_t nTotalRaxKills, uint32_t nTotalCourierKills ) -{ - m_Server = nServer; - m_Name = nName; - m_TotalGames = nTotalGames; - m_TotalWins = nTotalWins; - m_TotalLosses = nTotalLosses; - m_TotalKills = nTotalKills; - m_TotalDeaths = nTotalDeaths; - m_TotalCreepKills = nTotalCreepKills; - m_TotalCreepDenies = nTotalCreepDenies; - m_TotalAssists = nTotalAssists; - m_TotalNeutralKills = nTotalNeutralKills; - m_TotalTowerKills = nTotalTowerKills; - m_TotalRaxKills = nTotalRaxKills; - m_TotalCourierKills = nTotalCourierKills; -} - -CDBDotAPlayerSummary :: ~CDBDotAPlayerSummary( ) -{ - -} diff --git a/ghost/ghostdb.h b/ghost/ghostdb.h deleted file mode 100644 index 48934f9..0000000 --- a/ghost/ghostdb.h +++ /dev/null @@ -1,837 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GHOSTDB_H -#define GHOSTDB_H - -// -// CGHostDB -// - -class CBaseCallable; -class CCallableAdminCount; -class CCallableAdminCheck; -class CCallableAdminAdd; -class CCallableAdminRemove; -class CCallableAdminList; -class CCallableBanCount; -class CCallableBanCheck; -class CCallableBanAdd; -class CCallableBanRemove; -class CCallableBanList; -class CCallableGameAdd; -class CCallableGamePlayerAdd; -class CCallableGamePlayerSummaryCheck; -class CCallableDotAGameAdd; -class CCallableDotAPlayerAdd; -class CCallableDotAPlayerSummaryCheck; -class CCallableDownloadAdd; -class CCallableScoreCheck; -class CCallableW3MMDPlayerAdd; -class CCallableW3MMDVarAdd; -class CDBBan; -class CDBGame; -class CDBGamePlayer; -class CDBGamePlayerSummary; -class CDBDotAPlayerSummary; - -typedef pair VarP; - -class CGHostDB -{ -protected: - bool m_HasError; - string m_Error; - -public: - CGHostDB( CConfig *CFG ); - virtual ~CGHostDB( ); - - bool HasError( ) { return m_HasError; } - string GetError( ) { return m_Error; } - virtual string GetStatus( ) { return "DB STATUS --- OK"; } - - virtual void RecoverCallable( CBaseCallable *callable ); - - // standard (non-threaded) database functions - - virtual bool Begin( ); - virtual bool Commit( ); - virtual uint32_t AdminCount( string server ); - virtual bool AdminCheck( string server, string user ); - virtual bool AdminAdd( string server, string user ); - virtual bool AdminRemove( string server, string user ); - virtual vector AdminList( string server ); - virtual uint32_t BanCount( string server ); - virtual CDBBan *BanCheck( string server, string user, string ip ); - virtual bool BanAdd( string server, string user, string ip, string gamename, string admin, string reason ); - virtual bool BanRemove( string server, string user ); - virtual bool BanRemove( string user ); - virtual vector BanList( string server ); - virtual uint32_t GameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); - virtual uint32_t GamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); - virtual uint32_t GamePlayerCount( string name ); - virtual CDBGamePlayerSummary *GamePlayerSummaryCheck( string name ); - virtual uint32_t DotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); - virtual uint32_t DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); - virtual uint32_t DotAPlayerCount( string name ); - virtual CDBDotAPlayerSummary *DotAPlayerSummaryCheck( string name ); - virtual string FromCheck( uint32_t ip ); - virtual bool FromAdd( uint32_t ip1, uint32_t ip2, string country ); - virtual bool DownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); - virtual uint32_t W3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_ints ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_reals ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_strings ); - - // threaded database functions - - virtual void CreateThread( CBaseCallable *callable ); - virtual CCallableAdminCount *ThreadedAdminCount( string server ); - virtual CCallableAdminCheck *ThreadedAdminCheck( string server, string user ); - virtual CCallableAdminAdd *ThreadedAdminAdd( string server, string user ); - virtual CCallableAdminRemove *ThreadedAdminRemove( string server, string user ); - virtual CCallableAdminList *ThreadedAdminList( string server ); - virtual CCallableBanCount *ThreadedBanCount( string server ); - virtual CCallableBanCheck *ThreadedBanCheck( string server, string user, string ip ); - virtual CCallableBanAdd *ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ); - virtual CCallableBanRemove *ThreadedBanRemove( string server, string user ); - virtual CCallableBanRemove *ThreadedBanRemove( string user ); - virtual CCallableBanList *ThreadedBanList( string server ); - virtual CCallableGameAdd *ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); - virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); - virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( string name ); - virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); - virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); - virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( string name ); - virtual CCallableDownloadAdd *ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); - virtual CCallableScoreCheck *ThreadedScoreCheck( string category, string name, string server ); - virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ); -}; - -// -// Callables -// - -// life cycle of a callable: -// - the callable is created in one of the database's ThreadedXXX functions -// - initially the callable is NOT ready (i.e. m_Ready = false) -// - the ThreadedXXX function normally creates a thread to perform some query and (potentially) store some result in the callable -// - at the time of this writing all threads are immediately detached, the code does not join any threads (the callable's "readiness" is used for this purpose instead) -// - when the thread completes it will set m_Ready = true -// - DO NOT DO *ANYTHING* TO THE CALLABLE UNTIL IT'S READY OR YOU WILL CREATE A CONCURRENCY MESS -// - THE ONLY SAFE FUNCTION IN THE CALLABLE IS GetReady -// - when the callable is ready you may access the callable's result which will have been set within the (now terminated) thread - -// example usage: -// - normally you will call a ThreadedXXX function, store the callable in a vector, and periodically check if the callable is ready -// - when the callable is ready you will consume the result then you will pass the callable back to the database via the RecoverCallable function -// - the RecoverCallable function allows the database to recover some of the callable's resources to be reused later (e.g. MySQL connections) -// - note that this will NOT free the callable's memory, you must do that yourself after calling the RecoverCallable function -// - be careful not to leak any callables, it's NOT safe to delete a callable even if you decide that you don't want the result anymore -// - you should deliver any to-be-orphaned callables to the main vector in CGHost so they can be properly deleted when ready even if you don't care about the result anymore -// - e.g. if a player does a stats check immediately before a game is deleted you can't just delete the callable on game deletion unless it's ready - -class CBaseCallable -{ -protected: - string m_Error; - volatile bool m_Ready; - uint32_t m_StartTicks; - uint32_t m_EndTicks; - -public: - CBaseCallable( ) : m_Error( ), m_Ready( false ), m_StartTicks( 0 ), m_EndTicks( 0 ) { } - virtual ~CBaseCallable( ) { } - - virtual void operator( )( ) { } - - virtual void Init( ); - virtual void Close( ); - - virtual string GetError( ) { return m_Error; } - virtual bool GetReady( ) { return m_Ready; } - virtual void SetReady( bool nReady ) { m_Ready = nReady; } - virtual uint32_t GetElapsed( ) { return m_Ready ? m_EndTicks - m_StartTicks : 0; } -}; - -class CCallableAdminCount : virtual public CBaseCallable -{ -protected: - string m_Server; - uint32_t m_Result; - -public: - CCallableAdminCount( string nServer ) : CBaseCallable( ), m_Server( nServer ), m_Result( 0 ) { } - virtual ~CCallableAdminCount( ); - - virtual string GetServer( ) { return m_Server; } - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableAdminCheck : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - bool m_Result; - -public: - CCallableAdminCheck( string nServer, string nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } - virtual ~CCallableAdminCheck( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableAdminAdd : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - bool m_Result; - -public: - CCallableAdminAdd( string nServer, string nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } - virtual ~CCallableAdminAdd( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableAdminRemove : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - bool m_Result; - -public: - CCallableAdminRemove( string nServer, string nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } - virtual ~CCallableAdminRemove( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableAdminList : virtual public CBaseCallable -{ -protected: - string m_Server; - vector m_Result; - -public: - CCallableAdminList( string nServer ) : CBaseCallable( ), m_Server( nServer ) { } - virtual ~CCallableAdminList( ); - - virtual vector GetResult( ) { return m_Result; } - virtual void SetResult( vector nResult ) { m_Result = nResult; } -}; - -class CCallableBanCount : virtual public CBaseCallable -{ -protected: - string m_Server; - uint32_t m_Result; - -public: - CCallableBanCount( string nServer ) : CBaseCallable( ), m_Server( nServer ), m_Result( 0 ) { } - virtual ~CCallableBanCount( ); - - virtual string GetServer( ) { return m_Server; } - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableBanCheck : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - string m_IP; - CDBBan *m_Result; - -public: - CCallableBanCheck( string nServer, string nUser, string nIP ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_IP( nIP ), m_Result( NULL ) { } - virtual ~CCallableBanCheck( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual string GetIP( ) { return m_IP; } - virtual CDBBan *GetResult( ) { return m_Result; } - virtual void SetResult( CDBBan *nResult ) { m_Result = nResult; } -}; - -class CCallableBanAdd : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - string m_IP; - string m_GameName; - string m_Admin; - string m_Reason; - bool m_Result; - -public: - CCallableBanAdd( string nServer, string nUser, string nIP, string nGameName, string nAdmin, string nReason ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_IP( nIP ), m_GameName( nGameName ), m_Admin( nAdmin ), m_Reason( nReason ), m_Result( false ) { } - virtual ~CCallableBanAdd( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual string GetIP( ) { return m_IP; } - virtual string GetGameName( ) { return m_GameName; } - virtual string GetAdmin( ) { return m_Admin; } - virtual string GetReason( ) { return m_Reason; } - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableBanRemove : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_User; - bool m_Result; - -public: - CCallableBanRemove( string nServer, string nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } - virtual ~CCallableBanRemove( ); - - virtual string GetServer( ) { return m_Server; } - virtual string GetUser( ) { return m_User; } - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableBanList : virtual public CBaseCallable -{ -protected: - string m_Server; - vector m_Result; - -public: - CCallableBanList( string nServer ) : CBaseCallable( ), m_Server( nServer ) { } - virtual ~CCallableBanList( ); - - virtual vector GetResult( ) { return m_Result; } - virtual void SetResult( vector nResult ) { m_Result = nResult; } -}; - -class CCallableGameAdd : virtual public CBaseCallable -{ -protected: - string m_Server; - string m_Map; - string m_GameName; - string m_OwnerName; - uint32_t m_Duration; - uint32_t m_GameState; - string m_CreatorName; - string m_CreatorServer; - uint32_t m_Result; - -public: - CCallableGameAdd( string nServer, string nMap, string nGameName, string nOwnerName, uint32_t nDuration, uint32_t nGameState, string nCreatorName, string nCreatorServer ) : CBaseCallable( ), m_Server( nServer ), m_Map( nMap ), m_GameName( nGameName ), m_OwnerName( nOwnerName ), m_Duration( nDuration ), m_GameState( nGameState ), m_CreatorName( nCreatorName ), m_CreatorServer( nCreatorServer ), m_Result( 0 ) { } - virtual ~CCallableGameAdd( ); - - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableGamePlayerAdd : virtual public CBaseCallable -{ -protected: - uint32_t m_GameID; - string m_Name; - string m_IP; - uint32_t m_Spoofed; - string m_SpoofedRealm; - uint32_t m_Reserved; - uint32_t m_LoadingTime; - uint32_t m_Left; - string m_LeftReason; - uint32_t m_Team; - uint32_t m_Colour; - uint32_t m_Result; - -public: - CCallableGamePlayerAdd( uint32_t nGameID, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nReserved, uint32_t nLoadingTime, uint32_t nLeft, string nLeftReason, uint32_t nTeam, uint32_t nColour ) : CBaseCallable( ), m_GameID( nGameID ), m_Name( nName ), m_IP( nIP ), m_Spoofed( nSpoofed ), m_SpoofedRealm( nSpoofedRealm ), m_Reserved( nReserved ), m_LoadingTime( nLoadingTime ), m_Left( nLeft ), m_LeftReason( nLeftReason ), m_Team( nTeam ), m_Colour( nColour ), m_Result( 0 ) { } - virtual ~CCallableGamePlayerAdd( ); - - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableGamePlayerSummaryCheck : virtual public CBaseCallable -{ -protected: - string m_Name; - CDBGamePlayerSummary *m_Result; - -public: - CCallableGamePlayerSummaryCheck( string nName ) : CBaseCallable( ), m_Name( nName ), m_Result( NULL ) { } - virtual ~CCallableGamePlayerSummaryCheck( ); - - virtual string GetName( ) { return m_Name; } - virtual CDBGamePlayerSummary *GetResult( ) { return m_Result; } - virtual void SetResult( CDBGamePlayerSummary *nResult ) { m_Result = nResult; } -}; - -class CCallableDotAGameAdd : virtual public CBaseCallable -{ -protected: - uint32_t m_GameID; - uint32_t m_Winner; - uint32_t m_Min; - uint32_t m_Sec; - uint32_t m_Result; - -public: - CCallableDotAGameAdd( uint32_t nGameID, uint32_t nWinner, uint32_t nMin, uint32_t nSec ) : CBaseCallable( ), m_GameID( nGameID ), m_Winner( nWinner ), m_Min( nMin ), m_Sec( nSec ), m_Result( 0 ) { } - virtual ~CCallableDotAGameAdd( ); - - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableDotAPlayerAdd : virtual public CBaseCallable -{ -protected: - uint32_t m_GameID; - uint32_t m_Colour; - uint32_t m_Kills; - uint32_t m_Deaths; - uint32_t m_CreepKills; - uint32_t m_CreepDenies; - uint32_t m_Assists; - uint32_t m_Gold; - uint32_t m_NeutralKills; - string m_Item1; - string m_Item2; - string m_Item3; - string m_Item4; - string m_Item5; - string m_Item6; - string m_Hero; - uint32_t m_NewColour; - uint32_t m_TowerKills; - uint32_t m_RaxKills; - uint32_t m_CourierKills; - uint32_t m_Result; - -public: - CCallableDotAPlayerAdd( uint32_t nGameID, uint32_t nColour, uint32_t nKills, uint32_t nDeaths, uint32_t nCreepKills, uint32_t nCreepDenies, uint32_t nAssists, uint32_t nGold, uint32_t nNeutralKills, string nItem1, string nItem2, string nItem3, string nItem4, string nItem5, string nItem6, string nHero, uint32_t nNewColour, uint32_t nTowerKills, uint32_t nRaxKills, uint32_t nCourierKills ) : CBaseCallable( ), m_GameID( nGameID ), m_Colour( nColour ), m_Kills( nKills ), m_Deaths( nDeaths ), m_CreepKills( nCreepKills ), m_CreepDenies( nCreepDenies ), m_Assists( nAssists ), m_Gold( nGold ), m_NeutralKills( nNeutralKills ), m_Item1( nItem1 ), m_Item2( nItem2 ), m_Item3( nItem3 ), m_Item4( nItem4 ), m_Item5( nItem5 ), m_Item6( nItem6 ), m_Hero( nHero ), m_NewColour( nNewColour ), m_TowerKills( nTowerKills ), m_RaxKills( nRaxKills ), m_CourierKills( nCourierKills ), m_Result( 0 ) { } - virtual ~CCallableDotAPlayerAdd( ); - - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableDotAPlayerSummaryCheck : virtual public CBaseCallable -{ -protected: - string m_Name; - CDBDotAPlayerSummary *m_Result; - -public: - CCallableDotAPlayerSummaryCheck( string nName ) : CBaseCallable( ), m_Name( nName ), m_Result( NULL ) { } - virtual ~CCallableDotAPlayerSummaryCheck( ); - - virtual string GetName( ) { return m_Name; } - virtual CDBDotAPlayerSummary *GetResult( ) { return m_Result; } - virtual void SetResult( CDBDotAPlayerSummary *nResult ) { m_Result = nResult; } -}; - -class CCallableDownloadAdd : virtual public CBaseCallable -{ -protected: - string m_Map; - uint32_t m_MapSize; - string m_Name; - string m_IP; - uint32_t m_Spoofed; - string m_SpoofedRealm; - uint32_t m_DownloadTime; - bool m_Result; - -public: - CCallableDownloadAdd( string nMap, uint32_t nMapSize, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nDownloadTime ) : CBaseCallable( ), m_Map( nMap ), m_MapSize( nMapSize ), m_Name( nName ), m_IP( nIP ), m_Spoofed( nSpoofed ), m_SpoofedRealm( nSpoofedRealm ), m_DownloadTime( nDownloadTime ), m_Result( false ) { } - virtual ~CCallableDownloadAdd( ); - - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -class CCallableScoreCheck : virtual public CBaseCallable -{ -protected: - string m_Category; - string m_Name; - string m_Server; - double m_Result; - -public: - CCallableScoreCheck( string nCategory, string nName, string nServer ) : CBaseCallable( ), m_Category( nCategory ), m_Name( nName ), m_Server( nServer ), m_Result( 0.0 ) { } - virtual ~CCallableScoreCheck( ); - - virtual string GetName( ) { return m_Name; } - virtual double GetResult( ) { return m_Result; } - virtual void SetResult( double nResult ) { m_Result = nResult; } -}; - -class CCallableW3MMDPlayerAdd : virtual public CBaseCallable -{ -protected: - string m_Category; - uint32_t m_GameID; - uint32_t m_PID; - string m_Name; - string m_Flag; - uint32_t m_Leaver; - uint32_t m_Practicing; - uint32_t m_Result; - -public: - CCallableW3MMDPlayerAdd( string nCategory, uint32_t nGameID, uint32_t nPID, string nName, string nFlag, uint32_t nLeaver, uint32_t nPracticing ) : CBaseCallable( ), m_Category( nCategory ), m_GameID( nGameID ), m_PID( nPID ), m_Name( nName ), m_Flag( nFlag ), m_Leaver( nLeaver ), m_Practicing( nPracticing ), m_Result( 0 ) { } - virtual ~CCallableW3MMDPlayerAdd( ); - - virtual uint32_t GetResult( ) { return m_Result; } - virtual void SetResult( uint32_t nResult ) { m_Result = nResult; } -}; - -class CCallableW3MMDVarAdd : virtual public CBaseCallable -{ -protected: - uint32_t m_GameID; - map m_VarInts; - map m_VarReals; - map m_VarStrings; - - enum ValueType { - VALUETYPE_INT = 1, - VALUETYPE_REAL = 2, - VALUETYPE_STRING = 3 - }; - - ValueType m_ValueType; - bool m_Result; - -public: - CCallableW3MMDVarAdd( uint32_t nGameID, map nVarInts ) : CBaseCallable( ), m_GameID( nGameID ), m_VarInts( nVarInts ), m_ValueType( VALUETYPE_INT ), m_Result( false ) { } - CCallableW3MMDVarAdd( uint32_t nGameID, map nVarReals ) : CBaseCallable( ), m_GameID( nGameID ), m_VarReals( nVarReals ), m_ValueType( VALUETYPE_REAL ), m_Result( false ) { } - CCallableW3MMDVarAdd( uint32_t nGameID, map nVarStrings ) : CBaseCallable( ), m_GameID( nGameID ), m_VarStrings( nVarStrings ), m_ValueType( VALUETYPE_STRING ), m_Result( false ) { } - virtual ~CCallableW3MMDVarAdd( ); - - virtual bool GetResult( ) { return m_Result; } - virtual void SetResult( bool nResult ) { m_Result = nResult; } -}; - -// -// CDBBan -// - -class CDBBan -{ -private: - string m_Server; - string m_Name; - string m_IP; - string m_Date; - string m_GameName; - string m_Admin; - string m_Reason; - -public: - CDBBan( string nServer, string nName, string nIP, string nDate, string nGameName, string nAdmin, string nReason ); - ~CDBBan( ); - - string GetServer( ) { return m_Server; } - string GetName( ) { return m_Name; } - string GetIP( ) { return m_IP; } - string GetDate( ) { return m_Date; } - string GetGameName( ) { return m_GameName; } - string GetAdmin( ) { return m_Admin; } - string GetReason( ) { return m_Reason; } -}; - -// -// CDBGame -// - -class CDBGame -{ -private: - uint32_t m_ID; - string m_Server; - string m_Map; - string m_DateTime; - string m_GameName; - string m_OwnerName; - uint32_t m_Duration; - -public: - CDBGame( uint32_t nID, string nServer, string nMap, string nDateTime, string nGameName, string nOwnerName, uint32_t nDuration ); - ~CDBGame( ); - - uint32_t GetID( ) { return m_ID; } - string GetServer( ) { return m_Server; } - string GetMap( ) { return m_Map; } - string GetDateTime( ) { return m_DateTime; } - string GetGameName( ) { return m_GameName; } - string GetOwnerName( ) { return m_OwnerName; } - uint32_t GetDuration( ) { return m_Duration; } - - void SetDuration( uint32_t nDuration ) { m_Duration = nDuration; } -}; - -// -// CDBGamePlayer -// - -class CDBGamePlayer -{ -private: - uint32_t m_ID; - uint32_t m_GameID; - string m_Name; - string m_IP; - uint32_t m_Spoofed; - string m_SpoofedRealm; - uint32_t m_Reserved; - uint32_t m_LoadingTime; - uint32_t m_Left; - string m_LeftReason; - uint32_t m_Team; - uint32_t m_Colour; - -public: - CDBGamePlayer( uint32_t nID, uint32_t nGameID, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nReserved, uint32_t nLoadingTime, uint32_t nLeft, string nLeftReason, uint32_t nTeam, uint32_t nColour ); - ~CDBGamePlayer( ); - - uint32_t GetID( ) { return m_ID; } - uint32_t GetGameID( ) { return m_GameID; } - string GetName( ) { return m_Name; } - string GetIP( ) { return m_IP; } - uint32_t GetSpoofed( ) { return m_Spoofed; } - string GetSpoofedRealm( ) { return m_SpoofedRealm; } - uint32_t GetReserved( ) { return m_Reserved; } - uint32_t GetLoadingTime( ) { return m_LoadingTime; } - uint32_t GetLeft( ) { return m_Left; } - string GetLeftReason( ) { return m_LeftReason; } - uint32_t GetTeam( ) { return m_Team; } - uint32_t GetColour( ) { return m_Colour; } - - void SetLoadingTime( uint32_t nLoadingTime ) { m_LoadingTime = nLoadingTime; } - void SetLeft( uint32_t nLeft ) { m_Left = nLeft; } - void SetLeftReason( string nLeftReason ) { m_LeftReason = nLeftReason; } -}; - -// -// CDBGamePlayerSummary -// - -class CDBGamePlayerSummary -{ -private: - string m_Server; - string m_Name; - string m_FirstGameDateTime; // datetime of first game played - string m_LastGameDateTime; // datetime of last game played - uint32_t m_TotalGames; // total number of games played - uint32_t m_MinLoadingTime; // minimum loading time in milliseconds (this could be skewed because different maps have different load times) - uint32_t m_AvgLoadingTime; // average loading time in milliseconds (this could be skewed because different maps have different load times) - uint32_t m_MaxLoadingTime; // maximum loading time in milliseconds (this could be skewed because different maps have different load times) - uint32_t m_MinLeftPercent; // minimum time at which the player left the game expressed as a percentage of the game duration (0-100) - uint32_t m_AvgLeftPercent; // average time at which the player left the game expressed as a percentage of the game duration (0-100) - uint32_t m_MaxLeftPercent; // maximum time at which the player left the game expressed as a percentage of the game duration (0-100) - uint32_t m_MinDuration; // minimum game duration in seconds - uint32_t m_AvgDuration; // average game duration in seconds - uint32_t m_MaxDuration; // maximum game duration in seconds - -public: - CDBGamePlayerSummary( string nServer, string nName, string nFirstGameDateTime, string nLastGameDateTime, uint32_t nTotalGames, uint32_t nMinLoadingTime, uint32_t nAvgLoadingTime, uint32_t nMaxLoadingTime, uint32_t nMinLeftPercent, uint32_t nAvgLeftPercent, uint32_t nMaxLeftPercent, uint32_t nMinDuration, uint32_t nAvgDuration, uint32_t nMaxDuration ); - ~CDBGamePlayerSummary( ); - - string GetServer( ) { return m_Server; } - string GetName( ) { return m_Name; } - string GetFirstGameDateTime( ) { return m_FirstGameDateTime; } - string GetLastGameDateTime( ) { return m_LastGameDateTime; } - uint32_t GetTotalGames( ) { return m_TotalGames; } - uint32_t GetMinLoadingTime( ) { return m_MinLoadingTime; } - uint32_t GetAvgLoadingTime( ) { return m_AvgLoadingTime; } - uint32_t GetMaxLoadingTime( ) { return m_MaxLoadingTime; } - uint32_t GetMinLeftPercent( ) { return m_MinLeftPercent; } - uint32_t GetAvgLeftPercent( ) { return m_AvgLeftPercent; } - uint32_t GetMaxLeftPercent( ) { return m_MaxLeftPercent; } - uint32_t GetMinDuration( ) { return m_MinDuration; } - uint32_t GetAvgDuration( ) { return m_AvgDuration; } - uint32_t GetMaxDuration( ) { return m_MaxDuration; } -}; - -// -// CDBDotAGame -// - -class CDBDotAGame -{ -private: - uint32_t m_ID; - uint32_t m_GameID; - uint32_t m_Winner; - uint32_t m_Min; - uint32_t m_Sec; - -public: - CDBDotAGame( uint32_t nID, uint32_t nGameID, uint32_t nWinner, uint32_t nMin, uint32_t nSec ); - ~CDBDotAGame( ); - - uint32_t GetID( ) { return m_ID; } - uint32_t GetGameID( ) { return m_GameID; } - uint32_t GetWinner( ) { return m_Winner; } - uint32_t GetMin( ) { return m_Min; } - uint32_t GetSec( ) { return m_Sec; } -}; - -// -// CDBDotAPlayer -// - -class CDBDotAPlayer -{ -private: - uint32_t m_ID; - uint32_t m_GameID; - uint32_t m_Colour; - uint32_t m_Kills; - uint32_t m_Deaths; - uint32_t m_CreepKills; - uint32_t m_CreepDenies; - uint32_t m_Assists; - uint32_t m_Gold; - uint32_t m_NeutralKills; - string m_Items[6]; - string m_Hero; - uint32_t m_NewColour; - uint32_t m_TowerKills; - uint32_t m_RaxKills; - uint32_t m_CourierKills; - -public: - CDBDotAPlayer( ); - CDBDotAPlayer( uint32_t nID, uint32_t nGameID, uint32_t nColour, uint32_t nKills, uint32_t nDeaths, uint32_t nCreepKills, uint32_t nCreepDenies, uint32_t nAssists, uint32_t nGold, uint32_t nNeutralKills, string nItem1, string nItem2, string nItem3, string nItem4, string nItem5, string nItem6, string nHero, uint32_t nNewColour, uint32_t nTowerKills, uint32_t nRaxKills, uint32_t nCourierKills ); - ~CDBDotAPlayer( ); - - uint32_t GetID( ) { return m_ID; } - uint32_t GetGameID( ) { return m_GameID; } - uint32_t GetColour( ) { return m_Colour; } - uint32_t GetKills( ) { return m_Kills; } - uint32_t GetDeaths( ) { return m_Deaths; } - uint32_t GetCreepKills( ) { return m_CreepKills; } - uint32_t GetCreepDenies( ) { return m_CreepDenies; } - uint32_t GetAssists( ) { return m_Assists; } - uint32_t GetGold( ) { return m_Gold; } - uint32_t GetNeutralKills( ) { return m_NeutralKills; } - string GetItem( unsigned int i ); - string GetHero( ) { return m_Hero; } - uint32_t GetNewColour( ) { return m_NewColour; } - uint32_t GetTowerKills( ) { return m_TowerKills; } - uint32_t GetRaxKills( ) { return m_RaxKills; } - uint32_t GetCourierKills( ) { return m_CourierKills; } - - void SetColour( uint32_t nColour ) { m_Colour = nColour; } - void SetKills( uint32_t nKills ) { m_Kills = nKills; } - void SetDeaths( uint32_t nDeaths ) { m_Deaths = nDeaths; } - void SetCreepKills( uint32_t nCreepKills ) { m_CreepKills = nCreepKills; } - void SetCreepDenies( uint32_t nCreepDenies ) { m_CreepDenies = nCreepDenies; } - void SetAssists( uint32_t nAssists ) { m_Assists = nAssists; } - void SetGold( uint32_t nGold ) { m_Gold = nGold; } - void SetNeutralKills( uint32_t nNeutralKills ) { m_NeutralKills = nNeutralKills; } - void SetItem( unsigned int i, string item ); - void SetHero( string nHero ) { m_Hero = nHero; } - void SetNewColour( uint32_t nNewColour ) { m_NewColour = nNewColour; } - void SetTowerKills( uint32_t nTowerKills ) { m_TowerKills = nTowerKills; } - void SetRaxKills( uint32_t nRaxKills ) { m_RaxKills = nRaxKills; } - void SetCourierKills( uint32_t nCourierKills ) { m_CourierKills = nCourierKills; } -}; - -// -// CDBDotAPlayerSummary -// - -class CDBDotAPlayerSummary -{ -private: - string m_Server; - string m_Name; - uint32_t m_TotalGames; // total number of dota games played - uint32_t m_TotalWins; // total number of dota games won - uint32_t m_TotalLosses; // total number of dota games lost - uint32_t m_TotalKills; // total number of hero kills - uint32_t m_TotalDeaths; // total number of deaths - uint32_t m_TotalCreepKills; // total number of creep kills - uint32_t m_TotalCreepDenies; // total number of creep denies - uint32_t m_TotalAssists; // total number of assists - uint32_t m_TotalNeutralKills; // total number of neutral kills - uint32_t m_TotalTowerKills; // total number of tower kills - uint32_t m_TotalRaxKills; // total number of rax kills - uint32_t m_TotalCourierKills; // total number of courier kills - -public: - CDBDotAPlayerSummary( string nServer, string nName, uint32_t nTotalGames, uint32_t nTotalWins, uint32_t nTotalLosses, uint32_t nTotalKills, uint32_t nTotalDeaths, uint32_t nTotalCreepKills, uint32_t nTotalCreepDenies, uint32_t nTotalAssists, uint32_t nTotalNeutralKills, uint32_t nTotalTowerKills, uint32_t nTotalRaxKills, uint32_t nTotalCourierKills ); - ~CDBDotAPlayerSummary( ); - - string GetServer( ) { return m_Server; } - string GetName( ) { return m_Name; } - uint32_t GetTotalGames( ) { return m_TotalGames; } - uint32_t GetTotalWins( ) { return m_TotalWins; } - uint32_t GetTotalLosses( ) { return m_TotalLosses; } - uint32_t GetTotalKills( ) { return m_TotalKills; } - uint32_t GetTotalDeaths( ) { return m_TotalDeaths; } - uint32_t GetTotalCreepKills( ) { return m_TotalCreepKills; } - uint32_t GetTotalCreepDenies( ) { return m_TotalCreepDenies; } - uint32_t GetTotalAssists( ) { return m_TotalAssists; } - uint32_t GetTotalNeutralKills( ) { return m_TotalNeutralKills; } - uint32_t GetTotalTowerKills( ) { return m_TotalTowerKills; } - uint32_t GetTotalRaxKills( ) { return m_TotalRaxKills; } - uint32_t GetTotalCourierKills( ) { return m_TotalCourierKills; } - - float GetAvgKills( ) { return m_TotalGames > 0 ? (float)m_TotalKills / m_TotalGames : 0; } - float GetAvgDeaths( ) { return m_TotalGames > 0 ? (float)m_TotalDeaths / m_TotalGames : 0; } - float GetAvgCreepKills( ) { return m_TotalGames > 0 ? (float)m_TotalCreepKills / m_TotalGames : 0; } - float GetAvgCreepDenies( ) { return m_TotalGames > 0 ? (float)m_TotalCreepDenies / m_TotalGames : 0; } - float GetAvgAssists( ) { return m_TotalGames > 0 ? (float)m_TotalAssists / m_TotalGames : 0; } - float GetAvgNeutralKills( ) { return m_TotalGames > 0 ? (float)m_TotalNeutralKills / m_TotalGames : 0; } - float GetAvgTowerKills( ) { return m_TotalGames > 0 ? (float)m_TotalTowerKills / m_TotalGames : 0; } - float GetAvgRaxKills( ) { return m_TotalGames > 0 ? (float)m_TotalRaxKills / m_TotalGames : 0; } - float GetAvgCourierKills( ) { return m_TotalGames > 0 ? (float)m_TotalCourierKills / m_TotalGames : 0; } -}; - -#endif diff --git a/ghost/ghostdbmysql.h b/ghost/ghostdbmysql.h deleted file mode 100644 index f074871..0000000 --- a/ghost/ghostdbmysql.h +++ /dev/null @@ -1,497 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifdef GHOST_MYSQL - -#ifndef GHOSTDBMYSQL_H -#define GHOSTDBMYSQL_H - -/************** - *** SCHEMA *** - ************** - -CREATE TABLE admins ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - name VARCHAR(15) NOT NULL, - server VARCHAR(100) NOT NULL -) - -CREATE TABLE bans ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - server VARCHAR(100) NOT NULL, - name VARCHAR(15) NOT NULL, - ip VARCHAR(15) NOT NULL, - date DATETIME NOT NULL, - gamename VARCHAR(31) NOT NULL, - admin VARCHAR(15) NOT NULL, - reason VARCHAR(255) NOT NULL -) - -CREATE TABLE games ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - server VARCHAR(100) NOT NULL, - map VARCHAR(100) NOT NULL, - datetime DATETIME NOT NULL, - gamename VARCHAR(31) NOT NULL, - ownername VARCHAR(15) NOT NULL, - duration INT NOT NULL, - gamestate INT NOT NULL, - creatorname VARCHAR(15) NOT NULL, - creatorserver VARCHAR(100) NOT NULL -) - -CREATE TABLE gameplayers ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - gameid INT NOT NULL, - name VARCHAR(15) NOT NULL, - ip VARCHAR(15) NOT NULL, - spoofed INT NOT NULL, - reserved INT NOT NULL, - loadingtime INT NOT NULL, - `left` INT NOT NULL, - leftreason VARCHAR(100) NOT NULL, - team INT NOT NULL, - colour INT NOT NULL, - spoofedrealm VARCHAR(100) NOT NULL, - INDEX( gameid ) -) - -CREATE TABLE dotagames ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - gameid INT NOT NULL, - winner INT NOT NULL, - min INT NOT NULL, - sec INT NOT NULL -) - -CREATE TABLE dotaplayers ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - gameid INT NOT NULL, - colour INT NOT NULL, - kills INT NOT NULL, - deaths INT NOT NULL, - creepkills INT NOT NULL, - creepdenies INT NOT NULL, - assists INT NOT NULL, - gold INT NOT NULL, - neutralkills INT NOT NULL, - item1 CHAR(4) NOT NULL, - item2 CHAR(4) NOT NULL, - item3 CHAR(4) NOT NULL, - item4 CHAR(4) NOT NULL, - item5 CHAR(4) NOT NULL, - item6 CHAR(4) NOT NULL, - hero CHAR(4) NOT NULL, - newcolour INT NOT NULL, - towerkills INT NOT NULL, - raxkills INT NOT NULL, - courierkills INT NOT NULL, - INDEX( gameid, colour ) -) - -CREATE TABLE downloads ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - map VARCHAR(100) NOT NULL, - mapsize INT NOT NULL, - datetime DATETIME NOT NULL, - name VARCHAR(15) NOT NULL, - ip VARCHAR(15) NOT NULL, - spoofed INT NOT NULL, - spoofedrealm VARCHAR(100) NOT NULL, - downloadtime INT NOT NULL -) - -CREATE TABLE scores ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - category VARCHAR(25) NOT NULL, - name VARCHAR(15) NOT NULL, - server VARCHAR(100) NOT NULL, - score REAL NOT NULL -) - -CREATE TABLE w3mmdplayers ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - category VARCHAR(25) NOT NULL, - gameid INT NOT NULL, - pid INT NOT NULL, - name VARCHAR(15) NOT NULL, - flag VARCHAR(32) NOT NULL, - leaver INT NOT NULL, - practicing INT NOT NULL -) - -CREATE TABLE w3mmdvars ( - id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - botid INT NOT NULL, - gameid INT NOT NULL, - pid INT NOT NULL, - varname VARCHAR(25) NOT NULL, - value_int INT DEFAULT NULL, - value_real REAL DEFAULT NULL, - value_string VARCHAR(100) DEFAULT NULL -) - - ************** - *** SCHEMA *** - **************/ - -// -// CGHostDBMySQL -// - -class CGHostDBMySQL : public CGHostDB -{ -private: - string m_Server; - string m_Database; - string m_User; - string m_Password; - uint16_t m_Port; - uint32_t m_BotID; - queue m_IdleConnections; - uint32_t m_NumConnections; - uint32_t m_OutstandingCallables; - -public: - CGHostDBMySQL( CConfig *CFG ); - virtual ~CGHostDBMySQL( ); - - virtual string GetStatus( ); - - virtual void RecoverCallable( CBaseCallable *callable ); - - // threaded database functions - - virtual void CreateThread( CBaseCallable *callable ); - virtual CCallableAdminCount *ThreadedAdminCount( string server ); - virtual CCallableAdminCheck *ThreadedAdminCheck( string server, string user ); - virtual CCallableAdminAdd *ThreadedAdminAdd( string server, string user ); - virtual CCallableAdminRemove *ThreadedAdminRemove( string server, string user ); - virtual CCallableAdminList *ThreadedAdminList( string server ); - virtual CCallableBanCount *ThreadedBanCount( string server ); - virtual CCallableBanCheck *ThreadedBanCheck( string server, string user, string ip ); - virtual CCallableBanAdd *ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ); - virtual CCallableBanRemove *ThreadedBanRemove( string server, string user ); - virtual CCallableBanRemove *ThreadedBanRemove( string user ); - virtual CCallableBanList *ThreadedBanList( string server ); - virtual CCallableGameAdd *ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); - virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); - virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( string name ); - virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); - virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); - virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( string name ); - virtual CCallableDownloadAdd *ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); - virtual CCallableScoreCheck *ThreadedScoreCheck( string category, string name, string server ); - virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ); - - // other database functions - - virtual void *GetIdleConnection( ); -}; - -// -// global helper functions -// - -uint32_t MySQLAdminCount( void *conn, string *error, uint32_t botid, string server ); -bool MySQLAdminCheck( void *conn, string *error, uint32_t botid, string server, string user ); -bool MySQLAdminAdd( void *conn, string *error, uint32_t botid, string server, string user ); -bool MySQLAdminRemove( void *conn, string *error, uint32_t botid, string server, string user ); -vector MySQLAdminList( void *conn, string *error, uint32_t botid, string server ); -uint32_t MySQLBanCount( void *conn, string *error, uint32_t botid, string server ); -CDBBan *MySQLBanCheck( void *conn, string *error, uint32_t botid, string server, string user, string ip ); -bool MySQLBanAdd( void *conn, string *error, uint32_t botid, string server, string user, string ip, string gamename, string admin, string reason ); -bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string server, string user ); -bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string user ); -vector MySQLBanList( void *conn, string *error, uint32_t botid, string server ); -uint32_t MySQLGameAdd( void *conn, string *error, uint32_t botid, string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); -uint32_t MySQLGamePlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); -CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, string *error, uint32_t botid, string name ); -uint32_t MySQLDotAGameAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); -uint32_t MySQLDotAPlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); -CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, uint32_t botid, string name ); -bool MySQLDownloadAdd( void *conn, string *error, uint32_t botid, string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); -double MySQLScoreCheck( void *conn, string *error, uint32_t botid, string category, string name, string server ); -uint32_t MySQLW3MMDPlayerAdd( void *conn, string *error, uint32_t botid, string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_ints ); -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_reals ); -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_strings ); - -// -// MySQL Callables -// - -class CMySQLCallable : virtual public CBaseCallable -{ -protected: - void *m_Connection; - string m_SQLServer; - string m_SQLDatabase; - string m_SQLUser; - string m_SQLPassword; - uint16_t m_SQLPort; - uint32_t m_SQLBotID; - -public: - CMySQLCallable( void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), m_Connection( nConnection ), m_SQLBotID( nSQLBotID ), m_SQLServer( nSQLServer ), m_SQLDatabase( nSQLDatabase ), m_SQLUser( nSQLUser ), m_SQLPassword( nSQLPassword ), m_SQLPort( nSQLPort ) { } - virtual ~CMySQLCallable( ) { } - - virtual void *GetConnection( ) { return m_Connection; } - - virtual void Init( ); - virtual void Close( ); -}; - -class CMySQLCallableAdminCount : public CCallableAdminCount, public CMySQLCallable -{ -public: - CMySQLCallableAdminCount( string nServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableAdminCount( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableAdminCount( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableAdminCheck : public CCallableAdminCheck, public CMySQLCallable -{ -public: - CMySQLCallableAdminCheck( string nServer, string nUser, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableAdminCheck( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableAdminCheck( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableAdminAdd : public CCallableAdminAdd, public CMySQLCallable -{ -public: - CMySQLCallableAdminAdd( string nServer, string nUser, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableAdminAdd( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableAdminAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableAdminRemove : public CCallableAdminRemove, public CMySQLCallable -{ -public: - CMySQLCallableAdminRemove( string nServer, string nUser, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableAdminRemove( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableAdminRemove( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableAdminList : public CCallableAdminList, public CMySQLCallable -{ -public: - CMySQLCallableAdminList( string nServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableAdminList( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableAdminList( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableBanCount : public CCallableBanCount, public CMySQLCallable -{ -public: - CMySQLCallableBanCount( string nServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableBanCount( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableBanCount( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableBanCheck : public CCallableBanCheck, public CMySQLCallable -{ -public: - CMySQLCallableBanCheck( string nServer, string nUser, string nIP, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableBanCheck( nServer, nUser, nIP ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableBanCheck( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableBanAdd : public CCallableBanAdd, public CMySQLCallable -{ -public: - CMySQLCallableBanAdd( string nServer, string nUser, string nIP, string nGameName, string nAdmin, string nReason, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableBanAdd( nServer, nUser, nIP, nGameName, nAdmin, nReason ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableBanAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableBanRemove : public CCallableBanRemove, public CMySQLCallable -{ -public: - CMySQLCallableBanRemove( string nServer, string nUser, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableBanRemove( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableBanRemove( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableBanList : public CCallableBanList, public CMySQLCallable -{ -public: - CMySQLCallableBanList( string nServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableBanList( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableBanList( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableGameAdd : public CCallableGameAdd, public CMySQLCallable -{ -public: - CMySQLCallableGameAdd( string nServer, string nMap, string nGameName, string nOwnerName, uint32_t nDuration, uint32_t nGameState, string nCreatorName, string nCreatorServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableGameAdd( nServer, nMap, nGameName, nOwnerName, nDuration, nGameState, nCreatorName, nCreatorServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableGameAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableGamePlayerAdd : public CCallableGamePlayerAdd, public CMySQLCallable -{ -public: - CMySQLCallableGamePlayerAdd( uint32_t nGameID, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nReserved, uint32_t nLoadingTime, uint32_t nLeft, string nLeftReason, uint32_t nTeam, uint32_t nColour, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableGamePlayerAdd( nGameID, nName, nIP, nSpoofed, nSpoofedRealm, nReserved, nLoadingTime, nLeft, nLeftReason, nTeam, nColour ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableGamePlayerAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableGamePlayerSummaryCheck : public CCallableGamePlayerSummaryCheck, public CMySQLCallable -{ -public: - CMySQLCallableGamePlayerSummaryCheck( string nName, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableGamePlayerSummaryCheck( nName ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableGamePlayerSummaryCheck( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableDotAGameAdd : public CCallableDotAGameAdd, public CMySQLCallable -{ -public: - CMySQLCallableDotAGameAdd( uint32_t nGameID, uint32_t nWinner, uint32_t nMin, uint32_t nSec, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableDotAGameAdd( nGameID, nWinner, nMin, nSec ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableDotAGameAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableDotAPlayerAdd : public CCallableDotAPlayerAdd, public CMySQLCallable -{ -public: - CMySQLCallableDotAPlayerAdd( uint32_t nGameID, uint32_t nColour, uint32_t nKills, uint32_t nDeaths, uint32_t nCreepKills, uint32_t nCreepDenies, uint32_t nAssists, uint32_t nGold, uint32_t nNeutralKills, string nItem1, string nItem2, string nItem3, string nItem4, string nItem5, string nItem6, string nHero, uint32_t nNewColour, uint32_t nTowerKills, uint32_t nRaxKills, uint32_t nCourierKills, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableDotAPlayerAdd( nGameID, nColour, nKills, nDeaths, nCreepKills, nCreepDenies, nAssists, nGold, nNeutralKills, nItem1, nItem2, nItem3, nItem4, nItem5, nItem6, nHero, nNewColour, nTowerKills, nRaxKills, nCourierKills ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableDotAPlayerAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableDotAPlayerSummaryCheck : public CCallableDotAPlayerSummaryCheck, public CMySQLCallable -{ -public: - CMySQLCallableDotAPlayerSummaryCheck( string nName, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableDotAPlayerSummaryCheck( nName ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableDotAPlayerSummaryCheck( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableDownloadAdd : public CCallableDownloadAdd, public CMySQLCallable -{ -public: - CMySQLCallableDownloadAdd( string nMap, uint32_t nMapSize, string nName, string nIP, uint32_t nSpoofed, string nSpoofedRealm, uint32_t nDownloadTime, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableDownloadAdd( nMap, nMapSize, nName, nIP, nSpoofed, nSpoofedRealm, nDownloadTime ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableDownloadAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableScoreCheck : public CCallableScoreCheck, public CMySQLCallable -{ -public: - CMySQLCallableScoreCheck( string nCategory, string nName, string nServer, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableScoreCheck( nCategory, nName, nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableScoreCheck( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableW3MMDPlayerAdd : public CCallableW3MMDPlayerAdd, public CMySQLCallable -{ -public: - CMySQLCallableW3MMDPlayerAdd( string nCategory, uint32_t nGameID, uint32_t nPID, string nName, string nFlag, uint32_t nLeaver, uint32_t nPracticing, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableW3MMDPlayerAdd( nCategory, nGameID, nPID, nName, nFlag, nLeaver, nPracticing ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableW3MMDPlayerAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -class CMySQLCallableW3MMDVarAdd : public CCallableW3MMDVarAdd, public CMySQLCallable -{ -public: - CMySQLCallableW3MMDVarAdd( uint32_t nGameID, map nVarInts, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarInts ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - CMySQLCallableW3MMDVarAdd( uint32_t nGameID, map nVarReals, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarReals ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - CMySQLCallableW3MMDVarAdd( uint32_t nGameID, map nVarStrings, void *nConnection, uint32_t nSQLBotID, string nSQLServer, string nSQLDatabase, string nSQLUser, string nSQLPassword, uint16_t nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarStrings ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } - virtual ~CMySQLCallableW3MMDVarAdd( ) { } - - virtual void operator( )( ); - virtual void Init( ) { CMySQLCallable :: Init( ); } - virtual void Close( ) { CMySQLCallable :: Close( ); } -}; - -#endif - -#endif diff --git a/ghost/ghostdbsqlite.h b/ghost/ghostdbsqlite.h deleted file mode 100644 index fe0d03e..0000000 --- a/ghost/ghostdbsqlite.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef GHOSTDBSQLITE_H -#define GHOSTDBSQLITE_H - -/************** - *** SCHEMA *** - ************** - -CREATE TABLE admins ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - server TEXT NOT NULL DEFAULT "" -) - -CREATE TABLE bans ( - id INTEGER PRIMARY KEY, - server TEXT NOT NULL, - name TEXT NOT NULL, - ip TEXT, - date TEXT NOT NULL, - gamename TEXT, - admin TEXT NOT NULL, - reason TEXT -) - -CREATE TABLE games ( - id INTEGER PRIMARY KEY, - server TEXT NOT NULL, - map TEXT NOT NULL, - datetime TEXT NOT NULL, - gamename TEXT NOT NULL, - ownername TEXT NOT NULL, - duration INTEGER NOT NULL, - gamestate INTEGER NOT NULL DEFAULT 0, - creatorname TEXT NOT NULL DEFAULT "", - creatorserver TEXT NOT NULL DEFAULT "" -) - -CREATE TABLE gameplayers ( - id INTEGER PRIMARY KEY, - gameid INTEGER NOT NULL, - name TEXT NOT NULL, - ip TEXT NOT NULL, - spoofed INTEGER NOT NULL, - reserved INTEGER NOT NULL, - loadingtime INTEGER NOT NULL, - left INTEGER NOT NULL, - leftreason TEXT NOT NULL, - team INTEGER NOT NULL, - colour INTEGER NOT NULL, - spoofedrealm TEXT NOT NULL DEFAULT "" -) - -CREATE TABLE dotagames ( - id INTEGER PRIMARY KEY, - gameid INTEGER NOT NULL, - winner INTEGER NOT NULL, - min INTEGER NOT NULL DEFAULT 0, - sec INTEGER NOT NULL DEFAULT 0 -) - -CREATE TABLE dotaplayers ( - id INTEGER PRIMARY KEY, - gameid INTEGER NOT NULL, - colour INTEGER NOT NULL, - kills INTEGER NOT NULL, - deaths INTEGER NOT NULL, - creepkills INTEGER NOT NULL, - creepdenies INTEGER NOT NULL, - assists INTEGER NOT NULL, - gold INTEGER NOT NULL, - neutralkills INTEGER NOT NULL, - item1 TEXT NOT NULL, - item2 TEXT NOT NULL, - item3 TEXT NOT NULL, - item4 TEXT NOT NULL, - item5 TEXT NOT NULL, - item6 TEXT NOT NULL, - hero TEXT NOT NULL DEFAULT "", - newcolour NOT NULL DEFAULT 0, - towerkills NOT NULL DEFAULT 0, - raxkills NOT NULL DEFAULT 0, - courierkills NOT NULL DEFAULT 0 -) - -CREATE TABLE config ( - name TEXT NOT NULL PRIMARY KEY, - value TEXT NOT NULL -) - -CREATE TABLE downloads ( - id INTEGER PRIMARY KEY, - map TEXT NOT NULL, - mapsize INTEGER NOT NULL, - datetime TEXT NOT NULL, - name TEXT NOT NULL, - ip TEXT NOT NULL, - spoofed INTEGER NOT NULL, - spoofedrealm TEXT NOT NULL, - downloadtime INTEGER NOT NULL -) - -CREATE TABLE w3mmdplayers ( - id INTEGER PRIMARY KEY, - category TEXT NOT NULL, - gameid INTEGER NOT NULL, - pid INTEGER NOT NULL, - name TEXT NOT NULL, - flag TEXT NOT NULL, - leaver INTEGER NOT NULL, - practicing INTEGER NOT NULL -) - -CREATE TABLE w3mmdvars ( - id INTEGER PRIMARY KEY, - gameid INTEGER NOT NULL, - pid INTEGER NOT NULL, - varname TEXT NOT NULL, - value_int INTEGER DEFAULT NULL, - value_real REAL DEFAULT NULL, - value_string TEXT DEFAULT NULL -) - -CREATE TEMPORARY TABLE iptocountry ( - ip1 INTEGER NOT NULL, - ip2 INTEGER NOT NULL, - country TEXT NOT NULL, - PRIMARY KEY ( ip1, ip2 ) -) - -CREATE INDEX idx_gameid ON gameplayers ( gameid ) -CREATE INDEX idx_gameid_colour ON dotaplayers ( gameid, colour ) - - ************** - *** SCHEMA *** - **************/ - -// -// CSQLITE3 (wrapper class) -// - -class CSQLITE3 -{ -private: - void *m_DB; - bool m_Ready; - vector m_Row; - -public: - CSQLITE3( string filename ); - ~CSQLITE3( ); - - bool GetReady( ) { return m_Ready; } - vector *GetRow( ) { return &m_Row; } - string GetError( ); - - int Prepare( string query, void **Statement ); - int Step( void *Statement ); - int Finalize( void *Statement ); - int Reset( void *Statement ); - int ClearBindings( void *Statement ); - int Exec( string query ); - uint32_t LastRowID( ); -}; - -// -// CGHostDBSQLite -// - -class CGHostDBSQLite : public CGHostDB -{ -private: - string m_File; - CSQLITE3 *m_DB; - - // we keep some prepared statements in memory rather than recreating them each function call - // this is an optimization because preparing statements takes time - // however it only pays off if you're going to be using the statement extremely often - - void *FromAddStmt; - -public: - CGHostDBSQLite( CConfig *CFG ); - virtual ~CGHostDBSQLite( ); - - virtual void Upgrade1_2( ); - virtual void Upgrade2_3( ); - virtual void Upgrade3_4( ); - virtual void Upgrade4_5( ); - virtual void Upgrade5_6( ); - virtual void Upgrade6_7( ); - virtual void Upgrade7_8( ); - - virtual bool Begin( ); - virtual bool Commit( ); - virtual uint32_t AdminCount( string server ); - virtual bool AdminCheck( string server, string user ); - virtual bool AdminAdd( string server, string user ); - virtual bool AdminRemove( string server, string user ); - virtual vector AdminList( string server ); - virtual uint32_t BanCount( string server ); - virtual CDBBan *BanCheck( string server, string user, string ip ); - virtual bool BanAdd( string server, string user, string ip, string gamename, string admin, string reason ); - virtual bool BanRemove( string server, string user ); - virtual bool BanRemove( string user ); - virtual vector BanList( string server ); - virtual uint32_t GameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); - virtual uint32_t GamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); - virtual uint32_t GamePlayerCount( string name ); - virtual CDBGamePlayerSummary *GamePlayerSummaryCheck( string name ); - virtual uint32_t DotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); - virtual uint32_t DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); - virtual uint32_t DotAPlayerCount( string name ); - virtual CDBDotAPlayerSummary *DotAPlayerSummaryCheck( string name ); - virtual string FromCheck( uint32_t ip ); - virtual bool FromAdd( uint32_t ip1, uint32_t ip2, string country ); - virtual bool DownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); - virtual uint32_t W3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_ints ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_reals ); - virtual bool W3MMDVarAdd( uint32_t gameid, map var_strings ); - - // threaded database functions - // note: these are not actually implemented with threads at the moment, they WILL block until the query is complete - // todotodo: implement threads here - - virtual CCallableAdminCount *ThreadedAdminCount( string server ); - virtual CCallableAdminCheck *ThreadedAdminCheck( string server, string user ); - virtual CCallableAdminAdd *ThreadedAdminAdd( string server, string user ); - virtual CCallableAdminRemove *ThreadedAdminRemove( string server, string user ); - virtual CCallableAdminList *ThreadedAdminList( string server ); - virtual CCallableBanCount *ThreadedBanCount( string server ); - virtual CCallableBanCheck *ThreadedBanCheck( string server, string user, string ip ); - virtual CCallableBanAdd *ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ); - virtual CCallableBanRemove *ThreadedBanRemove( string server, string user ); - virtual CCallableBanRemove *ThreadedBanRemove( string user ); - virtual CCallableBanList *ThreadedBanList( string server ); - virtual CCallableGameAdd *ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ); - virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ); - virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( string name ); - virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ); - virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ); - virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( string name ); - virtual CCallableDownloadAdd *ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ); - virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ); - virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ); -}; - -#endif diff --git a/ghost/includes.h b/ghost/includes.h deleted file mode 100644 index f2954bb..0000000 --- a/ghost/includes.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef INCLUDES_H -#define INCLUDES_H - -// standard integer sizes for 64 bit compatibility - -#ifdef WIN32 - #include "ms_stdint.h" -#else - #include -#endif - -// STL - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -typedef vector BYTEARRAY; -typedef pair PIDPlayer; - -// time - -uint32_t GetTime( ); // seconds -uint32_t GetTicks( ); // milliseconds - -#ifdef WIN32 - #define MILLISLEEP( x ) Sleep( x ) -#else - #define MILLISLEEP( x ) usleep( ( x ) * 1000 ) -#endif - -// network - -#undef FD_SETSIZE -#define FD_SETSIZE 512 - -// output - -void CONSOLE_Print( string message ); -void DEBUG_Print( string message ); -void DEBUG_Print( BYTEARRAY b ); - -#endif diff --git a/ghost/language.cpp b/ghost/language.cpp deleted file mode 100644 index 7802ceb..0000000 --- a/ghost/language.cpp +++ /dev/null @@ -1,1535 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "config.h" -#include "language.h" - -// -// CLanguage -// - -CLanguage :: CLanguage( string nCFGFile ) -{ - m_CFG = new CConfig( ); - m_CFG->Read( nCFGFile ); -} - -CLanguage :: ~CLanguage( ) -{ - delete m_CFG; -} - -string CLanguage :: UnableToCreateGameTryAnotherName( string server, string gamename ) -{ - string Out = m_CFG->GetString( "lang_0001", "lang_0001" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: UserIsAlreadyAnAdmin( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0002", "lang_0002" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: AddedUserToAdminDatabase( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0003", "lang_0003" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: ErrorAddingUserToAdminDatabase( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0004", "lang_0004" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: YouDontHaveAccessToThatCommand( ) -{ - return m_CFG->GetString( "lang_0005", "lang_0005" ); -} - -string CLanguage :: UserIsAlreadyBanned( string server, string victim ) -{ - string Out = m_CFG->GetString( "lang_0006", "lang_0006" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: BannedUser( string server, string victim ) -{ - string Out = m_CFG->GetString( "lang_0007", "lang_0007" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: ErrorBanningUser( string server, string victim ) -{ - string Out = m_CFG->GetString( "lang_0008", "lang_0008" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UserIsAnAdmin( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0009", "lang_0009" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UserIsNotAnAdmin( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0010", "lang_0010" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UserWasBannedOnByBecause( string server, string victim, string date, string admin, string reason ) -{ - string Out = m_CFG->GetString( "lang_0011", "lang_0011" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$DATE$", date ); - UTIL_Replace( Out, "$ADMIN$", admin ); - UTIL_Replace( Out, "$REASON$", reason ); - return Out; -} - -string CLanguage :: UserIsNotBanned( string server, string victim ) -{ - string Out = m_CFG->GetString( "lang_0012", "lang_0012" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: ThereAreNoAdmins( string server ) -{ - string Out = m_CFG->GetString( "lang_0013", "lang_0013" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: ThereIsAdmin( string server ) -{ - string Out = m_CFG->GetString( "lang_0014", "lang_0014" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: ThereAreAdmins( string server, string count ) -{ - string Out = m_CFG->GetString( "lang_0015", "lang_0015" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$COUNT$", count ); - return Out; -} - -string CLanguage :: ThereAreNoBannedUsers( string server ) -{ - string Out = m_CFG->GetString( "lang_0016", "lang_0016" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: ThereIsBannedUser( string server ) -{ - string Out = m_CFG->GetString( "lang_0017", "lang_0017" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: ThereAreBannedUsers( string server, string count ) -{ - string Out = m_CFG->GetString( "lang_0018", "lang_0018" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$COUNT$", count ); - return Out; -} - -string CLanguage :: YouCantDeleteTheRootAdmin( ) -{ - return m_CFG->GetString( "lang_0019", "lang_0019" ); -} - -string CLanguage :: DeletedUserFromAdminDatabase( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0020", "lang_0020" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: ErrorDeletingUserFromAdminDatabase( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0021", "lang_0021" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnbannedUser( string victim ) -{ - string Out = m_CFG->GetString( "lang_0022", "lang_0022" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: ErrorUnbanningUser( string victim ) -{ - string Out = m_CFG->GetString( "lang_0023", "lang_0023" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: GameNumberIs( string number, string description ) -{ - string Out = m_CFG->GetString( "lang_0024", "lang_0024" ); - UTIL_Replace( Out, "$NUMBER$", number ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: GameNumberDoesntExist( string number ) -{ - string Out = m_CFG->GetString( "lang_0025", "lang_0025" ); - UTIL_Replace( Out, "$NUMBER$", number ); - return Out; -} - -string CLanguage :: GameIsInTheLobby( string description, string current, string max ) -{ - string Out = m_CFG->GetString( "lang_0026", "lang_0026" ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - UTIL_Replace( Out, "$CURRENT$", current ); - UTIL_Replace( Out, "$MAX$", max ); - return Out; -} - -string CLanguage :: ThereIsNoGameInTheLobby( string current, string max ) -{ - string Out = m_CFG->GetString( "lang_0027", "lang_0027" ); - UTIL_Replace( Out, "$CURRENT$", current ); - UTIL_Replace( Out, "$MAX$", max ); - return Out; -} - -string CLanguage :: UnableToLoadConfigFilesOutside( ) -{ - return m_CFG->GetString( "lang_0028", "lang_0028" ); -} - -string CLanguage :: LoadingConfigFile( string file ) -{ - string Out = m_CFG->GetString( "lang_0029", "lang_0029" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: UnableToLoadConfigFileDoesntExist( string file ) -{ - string Out = m_CFG->GetString( "lang_0030", "lang_0030" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: CreatingPrivateGame( string gamename, string user ) -{ - string Out = m_CFG->GetString( "lang_0031", "lang_0031" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: CreatingPublicGame( string gamename, string user ) -{ - string Out = m_CFG->GetString( "lang_0032", "lang_0032" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnableToUnhostGameCountdownStarted( string description ) -{ - string Out = m_CFG->GetString( "lang_0033", "lang_0033" ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: UnhostingGame( string description ) -{ - string Out = m_CFG->GetString( "lang_0034", "lang_0034" ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: UnableToUnhostGameNoGameInLobby( ) -{ - return m_CFG->GetString( "lang_0035", "lang_0035" ); -} - -string CLanguage :: VersionAdmin( string version ) -{ - string Out = m_CFG->GetString( "lang_0036", "lang_0036" ); - UTIL_Replace( Out, "$VERSION$", version ); - return Out; -} - -string CLanguage :: VersionNotAdmin( string version ) -{ - string Out = m_CFG->GetString( "lang_0037", "lang_0037" ); - UTIL_Replace( Out, "$VERSION$", version ); - return Out; -} - -string CLanguage :: UnableToCreateGameAnotherGameInLobby( string gamename, string description ) -{ - string Out = m_CFG->GetString( "lang_0038", "lang_0038" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: UnableToCreateGameMaxGamesReached( string gamename, string max ) -{ - string Out = m_CFG->GetString( "lang_0039", "lang_0039" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - UTIL_Replace( Out, "$MAX$", max ); - return Out; -} - -string CLanguage :: GameIsOver( string description ) -{ - string Out = m_CFG->GetString( "lang_0040", "lang_0040" ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: SpoofCheckByReplying( ) -{ - return m_CFG->GetString( "lang_0041", "lang_0041" ); -} - -string CLanguage :: GameRefreshed( ) -{ - return m_CFG->GetString( "lang_0042", "lang_0042" ); -} - -string CLanguage :: SpoofPossibleIsAway( string user ) -{ - string Out = m_CFG->GetString( "lang_0043", "lang_0043" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: SpoofPossibleIsUnavailable( string user ) -{ - string Out = m_CFG->GetString( "lang_0044", "lang_0044" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: SpoofPossibleIsRefusingMessages( string user ) -{ - string Out = m_CFG->GetString( "lang_0045", "lang_0045" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: SpoofDetectedIsNotInGame( string user ) -{ - string Out = m_CFG->GetString( "lang_0046", "lang_0046" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: SpoofDetectedIsInPrivateChannel( string user ) -{ - string Out = m_CFG->GetString( "lang_0047", "lang_0047" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: SpoofDetectedIsInAnotherGame( string user ) -{ - string Out = m_CFG->GetString( "lang_0048", "lang_0048" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: CountDownAborted( ) -{ - return m_CFG->GetString( "lang_0049", "lang_0049" ); -} - -string CLanguage :: TryingToJoinTheGameButBanned( string victim ) -{ - string Out = m_CFG->GetString( "lang_0050", "lang_0050" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UnableToBanNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0051", "lang_0051" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: PlayerWasBannedByPlayer( string server, string victim, string user ) -{ - string Out = m_CFG->GetString( "lang_0052", "lang_0052" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnableToBanFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0053", "lang_0053" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: AddedPlayerToTheHoldList( string user ) -{ - string Out = m_CFG->GetString( "lang_0054", "lang_0054" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnableToKickNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0055", "lang_0055" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UnableToKickFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0056", "lang_0056" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: SettingLatencyToMinimum( string min ) -{ - string Out = m_CFG->GetString( "lang_0057", "lang_0057" ); - UTIL_Replace( Out, "$MIN$", min ); - return Out; -} - -string CLanguage :: SettingLatencyToMaximum( string max ) -{ - string Out = m_CFG->GetString( "lang_0058", "lang_0058" ); - UTIL_Replace( Out, "$MAX$", max ); - return Out; -} - -string CLanguage :: SettingLatencyTo( string latency ) -{ - string Out = m_CFG->GetString( "lang_0059", "lang_0059" ); - UTIL_Replace( Out, "$LATENCY$", latency ); - return Out; -} - -string CLanguage :: KickingPlayersWithPingsGreaterThan( string total, string ping ) -{ - string Out = m_CFG->GetString( "lang_0060", "lang_0060" ); - UTIL_Replace( Out, "$TOTAL$", total ); - UTIL_Replace( Out, "$PING$", ping ); - return Out; -} - -string CLanguage :: HasPlayedGamesWithThisBot( string user, string firstgame, string lastgame, string totalgames, string avgloadingtime, string avgstay ) -{ - string Out = m_CFG->GetString( "lang_0061", "lang_0061" ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$FIRSTGAME$", firstgame ); - UTIL_Replace( Out, "$LASTGAME$", lastgame ); - UTIL_Replace( Out, "$TOTALGAMES$", totalgames ); - UTIL_Replace( Out, "$AVGLOADINGTIME$", avgloadingtime ); - UTIL_Replace( Out, "$AVGSTAY$", avgstay ); - return Out; -} - -string CLanguage :: HasntPlayedGamesWithThisBot( string user ) -{ - string Out = m_CFG->GetString( "lang_0062", "lang_0062" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: AutokickingPlayerForExcessivePing( string victim, string ping ) -{ - string Out = m_CFG->GetString( "lang_0063", "lang_0063" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$PING$", ping ); - return Out; -} - -string CLanguage :: SpoofCheckAcceptedFor( string server, string user ) -{ - string Out = m_CFG->GetString( "lang_0064", "lang_0064" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: PlayersNotYetSpoofChecked( string notspoofchecked ) -{ - string Out = m_CFG->GetString( "lang_0065", "lang_0065" ); - UTIL_Replace( Out, "$NOTSPOOFCHECKED$", notspoofchecked ); - return Out; -} - -string CLanguage :: ManuallySpoofCheckByWhispering( string hostname ) -{ - string Out = m_CFG->GetString( "lang_0066", "lang_0066" ); - UTIL_Replace( Out, "$HOSTNAME$", hostname ); - return Out; -} - -string CLanguage :: SpoofCheckByWhispering( string hostname ) -{ - string Out = m_CFG->GetString( "lang_0067", "lang_0067" ); - UTIL_Replace( Out, "$HOSTNAME$", hostname ); - return Out; -} - -string CLanguage :: EveryoneHasBeenSpoofChecked( ) -{ - return m_CFG->GetString( "lang_0068", "lang_0068" ); -} - -string CLanguage :: PlayersNotYetPinged( string notpinged ) -{ - string Out = m_CFG->GetString( "lang_0069", "lang_0069" ); - UTIL_Replace( Out, "$NOTPINGED$", notpinged ); - return Out; -} - -string CLanguage :: EveryoneHasBeenPinged( ) -{ - return m_CFG->GetString( "lang_0070", "lang_0070" ); -} - -string CLanguage :: ShortestLoadByPlayer( string user, string loadingtime ) -{ - string Out = m_CFG->GetString( "lang_0071", "lang_0071" ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$LOADINGTIME$", loadingtime ); - return Out; -} - -string CLanguage :: LongestLoadByPlayer( string user, string loadingtime ) -{ - string Out = m_CFG->GetString( "lang_0072", "lang_0072" ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$LOADINGTIME$", loadingtime ); - return Out; -} - -string CLanguage :: YourLoadingTimeWas( string loadingtime ) -{ - string Out = m_CFG->GetString( "lang_0073", "lang_0073" ); - UTIL_Replace( Out, "$LOADINGTIME$", loadingtime ); - return Out; -} - -string CLanguage :: HasPlayedDotAGamesWithThisBot( string user, string totalgames, string totalwins, string totallosses, string totalkills, string totaldeaths, string totalcreepkills, string totalcreepdenies, string totalassists, string totalneutralkills, string totaltowerkills, string totalraxkills, string totalcourierkills, string avgkills, string avgdeaths, string avgcreepkills, string avgcreepdenies, string avgassists, string avgneutralkills, string avgtowerkills, string avgraxkills, string avgcourierkills ) -{ - string Out = m_CFG->GetString( "lang_0074", "lang_0074" ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$TOTALGAMES$", totalgames ); - UTIL_Replace( Out, "$TOTALWINS$", totalwins ); - UTIL_Replace( Out, "$TOTALLOSSES$", totallosses ); - UTIL_Replace( Out, "$TOTALKILLS$", totalkills ); - UTIL_Replace( Out, "$TOTALDEATHS$", totaldeaths ); - UTIL_Replace( Out, "$TOTALCREEPKILLS$", totalcreepkills ); - UTIL_Replace( Out, "$TOTALCREEPDENIES$", totalcreepdenies ); - UTIL_Replace( Out, "$TOTALASSISTS$", totalassists ); - UTIL_Replace( Out, "$TOTALNEUTRALKILLS$", totalneutralkills ); - UTIL_Replace( Out, "$TOTALTOWERKILLS$", totaltowerkills ); - UTIL_Replace( Out, "$TOTALRAXKILLS$", totalraxkills ); - UTIL_Replace( Out, "$TOTALCOURIERKILLS$", totalcourierkills ); - UTIL_Replace( Out, "$AVGKILLS$", avgkills ); - UTIL_Replace( Out, "$AVGDEATHS$", avgdeaths ); - UTIL_Replace( Out, "$AVGCREEPKILLS$", avgcreepkills ); - UTIL_Replace( Out, "$AVGCREEPDENIES$", avgcreepdenies ); - UTIL_Replace( Out, "$AVGASSISTS$", avgassists ); - UTIL_Replace( Out, "$AVGNEUTRALKILLS$", avgneutralkills ); - UTIL_Replace( Out, "$AVGTOWERKILLS$", avgtowerkills ); - UTIL_Replace( Out, "$AVGRAXKILLS$", avgraxkills ); - UTIL_Replace( Out, "$AVGCOURIERKILLS$", avgcourierkills ); - return Out; -} - -string CLanguage :: HasntPlayedDotAGamesWithThisBot( string user ) -{ - string Out = m_CFG->GetString( "lang_0075", "lang_0075" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: WasKickedForReservedPlayer( string reserved ) -{ - string Out = m_CFG->GetString( "lang_0076", "lang_0076" ); - UTIL_Replace( Out, "$RESERVED$", reserved ); - return Out; -} - -string CLanguage :: WasKickedForOwnerPlayer( string owner ) -{ - string Out = m_CFG->GetString( "lang_0077", "lang_0077" ); - UTIL_Replace( Out, "$OWNER$", owner ); - return Out; -} - -string CLanguage :: WasKickedByPlayer( string user ) -{ - string Out = m_CFG->GetString( "lang_0078", "lang_0078" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: HasLostConnectionPlayerError( string error ) -{ - string Out = m_CFG->GetString( "lang_0079", "lang_0079" ); - UTIL_Replace( Out, "$ERROR$", error ); - return Out; -} - -string CLanguage :: HasLostConnectionSocketError( string error ) -{ - string Out = m_CFG->GetString( "lang_0080", "lang_0080" ); - UTIL_Replace( Out, "$ERROR$", error ); - return Out; -} - -string CLanguage :: HasLostConnectionClosedByRemoteHost( ) -{ - return m_CFG->GetString( "lang_0081", "lang_0081" ); -} - -string CLanguage :: HasLeftVoluntarily( ) -{ - return m_CFG->GetString( "lang_0082", "lang_0082" ); -} - -string CLanguage :: EndingGame( string description ) -{ - string Out = m_CFG->GetString( "lang_0083", "lang_0083" ); - UTIL_Replace( Out, "$DESCRIPTION$", description ); - return Out; -} - -string CLanguage :: HasLostConnectionTimedOut( ) -{ - return m_CFG->GetString( "lang_0084", "lang_0084" ); -} - -string CLanguage :: GlobalChatMuted( ) -{ - return m_CFG->GetString( "lang_0085", "lang_0085" ); -} - -string CLanguage :: GlobalChatUnmuted( ) -{ - return m_CFG->GetString( "lang_0086", "lang_0086" ); -} - -string CLanguage :: ShufflingPlayers( ) -{ - return m_CFG->GetString( "lang_0087", "lang_0087" ); -} - -string CLanguage :: UnableToLoadConfigFileGameInLobby( ) -{ - return m_CFG->GetString( "lang_0088", "lang_0088" ); -} - -string CLanguage :: PlayersStillDownloading( string stilldownloading ) -{ - string Out = m_CFG->GetString( "lang_0089", "lang_0089" ); - UTIL_Replace( Out, "$STILLDOWNLOADING$", stilldownloading ); - return Out; -} - -string CLanguage :: RefreshMessagesEnabled( ) -{ - return m_CFG->GetString( "lang_0090", "lang_0090" ); -} - -string CLanguage :: RefreshMessagesDisabled( ) -{ - return m_CFG->GetString( "lang_0091", "lang_0091" ); -} - -string CLanguage :: AtLeastOneGameActiveUseForceToShutdown( ) -{ - return m_CFG->GetString( "lang_0092", "lang_0092" ); -} - -string CLanguage :: CurrentlyLoadedMapCFGIs( string mapcfg ) -{ - string Out = m_CFG->GetString( "lang_0093", "lang_0093" ); - UTIL_Replace( Out, "$MAPCFG$", mapcfg ); - return Out; -} - -string CLanguage :: LaggedOutDroppedByAdmin( ) -{ - return m_CFG->GetString( "lang_0094", "lang_0094" ); -} - -string CLanguage :: LaggedOutDroppedByVote( ) -{ - return m_CFG->GetString( "lang_0095", "lang_0095" ); -} - -string CLanguage :: PlayerVotedToDropLaggers( string user ) -{ - string Out = m_CFG->GetString( "lang_0096", "lang_0096" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: LatencyIs( string latency ) -{ - string Out = m_CFG->GetString( "lang_0097", "lang_0097" ); - UTIL_Replace( Out, "$LATENCY$", latency ); - return Out; -} - -string CLanguage :: SyncLimitIs( string synclimit ) -{ - string Out = m_CFG->GetString( "lang_0098", "lang_0098" ); - UTIL_Replace( Out, "$SYNCLIMIT$", synclimit ); - return Out; -} - -string CLanguage :: SettingSyncLimitToMinimum( string min ) -{ - string Out = m_CFG->GetString( "lang_0099", "lang_0099" ); - UTIL_Replace( Out, "$MIN$", min ); - return Out; -} - -string CLanguage :: SettingSyncLimitToMaximum( string max ) -{ - string Out = m_CFG->GetString( "lang_0100", "lang_0100" ); - UTIL_Replace( Out, "$MAX$", max ); - return Out; -} - -string CLanguage :: SettingSyncLimitTo( string synclimit ) -{ - string Out = m_CFG->GetString( "lang_0101", "lang_0101" ); - UTIL_Replace( Out, "$SYNCLIMIT$", synclimit ); - return Out; -} - -string CLanguage :: UnableToCreateGameNotLoggedIn( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0102", "lang_0102" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: AdminLoggedIn( ) -{ - return m_CFG->GetString( "lang_0103", "lang_0103" ); -} - -string CLanguage :: AdminInvalidPassword( string attempt ) -{ - string Out = m_CFG->GetString( "lang_0104", "lang_0104" ); - UTIL_Replace( Out, "$ATTEMPT$", attempt ); - return Out; -} - -string CLanguage :: ConnectingToBNET( string server ) -{ - string Out = m_CFG->GetString( "lang_0105", "lang_0105" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: ConnectedToBNET( string server ) -{ - string Out = m_CFG->GetString( "lang_0106", "lang_0106" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: DisconnectedFromBNET( string server ) -{ - string Out = m_CFG->GetString( "lang_0107", "lang_0107" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: LoggedInToBNET( string server ) -{ - string Out = m_CFG->GetString( "lang_0108", "lang_0108" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: BNETGameHostingSucceeded( string server ) -{ - string Out = m_CFG->GetString( "lang_0109", "lang_0109" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: BNETGameHostingFailed( string server, string gamename ) -{ - string Out = m_CFG->GetString( "lang_0110", "lang_0110" ); - UTIL_Replace( Out, "$SERVER$", server ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: ConnectingToBNETTimedOut( string server ) -{ - string Out = m_CFG->GetString( "lang_0111", "lang_0111" ); - UTIL_Replace( Out, "$SERVER$", server ); - return Out; -} - -string CLanguage :: PlayerDownloadedTheMap( string user, string seconds, string rate ) -{ - string Out = m_CFG->GetString( "lang_0112", "lang_0112" ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$SECONDS$", seconds ); - UTIL_Replace( Out, "$RATE$", rate ); - return Out; -} - -string CLanguage :: UnableToCreateGameNameTooLong( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0113", "lang_0113" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: SettingGameOwnerTo( string owner ) -{ - string Out = m_CFG->GetString( "lang_0114", "lang_0114" ); - UTIL_Replace( Out, "$OWNER$", owner ); - return Out; -} - -string CLanguage :: TheGameIsLocked( ) -{ - return m_CFG->GetString( "lang_0115", "lang_0115" ); -} - -string CLanguage :: GameLocked( ) -{ - return m_CFG->GetString( "lang_0116", "lang_0116" ); -} - -string CLanguage :: GameUnlocked( ) -{ - return m_CFG->GetString( "lang_0117", "lang_0117" ); -} - -string CLanguage :: UnableToStartDownloadNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0118", "lang_0118" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UnableToStartDownloadFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0119", "lang_0119" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UnableToSetGameOwner( string owner ) -{ - string Out = m_CFG->GetString( "lang_0120", "lang_0120" ); - UTIL_Replace( Out, "$OWNER$", owner ); - return Out; -} - -string CLanguage :: UnableToCheckPlayerNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0121", "lang_0121" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: CheckedPlayer( string victim, string ping, string from, string admin, string owner, string spoofed, string spoofedrealm, string reserved ) -{ - string Out = m_CFG->GetString( "lang_0122", "lang_0122" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$PING$", ping ); - UTIL_Replace( Out, "$FROM$", from ); - UTIL_Replace( Out, "$ADMIN$", admin ); - UTIL_Replace( Out, "$OWNER$", owner ); - UTIL_Replace( Out, "$SPOOFED$", spoofed ); - UTIL_Replace( Out, "$SPOOFEDREALM$", spoofedrealm ); - UTIL_Replace( Out, "$RESERVED$", reserved ); - return Out; -} - -string CLanguage :: UnableToCheckPlayerFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0123", "lang_0123" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: TheGameIsLockedBNET( ) -{ - return m_CFG->GetString( "lang_0124", "lang_0124" ); -} - -string CLanguage :: UnableToCreateGameDisabled( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0125", "lang_0125" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: BotDisabled( ) -{ - return m_CFG->GetString( "lang_0126", "lang_0126" ); -} - -string CLanguage :: BotEnabled( ) -{ - return m_CFG->GetString( "lang_0127", "lang_0127" ); -} - -string CLanguage :: UnableToCreateGameInvalidMap( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0128", "lang_0128" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: WaitingForPlayersBeforeAutoStart( string players, string playersleft ) -{ - string Out = m_CFG->GetString( "lang_0129", "lang_0129" ); - UTIL_Replace( Out, "$PLAYERS$", players ); - UTIL_Replace( Out, "$PLAYERSLEFT$", playersleft ); - return Out; -} - -string CLanguage :: AutoStartDisabled( ) -{ - return m_CFG->GetString( "lang_0130", "lang_0130" ); -} - -string CLanguage :: AutoStartEnabled( string players ) -{ - string Out = m_CFG->GetString( "lang_0131", "lang_0131" ); - UTIL_Replace( Out, "$PLAYERS$", players ); - return Out; -} - -string CLanguage :: AnnounceMessageEnabled( ) -{ - return m_CFG->GetString( "lang_0132", "lang_0132" ); -} - -string CLanguage :: AnnounceMessageDisabled( ) -{ - return m_CFG->GetString( "lang_0133", "lang_0133" ); -} - -string CLanguage :: AutoHostEnabled( ) -{ - return m_CFG->GetString( "lang_0134", "lang_0134" ); -} - -string CLanguage :: AutoHostDisabled( ) -{ - return m_CFG->GetString( "lang_0135", "lang_0135" ); -} - -string CLanguage :: UnableToLoadSaveGamesOutside( ) -{ - return m_CFG->GetString( "lang_0136", "lang_0136" ); -} - -string CLanguage :: UnableToLoadSaveGameGameInLobby( ) -{ - return m_CFG->GetString( "lang_0137", "lang_0137" ); -} - -string CLanguage :: LoadingSaveGame( string file ) -{ - string Out = m_CFG->GetString( "lang_0138", "lang_0138" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: UnableToLoadSaveGameDoesntExist( string file ) -{ - string Out = m_CFG->GetString( "lang_0139", "lang_0139" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: UnableToCreateGameInvalidSaveGame( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0140", "lang_0140" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: UnableToCreateGameSaveGameMapMismatch( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0141", "lang_0141" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: AutoSaveEnabled( ) -{ - return m_CFG->GetString( "lang_0142", "lang_0142" ); -} - -string CLanguage :: AutoSaveDisabled( ) -{ - return m_CFG->GetString( "lang_0143", "lang_0143" ); -} - -string CLanguage :: DesyncDetected( ) -{ - return m_CFG->GetString( "lang_0144", "lang_0144" ); -} - -string CLanguage :: UnableToMuteNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0145", "lang_0145" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: MutedPlayer( string victim, string user ) -{ - string Out = m_CFG->GetString( "lang_0146", "lang_0146" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnmutedPlayer( string victim, string user ) -{ - string Out = m_CFG->GetString( "lang_0147", "lang_0147" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: UnableToMuteFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0148", "lang_0148" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: PlayerIsSavingTheGame( string player ) -{ - string Out = m_CFG->GetString( "lang_0149", "lang_0149" ); - UTIL_Replace( Out, "$PLAYER$", player ); - return Out; -} - -string CLanguage :: UpdatingClanList( ) -{ - return m_CFG->GetString( "lang_0150", "lang_0150" ); -} - -string CLanguage :: UpdatingFriendsList( ) -{ - return m_CFG->GetString( "lang_0151", "lang_0151" ); -} - -string CLanguage :: MultipleIPAddressUsageDetected( string player, string others ) -{ - string Out = m_CFG->GetString( "lang_0152", "lang_0152" ); - UTIL_Replace( Out, "$PLAYER$", player ); - UTIL_Replace( Out, "$OTHERS$", others ); - return Out; -} - -string CLanguage :: UnableToVoteKickAlreadyInProgress( ) -{ - return m_CFG->GetString( "lang_0153", "lang_0153" ); -} - -string CLanguage :: UnableToVoteKickNotEnoughPlayers( ) -{ - return m_CFG->GetString( "lang_0154", "lang_0154" ); -} - -string CLanguage :: UnableToVoteKickNoMatchesFound( string victim ) -{ - string Out = m_CFG->GetString( "lang_0155", "lang_0155" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: UnableToVoteKickPlayerIsReserved( string victim ) -{ - string Out = m_CFG->GetString( "lang_0156", "lang_0156" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: StartedVoteKick( string victim, string user, string votesneeded ) -{ - string Out = m_CFG->GetString( "lang_0157", "lang_0157" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$VOTESNEEDED$", votesneeded ); - return Out; -} - -string CLanguage :: UnableToVoteKickFoundMoreThanOneMatch( string victim ) -{ - string Out = m_CFG->GetString( "lang_0158", "lang_0158" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: VoteKickPassed( string victim ) -{ - string Out = m_CFG->GetString( "lang_0159", "lang_0159" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: ErrorVoteKickingPlayer( string victim ) -{ - string Out = m_CFG->GetString( "lang_0160", "lang_0160" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: VoteKickAcceptedNeedMoreVotes( string victim, string user, string votes ) -{ - string Out = m_CFG->GetString( "lang_0161", "lang_0161" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$USER$", user ); - UTIL_Replace( Out, "$VOTES$", votes ); - return Out; -} - -string CLanguage :: VoteKickCancelled( string victim ) -{ - string Out = m_CFG->GetString( "lang_0162", "lang_0162" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: VoteKickExpired( string victim ) -{ - string Out = m_CFG->GetString( "lang_0163", "lang_0163" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: WasKickedByVote( ) -{ - return m_CFG->GetString( "lang_0164", "lang_0164" ); -} - -string CLanguage :: TypeYesToVote( string commandtrigger ) -{ - string Out = m_CFG->GetString( "lang_0165", "lang_0165" ); - UTIL_Replace( Out, "$COMMANDTRIGGER$", commandtrigger ); - return Out; -} - -string CLanguage :: PlayersNotYetPingedAutoStart( string notpinged ) -{ - string Out = m_CFG->GetString( "lang_0166", "lang_0166" ); - UTIL_Replace( Out, "$NOTPINGED$", notpinged ); - return Out; -} - -string CLanguage :: WasKickedForNotSpoofChecking( ) -{ - return m_CFG->GetString( "lang_0167", "lang_0167" ); -} - -string CLanguage :: WasKickedForHavingFurthestScore( string score, string average ) -{ - string Out = m_CFG->GetString( "lang_0168", "lang_0168" ); - UTIL_Replace( Out, "$SCORE$", score ); - UTIL_Replace( Out, "$AVERAGE$", average ); - return Out; -} - -string CLanguage :: PlayerHasScore( string player, string score ) -{ - string Out = m_CFG->GetString( "lang_0169", "lang_0169" ); - UTIL_Replace( Out, "$PLAYER$", player ); - UTIL_Replace( Out, "$SCORE$", score ); - return Out; -} - -string CLanguage :: RatedPlayersSpread( string rated, string total, string spread ) -{ - string Out = m_CFG->GetString( "lang_0170", "lang_0170" ); - UTIL_Replace( Out, "$RATED$", rated ); - UTIL_Replace( Out, "$TOTAL$", total ); - UTIL_Replace( Out, "$SPREAD$", spread ); - return Out; -} - -string CLanguage :: ErrorListingMaps( ) -{ - return m_CFG->GetString( "lang_0171", "lang_0171" ); -} - -string CLanguage :: FoundMaps( string maps ) -{ - string Out = m_CFG->GetString( "lang_0172", "lang_0172" ); - UTIL_Replace( Out, "$MAPS$", maps ); - return Out; -} - -string CLanguage :: NoMapsFound( ) -{ - return m_CFG->GetString( "lang_0173", "lang_0173" ); -} - -string CLanguage :: ErrorListingMapConfigs( ) -{ - return m_CFG->GetString( "lang_0174", "lang_0174" ); -} - -string CLanguage :: FoundMapConfigs( string mapconfigs ) -{ - string Out = m_CFG->GetString( "lang_0175", "lang_0175" ); - UTIL_Replace( Out, "$MAPCONFIGS$", mapconfigs ); - return Out; -} - -string CLanguage :: NoMapConfigsFound( ) -{ - return m_CFG->GetString( "lang_0176", "lang_0176" ); -} - -string CLanguage :: PlayerFinishedLoading( string user ) -{ - string Out = m_CFG->GetString( "lang_0177", "lang_0177" ); - UTIL_Replace( Out, "$USER$", user ); - return Out; -} - -string CLanguage :: PleaseWaitPlayersStillLoading( ) -{ - return m_CFG->GetString( "lang_0178", "lang_0178" ); -} - -string CLanguage :: MapDownloadsDisabled( ) -{ - return m_CFG->GetString( "lang_0179", "lang_0179" ); -} - -string CLanguage :: MapDownloadsEnabled( ) -{ - return m_CFG->GetString( "lang_0180", "lang_0180" ); -} - -string CLanguage :: MapDownloadsConditional( ) -{ - return m_CFG->GetString( "lang_0181", "lang_0181" ); -} - -string CLanguage :: SettingHCL( string HCL ) -{ - string Out = m_CFG->GetString( "lang_0182", "lang_0182" ); - UTIL_Replace( Out, "$HCL$", HCL ); - return Out; -} - -string CLanguage :: UnableToSetHCLInvalid( ) -{ - return m_CFG->GetString( "lang_0183", "lang_0183" ); -} - -string CLanguage :: UnableToSetHCLTooLong( ) -{ - return m_CFG->GetString( "lang_0184", "lang_0184" ); -} - -string CLanguage :: TheHCLIs( string HCL ) -{ - string Out = m_CFG->GetString( "lang_0185", "lang_0185" ); - UTIL_Replace( Out, "$HCL$", HCL ); - return Out; -} - -string CLanguage :: TheHCLIsTooLongUseForceToStart( ) -{ - return m_CFG->GetString( "lang_0186", "lang_0186" ); -} - -string CLanguage :: ClearingHCL( ) -{ - return m_CFG->GetString( "lang_0187", "lang_0187" ); -} - -string CLanguage :: TryingToRehostAsPrivateGame( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0188", "lang_0188" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: TryingToRehostAsPublicGame( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0189", "lang_0189" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: RehostWasSuccessful( ) -{ - return m_CFG->GetString( "lang_0190", "lang_0190" ); -} - -string CLanguage :: TryingToJoinTheGameButBannedByName( string victim ) -{ - string Out = m_CFG->GetString( "lang_0191", "lang_0191" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: TryingToJoinTheGameButBannedByIP( string victim, string ip, string bannedname ) -{ - string Out = m_CFG->GetString( "lang_0192", "lang_0192" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$IP$", ip ); - UTIL_Replace( Out, "$BANNEDNAME$", bannedname ); - return Out; -} - -string CLanguage :: HasBannedName( string victim ) -{ - string Out = m_CFG->GetString( "lang_0193", "lang_0193" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - return Out; -} - -string CLanguage :: HasBannedIP( string victim, string ip, string bannedname ) -{ - string Out = m_CFG->GetString( "lang_0194", "lang_0194" ); - UTIL_Replace( Out, "$VICTIM$", victim ); - UTIL_Replace( Out, "$IP$", ip ); - UTIL_Replace( Out, "$BANNEDNAME$", bannedname ); - return Out; -} - -string CLanguage :: PlayersInGameState( string number, string players ) -{ - string Out = m_CFG->GetString( "lang_0195", "lang_0195" ); - UTIL_Replace( Out, "$NUMBER$", number ); - UTIL_Replace( Out, "$PLAYERS$", players ); - return Out; -} - -string CLanguage :: ValidServers( string servers ) -{ - string Out = m_CFG->GetString( "lang_0196", "lang_0196" ); - UTIL_Replace( Out, "$SERVERS$", servers ); - return Out; -} - -string CLanguage :: TeamCombinedScore( string team, string score ) -{ - string Out = m_CFG->GetString( "lang_0197", "lang_0197" ); - UTIL_Replace( Out, "$TEAM$", team ); - UTIL_Replace( Out, "$SCORE$", score ); - return Out; -} - -string CLanguage :: BalancingSlotsCompleted( ) -{ - return m_CFG->GetString( "lang_0198", "lang_0198" ); -} - -string CLanguage :: PlayerWasKickedForFurthestScore( string name, string score, string average ) -{ - string Out = m_CFG->GetString( "lang_0199", "lang_0199" ); - UTIL_Replace( Out, "$NAME$", name ); - UTIL_Replace( Out, "$SCORE$", score ); - UTIL_Replace( Out, "$AVERAGE$", average ); - return Out; -} - -string CLanguage :: LocalAdminMessagesEnabled( ) -{ - return m_CFG->GetString( "lang_0200", "lang_0200" ); -} - -string CLanguage :: LocalAdminMessagesDisabled( ) -{ - return m_CFG->GetString( "lang_0201", "lang_0201" ); -} - -string CLanguage :: WasDroppedDesync( ) -{ - return m_CFG->GetString( "lang_0202", "lang_0202" ); -} - -string CLanguage :: WasKickedForHavingLowestScore( string score ) -{ - string Out = m_CFG->GetString( "lang_0203", "lang_0203" ); - UTIL_Replace( Out, "$SCORE$", score ); - return Out; -} - -string CLanguage :: PlayerWasKickedForLowestScore( string name, string score ) -{ - string Out = m_CFG->GetString( "lang_0204", "lang_0204" ); - UTIL_Replace( Out, "$NAME$", name ); - UTIL_Replace( Out, "$SCORE$", score ); - return Out; -} - -string CLanguage :: ReloadingConfigurationFiles( ) -{ - return m_CFG->GetString( "lang_0205", "lang_0205" ); -} - -string CLanguage :: CountDownAbortedSomeoneLeftRecently( ) -{ - return m_CFG->GetString( "lang_0206", "lang_0206" ); -} - -string CLanguage :: UnableToCreateGameMustEnforceFirst( string gamename ) -{ - string Out = m_CFG->GetString( "lang_0207", "lang_0207" ); - UTIL_Replace( Out, "$GAMENAME$", gamename ); - return Out; -} - -string CLanguage :: UnableToLoadReplaysOutside( ) -{ - return m_CFG->GetString( "lang_0208", "lang_0208" ); -} - -string CLanguage :: LoadingReplay( string file ) -{ - string Out = m_CFG->GetString( "lang_0209", "lang_0209" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: UnableToLoadReplayDoesntExist( string file ) -{ - string Out = m_CFG->GetString( "lang_0210", "lang_0210" ); - UTIL_Replace( Out, "$FILE$", file ); - return Out; -} - -string CLanguage :: CommandTrigger( string trigger ) -{ - string Out = m_CFG->GetString( "lang_0211", "lang_0211" ); - UTIL_Replace( Out, "$TRIGGER$", trigger ); - return Out; -} - -string CLanguage :: CantEndGameOwnerIsStillPlaying( string owner ) -{ - string Out = m_CFG->GetString( "lang_0212", "lang_0212" ); - UTIL_Replace( Out, "$OWNER$", owner ); - return Out; -} - -string CLanguage :: CantUnhostGameOwnerIsPresent( string owner ) -{ - string Out = m_CFG->GetString( "lang_0213", "lang_0213" ); - UTIL_Replace( Out, "$OWNER$", owner ); - return Out; -} - -string CLanguage :: WasAutomaticallyDroppedAfterSeconds( string seconds ) -{ - string Out = m_CFG->GetString( "lang_0214", "lang_0214" ); - UTIL_Replace( Out, "$SECONDS$", seconds ); - return Out; -} - -string CLanguage :: HasLostConnectionTimedOutGProxy( ) -{ - return m_CFG->GetString( "lang_0215", "lang_0215" ); -} - -string CLanguage :: HasLostConnectionSocketErrorGProxy( string error ) -{ - string Out = m_CFG->GetString( "lang_0216", "lang_0216" ); - UTIL_Replace( Out, "$ERROR$", error ); - return Out; -} - -string CLanguage :: HasLostConnectionClosedByRemoteHostGProxy( ) -{ - return m_CFG->GetString( "lang_0217", "lang_0217" ); -} - -string CLanguage :: WaitForReconnectSecondsRemain( string seconds ) -{ - string Out = m_CFG->GetString( "lang_0218", "lang_0218" ); - UTIL_Replace( Out, "$SECONDS$", seconds ); - return Out; -} - -string CLanguage :: WasUnrecoverablyDroppedFromGProxy( ) -{ - return m_CFG->GetString( "lang_0219", "lang_0219" ); -} - -string CLanguage :: PlayerReconnectedWithGProxy( string name ) -{ - string Out = m_CFG->GetString( "lang_0220", "lang_0220" ); - UTIL_Replace( Out, "$NAME$", name ); - return Out; -} diff --git a/ghost/language.h b/ghost/language.h deleted file mode 100644 index 3d12a5c..0000000 --- a/ghost/language.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef LANGUAGE_H -#define LANGUAGE_H - -// -// CLanguage -// - -class CLanguage -{ -private: - CConfig *m_CFG; - -public: - CLanguage( string nCFGFile ); - ~CLanguage( ); - - string UnableToCreateGameTryAnotherName( string server, string gamename ); - string UserIsAlreadyAnAdmin( string server, string user ); - string AddedUserToAdminDatabase( string server, string user ); - string ErrorAddingUserToAdminDatabase( string server, string user ); - string YouDontHaveAccessToThatCommand( ); - string UserIsAlreadyBanned( string server, string victim ); - string BannedUser( string server, string victim ); - string ErrorBanningUser( string server, string victim ); - string UserIsAnAdmin( string server, string user ); - string UserIsNotAnAdmin( string server, string user ); - string UserWasBannedOnByBecause( string server, string victim, string date, string admin, string reason ); - string UserIsNotBanned( string server, string victim ); - string ThereAreNoAdmins( string server ); - string ThereIsAdmin( string server ); - string ThereAreAdmins( string server, string count ); - string ThereAreNoBannedUsers( string server ); - string ThereIsBannedUser( string server ); - string ThereAreBannedUsers( string server, string count ); - string YouCantDeleteTheRootAdmin( ); - string DeletedUserFromAdminDatabase( string server, string user ); - string ErrorDeletingUserFromAdminDatabase( string server, string user ); - string UnbannedUser( string victim ); - string ErrorUnbanningUser( string victim ); - string GameNumberIs( string number, string description ); - string GameNumberDoesntExist( string number ); - string GameIsInTheLobby( string description, string current, string max ); - string ThereIsNoGameInTheLobby( string current, string max ); - string UnableToLoadConfigFilesOutside( ); - string LoadingConfigFile( string file ); - string UnableToLoadConfigFileDoesntExist( string file ); - string CreatingPrivateGame( string gamename, string user ); - string CreatingPublicGame( string gamename, string user ); - string UnableToUnhostGameCountdownStarted( string description ); - string UnhostingGame( string description ); - string UnableToUnhostGameNoGameInLobby( ); - string VersionAdmin( string version ); - string VersionNotAdmin( string version ); - string UnableToCreateGameAnotherGameInLobby( string gamename, string description ); - string UnableToCreateGameMaxGamesReached( string gamename, string max ); - string GameIsOver( string description ); - string SpoofCheckByReplying( ); - string GameRefreshed( ); - string SpoofPossibleIsAway( string user ); - string SpoofPossibleIsUnavailable( string user ); - string SpoofPossibleIsRefusingMessages( string user ); - string SpoofDetectedIsNotInGame( string user ); - string SpoofDetectedIsInPrivateChannel( string user ); - string SpoofDetectedIsInAnotherGame( string user ); - string CountDownAborted( ); - string TryingToJoinTheGameButBanned( string victim ); - string UnableToBanNoMatchesFound( string victim ); - string PlayerWasBannedByPlayer( string server, string victim, string user ); - string UnableToBanFoundMoreThanOneMatch( string victim ); - string AddedPlayerToTheHoldList( string user ); - string UnableToKickNoMatchesFound( string victim ); - string UnableToKickFoundMoreThanOneMatch( string victim ); - string SettingLatencyToMinimum( string min ); - string SettingLatencyToMaximum( string max ); - string SettingLatencyTo( string latency ); - string KickingPlayersWithPingsGreaterThan( string total, string ping ); - string HasPlayedGamesWithThisBot( string user, string firstgame, string lastgame, string totalgames, string avgloadingtime, string avgstay ); - string HasntPlayedGamesWithThisBot( string user ); - string AutokickingPlayerForExcessivePing( string victim, string ping ); - string SpoofCheckAcceptedFor( string server, string user ); - string PlayersNotYetSpoofChecked( string notspoofchecked ); - string ManuallySpoofCheckByWhispering( string hostname ); - string SpoofCheckByWhispering( string hostname ); - string EveryoneHasBeenSpoofChecked( ); - string PlayersNotYetPinged( string notpinged ); - string EveryoneHasBeenPinged( ); - string ShortestLoadByPlayer( string user, string loadingtime ); - string LongestLoadByPlayer( string user, string loadingtime ); - string YourLoadingTimeWas( string loadingtime ); - string HasPlayedDotAGamesWithThisBot( string user, string totalgames, string totalwins, string totallosses, string totalkills, string totaldeaths, string totalcreepkills, string totalcreepdenies, string totalassists, string totalneutralkills, string totaltowerkills, string totalraxkills, string totalcourierkills, string avgkills, string avgdeaths, string avgcreepkills, string avgcreepdenies, string avgassists, string avgneutralkills, string avgtowerkills, string avgraxkills, string avgcourierkills ); - string HasntPlayedDotAGamesWithThisBot( string user ); - string WasKickedForReservedPlayer( string reserved ); - string WasKickedForOwnerPlayer( string owner ); - string WasKickedByPlayer( string user ); - string HasLostConnectionPlayerError( string error ); - string HasLostConnectionSocketError( string error ); - string HasLostConnectionClosedByRemoteHost( ); - string HasLeftVoluntarily( ); - string EndingGame( string description ); - string HasLostConnectionTimedOut( ); - string GlobalChatMuted( ); - string GlobalChatUnmuted( ); - string ShufflingPlayers( ); - string UnableToLoadConfigFileGameInLobby( ); - string PlayersStillDownloading( string stilldownloading ); - string RefreshMessagesEnabled( ); - string RefreshMessagesDisabled( ); - string AtLeastOneGameActiveUseForceToShutdown( ); - string CurrentlyLoadedMapCFGIs( string mapcfg ); - string LaggedOutDroppedByAdmin( ); - string LaggedOutDroppedByVote( ); - string PlayerVotedToDropLaggers( string user ); - string LatencyIs( string latency ); - string SyncLimitIs( string synclimit ); - string SettingSyncLimitToMinimum( string min ); - string SettingSyncLimitToMaximum( string max ); - string SettingSyncLimitTo( string synclimit ); - string UnableToCreateGameNotLoggedIn( string gamename ); - string AdminLoggedIn( ); - string AdminInvalidPassword( string attempt ); - string ConnectingToBNET( string server ); - string ConnectedToBNET( string server ); - string DisconnectedFromBNET( string server ); - string LoggedInToBNET( string server ); - string BNETGameHostingSucceeded( string server ); - string BNETGameHostingFailed( string server, string gamename ); - string ConnectingToBNETTimedOut( string server ); - string PlayerDownloadedTheMap( string user, string seconds, string rate ); - string UnableToCreateGameNameTooLong( string gamename ); - string SettingGameOwnerTo( string owner ); - string TheGameIsLocked( ); - string GameLocked( ); - string GameUnlocked( ); - string UnableToStartDownloadNoMatchesFound( string victim ); - string UnableToStartDownloadFoundMoreThanOneMatch( string victim ); - string UnableToSetGameOwner( string owner ); - string UnableToCheckPlayerNoMatchesFound( string victim ); - string CheckedPlayer( string victim, string ping, string from, string admin, string owner, string spoofed, string spoofedrealm, string reserved ); - string UnableToCheckPlayerFoundMoreThanOneMatch( string victim ); - string TheGameIsLockedBNET( ); - string UnableToCreateGameDisabled( string gamename ); - string BotDisabled( ); - string BotEnabled( ); - string UnableToCreateGameInvalidMap( string gamename ); - string WaitingForPlayersBeforeAutoStart( string players, string playersleft ); - string AutoStartDisabled( ); - string AutoStartEnabled( string players ); - string AnnounceMessageEnabled( ); - string AnnounceMessageDisabled( ); - string AutoHostEnabled( ); - string AutoHostDisabled( ); - string UnableToLoadSaveGamesOutside( ); - string UnableToLoadSaveGameGameInLobby( ); - string LoadingSaveGame( string file ); - string UnableToLoadSaveGameDoesntExist( string file ); - string UnableToCreateGameInvalidSaveGame( string gamename ); - string UnableToCreateGameSaveGameMapMismatch( string gamename ); - string AutoSaveEnabled( ); - string AutoSaveDisabled( ); - string DesyncDetected( ); - string UnableToMuteNoMatchesFound( string victim ); - string MutedPlayer( string victim, string user ); - string UnmutedPlayer( string victim, string user ); - string UnableToMuteFoundMoreThanOneMatch( string victim ); - string PlayerIsSavingTheGame( string player ); - string UpdatingClanList( ); - string UpdatingFriendsList( ); - string MultipleIPAddressUsageDetected( string player, string others ); - string UnableToVoteKickAlreadyInProgress( ); - string UnableToVoteKickNotEnoughPlayers( ); - string UnableToVoteKickNoMatchesFound( string victim ); - string UnableToVoteKickPlayerIsReserved( string victim ); - string StartedVoteKick( string victim, string user, string votesneeded ); - string UnableToVoteKickFoundMoreThanOneMatch( string victim ); - string VoteKickPassed( string victim ); - string ErrorVoteKickingPlayer( string victim ); - string VoteKickAcceptedNeedMoreVotes( string victim, string user, string votes ); - string VoteKickCancelled( string victim ); - string VoteKickExpired( string victim ); - string WasKickedByVote( ); - string TypeYesToVote( string commandtrigger ); - string PlayersNotYetPingedAutoStart( string notpinged ); - string WasKickedForNotSpoofChecking( ); - string WasKickedForHavingFurthestScore( string score, string average ); - string PlayerHasScore( string player, string score ); - string RatedPlayersSpread( string rated, string total, string spread ); - string ErrorListingMaps( ); - string FoundMaps( string maps ); - string NoMapsFound( ); - string ErrorListingMapConfigs( ); - string FoundMapConfigs( string mapconfigs ); - string NoMapConfigsFound( ); - string PlayerFinishedLoading( string user ); - string PleaseWaitPlayersStillLoading( ); - string MapDownloadsDisabled( ); - string MapDownloadsEnabled( ); - string MapDownloadsConditional( ); - string SettingHCL( string HCL ); - string UnableToSetHCLInvalid( ); - string UnableToSetHCLTooLong( ); - string TheHCLIs( string HCL ); - string TheHCLIsTooLongUseForceToStart( ); - string ClearingHCL( ); - string TryingToRehostAsPrivateGame( string gamename ); - string TryingToRehostAsPublicGame( string gamename ); - string RehostWasSuccessful( ); - string TryingToJoinTheGameButBannedByName( string victim ); - string TryingToJoinTheGameButBannedByIP( string victim, string ip, string bannedname ); - string HasBannedName( string victim ); - string HasBannedIP( string victim, string ip, string bannedname ); - string PlayersInGameState( string number, string players ); - string ValidServers( string servers ); - string TeamCombinedScore( string team, string score ); - string BalancingSlotsCompleted( ); - string PlayerWasKickedForFurthestScore( string name, string score, string average ); - string LocalAdminMessagesEnabled( ); - string LocalAdminMessagesDisabled( ); - string WasDroppedDesync( ); - string WasKickedForHavingLowestScore( string score ); - string PlayerWasKickedForLowestScore( string name, string score ); - string ReloadingConfigurationFiles( ); - string CountDownAbortedSomeoneLeftRecently( ); - string UnableToCreateGameMustEnforceFirst( string gamename ); - string UnableToLoadReplaysOutside( ); - string LoadingReplay( string file ); - string UnableToLoadReplayDoesntExist( string file ); - string CommandTrigger( string trigger ); - string CantEndGameOwnerIsStillPlaying( string owner ); - string CantUnhostGameOwnerIsPresent( string owner ); - string WasAutomaticallyDroppedAfterSeconds( string seconds ); - string HasLostConnectionTimedOutGProxy( ); - string HasLostConnectionSocketErrorGProxy( string error ); - string HasLostConnectionClosedByRemoteHostGProxy( ); - string WaitForReconnectSecondsRemain( string seconds ); - string WasUnrecoverablyDroppedFromGProxy( ); - string PlayerReconnectedWithGProxy( string name ); -}; - -#endif diff --git a/ghost/map.h b/ghost/map.h deleted file mode 100644 index 48acc3f..0000000 --- a/ghost/map.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef MAP_H -#define MAP_H - -#define MAPSPEED_SLOW 1 -#define MAPSPEED_NORMAL 2 -#define MAPSPEED_FAST 3 - -#define MAPVIS_HIDETERRAIN 1 -#define MAPVIS_EXPLORED 2 -#define MAPVIS_ALWAYSVISIBLE 3 -#define MAPVIS_DEFAULT 4 - -#define MAPOBS_NONE 1 -#define MAPOBS_ONDEFEAT 2 -#define MAPOBS_ALLOWED 3 -#define MAPOBS_REFEREES 4 - -#define MAPFLAG_TEAMSTOGETHER 1 -#define MAPFLAG_FIXEDTEAMS 2 -#define MAPFLAG_UNITSHARE 4 -#define MAPFLAG_RANDOMHERO 8 -#define MAPFLAG_RANDOMRACES 16 - -#define MAPOPT_HIDEMINIMAP 1 << 0 -#define MAPOPT_MODIFYALLYPRIORITIES 1 << 1 -#define MAPOPT_MELEE 1 << 2 // the bot cares about this one... -#define MAPOPT_REVEALTERRAIN 1 << 4 -#define MAPOPT_FIXEDPLAYERSETTINGS 1 << 5 // and this one... -#define MAPOPT_CUSTOMFORCES 1 << 6 // and this one, the rest don't affect the bot's logic -#define MAPOPT_CUSTOMTECHTREE 1 << 7 -#define MAPOPT_CUSTOMABILITIES 1 << 8 -#define MAPOPT_CUSTOMUPGRADES 1 << 9 -#define MAPOPT_WATERWAVESONCLIFFSHORES 1 << 11 -#define MAPOPT_WATERWAVESONSLOPESHORES 1 << 12 - -#define MAPFILTER_MAKER_USER 1 -#define MAPFILTER_MAKER_BLIZZARD 2 - -#define MAPFILTER_TYPE_MELEE 1 -#define MAPFILTER_TYPE_SCENARIO 2 - -#define MAPFILTER_SIZE_SMALL 1 -#define MAPFILTER_SIZE_MEDIUM 2 -#define MAPFILTER_SIZE_LARGE 4 - -#define MAPFILTER_OBS_FULL 1 -#define MAPFILTER_OBS_ONDEATH 2 -#define MAPFILTER_OBS_NONE 4 - -#define MAPGAMETYPE_UNKNOWN0 1 // always set except for saved games? -// AuthenticatedMakerBlizzard = 1 << 3 -// OfficialMeleeGame = 1 << 5 -#define MAPGAMETYPE_SAVEDGAME 1 << 9 -#define MAPGAMETYPE_PRIVATEGAME 1 << 11 -#define MAPGAMETYPE_MAKERUSER 1 << 13 -#define MAPGAMETYPE_MAKERBLIZZARD 1 << 14 -#define MAPGAMETYPE_TYPEMELEE 1 << 15 -#define MAPGAMETYPE_TYPESCENARIO 1 << 16 -#define MAPGAMETYPE_SIZESMALL 1 << 17 -#define MAPGAMETYPE_SIZEMEDIUM 1 << 18 -#define MAPGAMETYPE_SIZELARGE 1 << 19 -#define MAPGAMETYPE_OBSFULL 1 << 20 -#define MAPGAMETYPE_OBSONDEATH 1 << 21 -#define MAPGAMETYPE_OBSNONE 1 << 22 - -#include "gameslot.h" - -// -// CMap -// - -class CMap -{ -public: - CGHost *m_GHost; - -private: - bool m_Valid; - string m_CFGFile; - string m_MapPath; // config value: map path - BYTEARRAY m_MapSize; // config value: map size (4 bytes) - BYTEARRAY m_MapInfo; // config value: map info (4 bytes) -> this is the real CRC - BYTEARRAY m_MapCRC; // config value: map crc (4 bytes) -> this is not the real CRC, it's the "xoro" value - BYTEARRAY m_MapSHA1; // config value: map sha1 (20 bytes) - unsigned char m_MapSpeed; - unsigned char m_MapVisibility; - unsigned char m_MapObservers; - unsigned char m_MapFlags; - unsigned char m_MapFilterMaker; - unsigned char m_MapFilterType; - unsigned char m_MapFilterSize; - unsigned char m_MapFilterObs; - uint32_t m_MapOptions; - BYTEARRAY m_MapWidth; // config value: map width (2 bytes) - BYTEARRAY m_MapHeight; // config value: map height (2 bytes) - string m_MapType; // config value: map type (for stats class) - string m_MapMatchMakingCategory; // config value: map matchmaking category (for matchmaking) - string m_MapStatsW3MMDCategory; // config value: map stats w3mmd category (for saving w3mmd stats) - string m_MapDefaultHCL; // config value: map default HCL to use (this should really be specified elsewhere and not part of the map config) - uint32_t m_MapDefaultPlayerScore; // config value: map default player score (for matchmaking) - string m_MapLocalPath; // config value: map local path - bool m_MapLoadInGame; - string m_MapData; // the map data itself, for sending the map to players - uint32_t m_MapNumPlayers; - uint32_t m_MapNumTeams; - vector m_Slots; - -public: - CMap( CGHost *nGHost ); - CMap( CGHost *nGHost, CConfig *CFG, string nCFGFile ); - ~CMap( ); - - bool GetValid( ) { return m_Valid; } - string GetCFGFile( ) { return m_CFGFile; } - string GetMapPath( ) { return m_MapPath; } - BYTEARRAY GetMapSize( ) { return m_MapSize; } - BYTEARRAY GetMapInfo( ) { return m_MapInfo; } - BYTEARRAY GetMapCRC( ) { return m_MapCRC; } - BYTEARRAY GetMapSHA1( ) { return m_MapSHA1; } - unsigned char GetMapSpeed( ) { return m_MapSpeed; } - unsigned char GetMapVisibility( ) { return m_MapVisibility; } - unsigned char GetMapObservers( ) { return m_MapObservers; } - unsigned char GetMapFlags( ) { return m_MapFlags; } - BYTEARRAY GetMapGameFlags( ); - uint32_t GetMapGameType( ); - uint32_t GetMapOptions( ) { return m_MapOptions; } - unsigned char GetMapLayoutStyle( ); - BYTEARRAY GetMapWidth( ) { return m_MapWidth; } - BYTEARRAY GetMapHeight( ) { return m_MapHeight; } - string GetMapType( ) { return m_MapType; } - string GetMapMatchMakingCategory( ) { return m_MapMatchMakingCategory; } - string GetMapStatsW3MMDCategory( ) { return m_MapStatsW3MMDCategory; } - string GetMapDefaultHCL( ) { return m_MapDefaultHCL; } - uint32_t GetMapDefaultPlayerScore( ) { return m_MapDefaultPlayerScore; } - string GetMapLocalPath( ) { return m_MapLocalPath; } - bool GetMapLoadInGame( ) { return m_MapLoadInGame; } - string *GetMapData( ) { return &m_MapData; } - uint32_t GetMapNumPlayers( ) { return m_MapNumPlayers; } - uint32_t GetMapNumTeams( ) { return m_MapNumTeams; } - vector GetSlots( ) { return m_Slots; } - - void Load( CConfig *CFG, string nCFGFile ); - void CheckValid( ); - uint32_t XORRotateLeft( unsigned char *data, uint32_t length ); -}; - -#endif diff --git a/ghost/ms_stdint.h b/ghost/ms_stdint.h deleted file mode 100644 index e032ff1..0000000 --- a/ghost/ms_stdint.h +++ /dev/null @@ -1,232 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// For Visual Studio 6 in C++ mode wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#if (_MSC_VER < 1300) && defined(__cplusplus) - extern "C++" { -#endif -# include -#if (_MSC_VER < 1300) && defined(__cplusplus) - } -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] diff --git a/ghost/packed.h b/ghost/packed.h deleted file mode 100644 index d33b839..0000000 --- a/ghost/packed.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef PACKED_H -#define PACKED_H - -// -// CPacked -// - -class CCRC32; - -class CPacked -{ -public: - CCRC32 *m_CRC; - -protected: - bool m_Valid; - string m_Compressed; - string m_Decompressed; - uint32_t m_HeaderSize; - uint32_t m_CompressedSize; - uint32_t m_HeaderVersion; - uint32_t m_DecompressedSize; - uint32_t m_NumBlocks; - uint32_t m_War3Identifier; - uint32_t m_War3Version; - uint16_t m_BuildNumber; - uint16_t m_Flags; - uint32_t m_ReplayLength; - -public: - CPacked( ); - virtual ~CPacked( ); - - virtual bool GetValid( ) { return m_Valid; } - virtual uint32_t GetHeaderSize( ) { return m_HeaderSize; } - virtual uint32_t GetCompressedSize( ) { return m_CompressedSize; } - virtual uint32_t GetHeaderVersion( ) { return m_HeaderVersion; } - virtual uint32_t GetDecompressedSize( ) { return m_DecompressedSize; } - virtual uint32_t GetNumBlocks( ) { return m_NumBlocks; } - virtual uint32_t GetWar3Identifier( ) { return m_War3Identifier; } - virtual uint32_t GetWar3Version( ) { return m_War3Version; } - virtual uint16_t GetBuildNumber( ) { return m_BuildNumber; } - virtual uint16_t GetFlags( ) { return m_Flags; } - virtual uint32_t GetReplayLength( ) { return m_ReplayLength; } - - virtual void SetWar3Version( uint32_t nWar3Version ) { m_War3Version = nWar3Version; } - virtual void SetBuildNumber( uint16_t nBuildNumber ) { m_BuildNumber = nBuildNumber; } - virtual void SetFlags( uint16_t nFlags ) { m_Flags = nFlags; } - virtual void SetReplayLength( uint32_t nReplayLength ) { m_ReplayLength = nReplayLength; } - - virtual void Load( string fileName, bool allBlocks ); - virtual bool Save( bool TFT, string fileName ); - virtual bool Extract( string inFileName, string outFileName ); - virtual bool Pack( bool TFT, string inFileName, string outFileName ); - virtual void Decompress( bool allBlocks ); - virtual void Compress( bool TFT ); -}; - -#endif diff --git a/ghost/replay.h b/ghost/replay.h deleted file mode 100644 index b38a313..0000000 --- a/ghost/replay.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef REPLAY_H -#define REPLAY_H - -#include "gameslot.h" - -// -// CReplay -// - -class CIncomingAction; - -class CReplay : public CPacked -{ -public: - enum BlockID { - REPLAY_LEAVEGAME = 0x17, - REPLAY_FIRSTSTARTBLOCK = 0x1A, - REPLAY_SECONDSTARTBLOCK = 0x1B, - REPLAY_THIRDSTARTBLOCK = 0x1C, - REPLAY_TIMESLOT2 = 0x1E, // corresponds to W3GS_INCOMING_ACTION2 - REPLAY_TIMESLOT = 0x1F, // corresponds to W3GS_INCOMING_ACTION - REPLAY_CHATMESSAGE = 0x20, - REPLAY_CHECKSUM = 0x22, // corresponds to W3GS_OUTGOING_KEEPALIVE - REPLAY_DESYNC = 0x23 - }; - -private: - unsigned char m_HostPID; - string m_HostName; - string m_GameName; - string m_StatString; - uint32_t m_PlayerCount; - uint32_t m_MapGameType; - vector m_Players; - vector m_Slots; - uint32_t m_RandomSeed; - unsigned char m_SelectMode; // also known as the "layout style" elsewhere in this project - unsigned char m_StartSpotCount; - queue m_LoadingBlocks; - queue m_Blocks; - queue m_CheckSums; - string m_CompiledBlocks; - -public: - CReplay( ); - virtual ~CReplay( ); - - unsigned char GetHostPID( ) { return m_HostPID; } - string GetHostName( ) { return m_HostName; } - string GetGameName( ) { return m_GameName; } - string GetStatString( ) { return m_StatString; } - uint32_t GetPlayerCount( ) { return m_PlayerCount; } - uint32_t GetMapGameType( ) { return m_MapGameType; } - vector GetPlayers( ) { return m_Players; } - vector GetSlots( ) { return m_Slots; } - uint32_t GetRandomSeed( ) { return m_RandomSeed; } - unsigned char GetSelectMode( ) { return m_SelectMode; } - unsigned char GetStartSpotCount( ) { return m_StartSpotCount; } - queue *GetLoadingBlocks( ) { return &m_LoadingBlocks; } - queue *GetBlocks( ) { return &m_Blocks; } - queue *GetCheckSums( ) { return &m_CheckSums; } - - void AddPlayer( unsigned char nPID, string nName ) { m_Players.push_back( PIDPlayer( nPID, nName ) ); } - void SetSlots( vector nSlots ) { m_Slots = nSlots; } - void SetRandomSeed( uint32_t nRandomSeed ) { m_RandomSeed = nRandomSeed; } - void SetSelectMode( unsigned char nSelectMode ) { m_SelectMode = nSelectMode; } - void SetStartSpotCount( unsigned char nStartSpotCount ) { m_StartSpotCount = nStartSpotCount; } - void SetMapGameType( uint32_t nMapGameType ) { m_MapGameType = nMapGameType; } - void SetHostPID( unsigned char nHostPID ) { m_HostPID = nHostPID; } - void SetHostName( string nHostName ) { m_HostName = nHostName; } - - void AddLeaveGame( uint32_t reason, unsigned char PID, uint32_t result ); - void AddLeaveGameDuringLoading( uint32_t reason, unsigned char PID, uint32_t result ); - void AddTimeSlot2( queue actions ); - void AddTimeSlot( uint16_t timeIncrement, queue actions ); - void AddChatMessage( unsigned char PID, unsigned char flags, uint32_t chatMode, string message ); - void AddLoadingBlock( BYTEARRAY &loadingBlock ); - void BuildReplay( string gameName, string statString, uint32_t war3Version, uint16_t buildNumber ); - - void ParseReplay( bool parseBlocks ); -}; - -#endif diff --git a/ghost/socket.cpp b/ghost/socket.cpp deleted file mode 100644 index f25e915..0000000 --- a/ghost/socket.cpp +++ /dev/null @@ -1,797 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" -#include "socket.h" - -#include - -#ifndef WIN32 - int GetLastError( ) { return errno; } -#endif - -// -// CSocket -// - -CSocket :: CSocket( ) -{ - m_Socket = INVALID_SOCKET; - memset( &m_SIN, 0, sizeof( m_SIN ) ); - m_HasError = false; - m_Error = 0; -} - -CSocket :: CSocket( SOCKET nSocket, struct sockaddr_in nSIN ) -{ - m_Socket = nSocket; - m_SIN = nSIN; - m_HasError = false; - m_Error = 0; -} - -CSocket :: ~CSocket( ) -{ - if( m_Socket != INVALID_SOCKET ) - closesocket( m_Socket ); -} - -BYTEARRAY CSocket :: GetPort( ) -{ - return UTIL_CreateByteArray( m_SIN.sin_port, false ); -} - -BYTEARRAY CSocket :: GetIP( ) -{ - return UTIL_CreateByteArray( (uint32_t)m_SIN.sin_addr.s_addr, false ); -} - -string CSocket :: GetIPString( ) -{ - return inet_ntoa( m_SIN.sin_addr ); -} - -string CSocket :: GetErrorString( ) -{ - if( !m_HasError ) - return "NO ERROR"; - - switch( m_Error ) - { - case EWOULDBLOCK: return "EWOULDBLOCK"; - case EINPROGRESS: return "EINPROGRESS"; - case EALREADY: return "EALREADY"; - case ENOTSOCK: return "ENOTSOCK"; - case EDESTADDRREQ: return "EDESTADDRREQ"; - case EMSGSIZE: return "EMSGSIZE"; - case EPROTOTYPE: return "EPROTOTYPE"; - case ENOPROTOOPT: return "ENOPROTOOPT"; - case EPROTONOSUPPORT: return "EPROTONOSUPPORT"; - case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; - case EOPNOTSUPP: return "EOPNOTSUPP"; - case EPFNOSUPPORT: return "EPFNOSUPPORT"; - case EAFNOSUPPORT: return "EAFNOSUPPORT"; - case EADDRINUSE: return "EADDRINUSE"; - case EADDRNOTAVAIL: return "EADDRNOTAVAIL"; - case ENETDOWN: return "ENETDOWN"; - case ENETUNREACH: return "ENETUNREACH"; - case ENETRESET: return "ENETRESET"; - case ECONNABORTED: return "ECONNABORTED"; - case ECONNRESET: return "ECONNRESET"; - case ENOBUFS: return "ENOBUFS"; - case EISCONN: return "EISCONN"; - case ENOTCONN: return "ENOTCONN"; - case ESHUTDOWN: return "ESHUTDOWN"; - case ETOOMANYREFS: return "ETOOMANYREFS"; - case ETIMEDOUT: return "ETIMEDOUT"; - case ECONNREFUSED: return "ECONNREFUSED"; - case ELOOP: return "ELOOP"; - case ENAMETOOLONG: return "ENAMETOOLONG"; - case EHOSTDOWN: return "EHOSTDOWN"; - case EHOSTUNREACH: return "EHOSTUNREACH"; - case ENOTEMPTY: return "ENOTEMPTY"; - case EUSERS: return "EUSERS"; - case EDQUOT: return "EDQUOT"; - case ESTALE: return "ESTALE"; - case EREMOTE: return "EREMOTE"; - } - - return "UNKNOWN ERROR (" + UTIL_ToString( m_Error ) + ")"; -} - -void CSocket :: SetFD( fd_set *fd, fd_set *send_fd, int *nfds ) -{ - if( m_Socket == INVALID_SOCKET ) - return; - - FD_SET( m_Socket, fd ); - FD_SET( m_Socket, send_fd ); - -#ifndef WIN32 - if( m_Socket > *nfds ) - *nfds = m_Socket; -#endif -} - -void CSocket :: Allocate( int type ) -{ - m_Socket = socket( AF_INET, type, 0 ); - - if( m_Socket == INVALID_SOCKET ) - { - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[SOCKET] error (socket) - " + GetErrorString( ) ); - return; - } -} - -void CSocket :: Reset( ) -{ - if( m_Socket != INVALID_SOCKET ) - closesocket( m_Socket ); - - m_Socket = INVALID_SOCKET; - memset( &m_SIN, 0, sizeof( m_SIN ) ); - m_HasError = false; - m_Error = 0; -} - -// -// CTCPSocket -// - -CTCPSocket :: CTCPSocket( ) : CSocket( ) -{ - Allocate( SOCK_STREAM ); - m_Connected = false; - m_LastRecv = GetTime( ); - m_LastSend = GetTime( ); - - // make socket non blocking - -#ifdef WIN32 - int iMode = 1; - ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode ); -#else - fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK ); -#endif -} - -CTCPSocket :: CTCPSocket( SOCKET nSocket, struct sockaddr_in nSIN ) : CSocket( nSocket, nSIN ) -{ - m_Connected = true; - m_LastRecv = GetTime( ); - m_LastSend = GetTime( ); - - // make socket non blocking - -#ifdef WIN32 - int iMode = 1; - ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode ); -#else - fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK ); -#endif -} - -CTCPSocket :: ~CTCPSocket( ) -{ - -} - -void CTCPSocket :: Reset( ) -{ - CSocket :: Reset( ); - - Allocate( SOCK_STREAM ); - m_Connected = false; - m_RecvBuffer.clear( ); - m_SendBuffer.clear( ); - m_LastRecv = GetTime( ); - m_LastSend = GetTime( ); - - // make socket non blocking - -#ifdef WIN32 - int iMode = 1; - ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode ); -#else - fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK ); -#endif - - if( !m_LogFile.empty( ) ) - { - ofstream Log; - Log.open( m_LogFile.c_str( ), ios :: app ); - - if( !Log.fail( ) ) - { - Log << "----------RESET----------" << endl; - Log.close( ); - } - } -} - -void CTCPSocket :: PutBytes( string bytes ) -{ - m_SendBuffer += bytes; -} - -void CTCPSocket :: PutBytes( BYTEARRAY bytes ) -{ - m_SendBuffer += string( bytes.begin( ), bytes.end( ) ); -} - -void CTCPSocket :: DoRecv( fd_set *fd ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connected ) - return; - - if( FD_ISSET( m_Socket, fd ) ) - { - // data is waiting, receive it - - char buffer[1024]; - int c = recv( m_Socket, buffer, 1024, 0 ); - - if( c == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK ) - { - // receive error - - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPSOCKET] error (recv) - " + GetErrorString( ) ); - return; - } - else if( c == 0 ) - { - // the other end closed the connection - - CONSOLE_Print( "[TCPSOCKET] closed by remote host" ); - m_Connected = false; - } - else if( c > 0 ) - { - // success! add the received data to the buffer - - if( !m_LogFile.empty( ) ) - { - ofstream Log; - Log.open( m_LogFile.c_str( ), ios :: app ); - - if( !Log.fail( ) ) - { - Log << " RECEIVE <<< " << UTIL_ByteArrayToHexString( UTIL_CreateByteArray( (unsigned char *)buffer, c ) ) << endl; - Log.close( ); - } - } - - m_RecvBuffer += string( buffer, c ); - m_LastRecv = GetTime( ); - } - } -} - -void CTCPSocket :: DoSend( fd_set *send_fd ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connected || m_SendBuffer.empty( ) ) - return; - - if( FD_ISSET( m_Socket, send_fd ) ) - { - // socket is ready, send it - - int s = send( m_Socket, m_SendBuffer.c_str( ), (int)m_SendBuffer.size( ), MSG_NOSIGNAL ); - - if( s == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK ) - { - // send error - - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPSOCKET] error (send) - " + GetErrorString( ) ); - return; - } - else if( s > 0 ) - { - // success! only some of the data may have been sent, remove it from the buffer - - if( !m_LogFile.empty( ) ) - { - ofstream Log; - Log.open( m_LogFile.c_str( ), ios :: app ); - - if( !Log.fail( ) ) - { - Log << "SEND >>> " << UTIL_ByteArrayToHexString( BYTEARRAY( m_SendBuffer.begin( ), m_SendBuffer.begin( ) + s ) ) << endl; - Log.close( ); - } - } - - m_SendBuffer = m_SendBuffer.substr( s ); - m_LastSend = GetTime( ); - } - } -} - -void CTCPSocket :: Disconnect( ) -{ - if( m_Socket != INVALID_SOCKET ) - shutdown( m_Socket, SHUT_RDWR ); - - m_Connected = false; -} - -void CTCPSocket :: SetNoDelay( bool noDelay ) -{ - int OptVal = 0; - - if( noDelay ) - OptVal = 1; - - setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&OptVal, sizeof( int ) ); -} - -// -// CTCPClient -// - -CTCPClient :: CTCPClient( ) : CTCPSocket( ) -{ - m_Connecting = false; -} - -CTCPClient :: ~CTCPClient( ) -{ - -} - -void CTCPClient :: Reset( ) -{ - CTCPSocket :: Reset( ); - m_Connecting = false; -} - -void CTCPClient :: Disconnect( ) -{ - CTCPSocket :: Disconnect( ); - m_Connecting = false; -} - -void CTCPClient :: Connect( string localaddress, string address, uint16_t port ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError || m_Connecting || m_Connected ) - return; - - if( !localaddress.empty( ) ) - { - struct sockaddr_in LocalSIN; - memset( &LocalSIN, 0, sizeof( LocalSIN ) ); - LocalSIN.sin_family = AF_INET; - - if( ( LocalSIN.sin_addr.s_addr = inet_addr( localaddress.c_str( ) ) ) == INADDR_NONE ) - LocalSIN.sin_addr.s_addr = INADDR_ANY; - - LocalSIN.sin_port = htons( 0 ); - - if( bind( m_Socket, (struct sockaddr *)&LocalSIN, sizeof( LocalSIN ) ) == SOCKET_ERROR ) - { - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPCLIENT] error (bind) - " + GetErrorString( ) ); - return; - } - } - - // get IP address - - struct hostent *HostInfo; - uint32_t HostAddress; - HostInfo = gethostbyname( address.c_str( ) ); - - if( !HostInfo ) - { - m_HasError = true; - // m_Error = h_error; - CONSOLE_Print( "[TCPCLIENT] error (gethostbyname)" ); - return; - } - - memcpy( &HostAddress, HostInfo->h_addr, HostInfo->h_length ); - - // connect - - m_SIN.sin_family = AF_INET; - m_SIN.sin_addr.s_addr = HostAddress; - m_SIN.sin_port = htons( port ); - - if( connect( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR ) - { - if( GetLastError( ) != EINPROGRESS && GetLastError( ) != EWOULDBLOCK ) - { - // connect error - - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPCLIENT] error (connect) - " + GetErrorString( ) ); - return; - } - } - - m_Connecting = true; -} - -bool CTCPClient :: CheckConnect( ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connecting ) - return false; - - fd_set fd; - FD_ZERO( &fd ); - FD_SET( m_Socket, &fd ); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 0; - - // check if the socket is connected - -#ifdef WIN32 - if( select( 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR ) -#else - if( select( m_Socket + 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR ) -#endif - { - m_HasError = true; - m_Error = GetLastError( ); - return false; - } - - if( FD_ISSET( m_Socket, &fd ) ) - { - m_Connecting = false; - m_Connected = true; - return true; - } - - return false; -} - -// -// CTCPServer -// - -CTCPServer :: CTCPServer( ) : CTCPSocket( ) -{ - // set the socket to reuse the address in case it hasn't been released yet - - int optval = 1; - -#ifdef WIN32 - setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof( int ) ); -#else - setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof( int ) ); -#endif -} - -CTCPServer :: ~CTCPServer( ) -{ - -} - -bool CTCPServer :: Listen( string address, uint16_t port ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - m_SIN.sin_family = AF_INET; - - if( !address.empty( ) ) - { - if( ( m_SIN.sin_addr.s_addr = inet_addr( address.c_str( ) ) ) == INADDR_NONE ) - m_SIN.sin_addr.s_addr = INADDR_ANY; - } - else - m_SIN.sin_addr.s_addr = INADDR_ANY; - - m_SIN.sin_port = htons( port ); - - if( bind( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR ) - { - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPSERVER] error (bind) - " + GetErrorString( ) ); - return false; - } - - // listen, queue length 8 - - if( listen( m_Socket, 8 ) == SOCKET_ERROR ) - { - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[TCPSERVER] error (listen) - " + GetErrorString( ) ); - return false; - } - - return true; -} - -CTCPSocket *CTCPServer :: Accept( fd_set *fd ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return NULL; - - if( FD_ISSET( m_Socket, fd ) ) - { - // a connection is waiting, accept it - - struct sockaddr_in Addr; - int AddrLen = sizeof( Addr ); - SOCKET NewSocket; - -#ifdef WIN32 - if( ( NewSocket = accept( m_Socket, (struct sockaddr *)&Addr, &AddrLen ) ) == INVALID_SOCKET ) -#else - if( ( NewSocket = accept( m_Socket, (struct sockaddr *)&Addr, (socklen_t *)&AddrLen ) ) == INVALID_SOCKET ) -#endif - { - // accept error, ignore it - } - else - { - // success! return the new socket - - return new CTCPSocket( NewSocket, Addr ); - } - } - - return NULL; -} - -// -// CUDPSocket -// - -CUDPSocket :: CUDPSocket( ) : CSocket( ) -{ - Allocate( SOCK_DGRAM ); - - // enable broadcast support - - int OptVal = 1; - setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (const char *)&OptVal, sizeof( int ) ); - - // set default broadcast target - m_BroadcastTarget.s_addr = INADDR_BROADCAST; -} - -CUDPSocket :: ~CUDPSocket( ) -{ - -} - -bool CUDPSocket :: SendTo( struct sockaddr_in sin, BYTEARRAY message ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - string MessageString = string( message.begin( ), message.end( ) ); - - if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) - return false; - - return true; -} - -bool CUDPSocket :: SendTo( string address, uint16_t port, BYTEARRAY message ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - // get IP address - - struct hostent *HostInfo; - uint32_t HostAddress; - HostInfo = gethostbyname( address.c_str( ) ); - - if( !HostInfo ) - { - m_HasError = true; - // m_Error = h_error; - CONSOLE_Print( "[UDPSOCKET] error (gethostbyname)" ); - return false; - } - - memcpy( &HostAddress, HostInfo->h_addr, HostInfo->h_length ); - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = HostAddress; - sin.sin_port = htons( port ); - - return SendTo( sin, message ); -} - -bool CUDPSocket :: Broadcast( uint16_t port, BYTEARRAY message ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = m_BroadcastTarget.s_addr; - sin.sin_port = htons( port ); - - string MessageString = string( message.begin( ), message.end( ) ); - - if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) - { - CONSOLE_Print( "[UDPSOCKET] failed to broadcast packet (port " + UTIL_ToString( port ) + ", size " + UTIL_ToString( MessageString.size( ) ) + " bytes)" ); - return false; - } - - return true; -} - -void CUDPSocket :: SetBroadcastTarget( string subnet ) -{ - if( subnet.empty( ) ) - { - CONSOLE_Print( "[UDPSOCKET] using default broadcast target" ); - m_BroadcastTarget.s_addr = INADDR_BROADCAST; - } - else - { - // this function does not check whether the given subnet is a valid subnet the user is on - // convert string representation of ip/subnet to in_addr - - CONSOLE_Print( "[UDPSOCKET] using broadcast target [" + subnet + "]" ); - m_BroadcastTarget.s_addr = inet_addr( subnet.c_str( ) ); - - // if conversion fails, inet_addr( ) returns INADDR_NONE - - if( m_BroadcastTarget.s_addr == INADDR_NONE ) - { - CONSOLE_Print( "[UDPSOCKET] invalid broadcast target, using default broadcast target" ); - m_BroadcastTarget.s_addr = INADDR_BROADCAST; - } - } -} - -void CUDPSocket :: SetDontRoute( bool dontRoute ) -{ - int OptVal = 0; - - if( dontRoute ) - OptVal = 1; - - // don't route packets; make them ignore routes set by routing table and send them to the interface - // belonging to the target address directly - - setsockopt( m_Socket, SOL_SOCKET, SO_DONTROUTE, (const char *)&OptVal, sizeof( int ) ); -} - -// -// CUDPServer -// - -CUDPServer :: CUDPServer( ) : CUDPSocket( ) -{ - // make socket non blocking - -#ifdef WIN32 - int iMode = 1; - ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode ); -#else - fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK ); -#endif - - // set the socket to reuse the address - // with UDP sockets this allows more than one program to listen on the same port - - int optval = 1; - -#ifdef WIN32 - setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof( int ) ); -#else - setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof( int ) ); -#endif -} - -CUDPServer :: ~CUDPServer( ) -{ - -} - -bool CUDPServer :: Bind( struct sockaddr_in sin ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - m_SIN = sin; - - if( bind( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR ) - { - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[UDPSERVER] error (bind) - " + GetErrorString( ) ); - return false; - } - - return true; -} - -bool CUDPServer :: Bind( string address, uint16_t port ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError ) - return false; - - struct sockaddr_in sin; - sin.sin_family = AF_INET; - - if( !address.empty( ) ) - { - if( ( sin.sin_addr.s_addr = inet_addr( address.c_str( ) ) ) == INADDR_NONE ) - sin.sin_addr.s_addr = INADDR_ANY; - } - else - sin.sin_addr.s_addr = INADDR_ANY; - - sin.sin_port = htons( port ); - - return Bind( sin ); -} - -void CUDPServer :: RecvFrom( fd_set *fd, struct sockaddr_in *sin, string *message ) -{ - if( m_Socket == INVALID_SOCKET || m_HasError || !sin || !message ) - return; - - int AddrLen = sizeof( *sin ); - - if( FD_ISSET( m_Socket, fd ) ) - { - // data is waiting, receive it - - char buffer[1024]; - -#ifdef WIN32 - int c = recvfrom( m_Socket, buffer, 1024, 0, (struct sockaddr *)sin, &AddrLen ); -#else - int c = recvfrom( m_Socket, buffer, 1024, 0, (struct sockaddr *)sin, (socklen_t *)&AddrLen ); -#endif - - if( c == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK ) - { - // receive error - - m_HasError = true; - m_Error = GetLastError( ); - CONSOLE_Print( "[UDPSERVER] error (recvfrom) - " + GetErrorString( ) ); - } - else if( c > 0 ) - { - // success! - - *message = string( buffer, c ); - } - } -} diff --git a/ghost/socket.h b/ghost/socket.h deleted file mode 100644 index 8fa879b..0000000 --- a/ghost/socket.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef SOCKET_H -#define SOCKET_H - -#ifdef WIN32 - #include - #include - - #define EADDRINUSE WSAEADDRINUSE - #define EADDRNOTAVAIL WSAEADDRNOTAVAIL - #define EAFNOSUPPORT WSAEAFNOSUPPORT - #define EALREADY WSAEALREADY - #define ECONNABORTED WSAECONNABORTED - #define ECONNREFUSED WSAECONNREFUSED - #define ECONNRESET WSAECONNRESET - #define EDESTADDRREQ WSAEDESTADDRREQ - #define EDQUOT WSAEDQUOT - #define EHOSTDOWN WSAEHOSTDOWN - #define EHOSTUNREACH WSAEHOSTUNREACH - #define EINPROGRESS WSAEINPROGRESS - #define EISCONN WSAEISCONN - #define ELOOP WSAELOOP - #define EMSGSIZE WSAEMSGSIZE - // #define ENAMETOOLONG WSAENAMETOOLONG - #define ENETDOWN WSAENETDOWN - #define ENETRESET WSAENETRESET - #define ENETUNREACH WSAENETUNREACH - #define ENOBUFS WSAENOBUFS - #define ENOPROTOOPT WSAENOPROTOOPT - #define ENOTCONN WSAENOTCONN - // #define ENOTEMPTY WSAENOTEMPTY - #define ENOTSOCK WSAENOTSOCK - #define EOPNOTSUPP WSAEOPNOTSUPP - #define EPFNOSUPPORT WSAEPFNOSUPPORT - #define EPROTONOSUPPORT WSAEPROTONOSUPPORT - #define EPROTOTYPE WSAEPROTOTYPE - #define EREMOTE WSAEREMOTE - #define ESHUTDOWN WSAESHUTDOWN - #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT - #define ESTALE WSAESTALE - #define ETIMEDOUT WSAETIMEDOUT - #define ETOOMANYREFS WSAETOOMANYREFS - #define EUSERS WSAEUSERS - #define EWOULDBLOCK WSAEWOULDBLOCK -#else - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - typedef int SOCKET; - - #define INVALID_SOCKET -1 - #define SOCKET_ERROR -1 - - #define closesocket close - - extern int GetLastError( ); -#endif - -#ifndef INADDR_NONE - #define INADDR_NONE -1 -#endif - -#ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 -#endif - -#ifdef WIN32 - #define SHUT_RDWR 2 -#endif - -// -// CSocket -// - -class CSocket -{ -protected: - SOCKET m_Socket; - struct sockaddr_in m_SIN; - bool m_HasError; - int m_Error; - -public: - CSocket( ); - CSocket( SOCKET nSocket, struct sockaddr_in nSIN ); - ~CSocket( ); - - virtual BYTEARRAY GetPort( ); - virtual BYTEARRAY GetIP( ); - virtual string GetIPString( ); - virtual bool HasError( ) { return m_HasError; } - virtual int GetError( ) { return m_Error; } - virtual string GetErrorString( ); - virtual void SetFD( fd_set *fd, fd_set *send_fd, int *nfds ); - virtual void Allocate( int type ); - virtual void Reset( ); -}; - -// -// CTCPSocket -// - -class CTCPSocket : public CSocket -{ -protected: - bool m_Connected; - string m_LogFile; - -private: - string m_RecvBuffer; - string m_SendBuffer; - uint32_t m_LastRecv; - uint32_t m_LastSend; - -public: - CTCPSocket( ); - CTCPSocket( SOCKET nSocket, struct sockaddr_in nSIN ); - virtual ~CTCPSocket( ); - - virtual void Reset( ); - virtual bool GetConnected( ) { return m_Connected; } - virtual string *GetBytes( ) { return &m_RecvBuffer; } - virtual void PutBytes( string bytes ); - virtual void PutBytes( BYTEARRAY bytes ); - virtual void ClearRecvBuffer( ) { m_RecvBuffer.clear( ); } - virtual void ClearSendBuffer( ) { m_SendBuffer.clear( ); } - virtual uint32_t GetLastRecv( ) { return m_LastRecv; } - virtual uint32_t GetLastSend( ) { return m_LastSend; } - virtual void DoRecv( fd_set *fd ); - virtual void DoSend( fd_set *send_fd ); - virtual void Disconnect( ); - virtual void SetNoDelay( bool noDelay ); - virtual void SetLogFile( string nLogFile ) { m_LogFile = nLogFile; } -}; - -// -// CTCPClient -// - -class CTCPClient : public CTCPSocket -{ -protected: - bool m_Connecting; - -public: - CTCPClient( ); - virtual ~CTCPClient( ); - - virtual void Reset( ); - virtual void Disconnect( ); - virtual bool GetConnecting( ) { return m_Connecting; } - virtual void Connect( string localaddress, string address, uint16_t port ); - virtual bool CheckConnect( ); -}; - -// -// CTCPServer -// - -class CTCPServer : public CTCPSocket -{ -public: - CTCPServer( ); - virtual ~CTCPServer( ); - - virtual bool Listen( string address, uint16_t port ); - virtual CTCPSocket *Accept( fd_set *fd ); -}; - -// -// CUDPSocket -// - -class CUDPSocket : public CSocket -{ -protected: - struct in_addr m_BroadcastTarget; -public: - CUDPSocket( ); - virtual ~CUDPSocket( ); - - virtual bool SendTo( struct sockaddr_in sin, BYTEARRAY message ); - virtual bool SendTo( string address, uint16_t port, BYTEARRAY message ); - virtual bool Broadcast( uint16_t port, BYTEARRAY message ); - virtual void SetBroadcastTarget( string subnet ); - virtual void SetDontRoute( bool dontRoute ); -}; - -// -// CUDPServer -// - -class CUDPServer : public CUDPSocket -{ -public: - CUDPServer( ); - virtual ~CUDPServer( ); - - virtual bool Bind( struct sockaddr_in sin ); - virtual bool Bind( string address, uint16_t port ); - virtual void RecvFrom( fd_set *fd, struct sockaddr_in *sin, string *message ); -}; - -#endif diff --git a/ghost/statsw3mmd.h b/ghost/statsw3mmd.h deleted file mode 100644 index b6ed218..0000000 --- a/ghost/statsw3mmd.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef STATSW3MMD_H -#define STATSW3MMD_H - -// -// CStatsW3MMD -// - -typedef pair VarP; - -class CStatsW3MMD : public CStats -{ -private: - string m_Category; - uint32_t m_NextValueID; - uint32_t m_NextCheckID; - map m_PIDToName; // pid -> player name (e.g. 0 -> "Varlock") --- note: will not be automatically converted to lower case - map m_Flags; // pid -> flag (e.g. 0 -> "winner") - map m_FlagsLeaver; // pid -> leaver flag (e.g. 0 -> true) --- note: will only be present if true - map m_FlagsPracticing; // pid -> practice flag (e.g. 0 -> true) --- note: will only be present if true - map m_DefVarPs; // varname -> value type (e.g. "kills" -> "int") - map m_VarPInts; // pid,varname -> value (e.g. 0,"kills" -> 5) - map m_VarPReals; // pid,varname -> value (e.g. 0,"x" -> 0.8) - map m_VarPStrings; // pid,varname -> value (e.g. 0,"hero" -> "heroname") - map > m_DefEvents; // event -> vector of arguments + format - -public: - CStatsW3MMD( CBaseGame *nGame, string nCategory ); - virtual ~CStatsW3MMD( ); - - virtual bool ProcessAction( CIncomingAction *Action ); - virtual void Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ); - virtual vector TokenizeKey( string key ); -}; - -#endif diff --git a/ghost/util.cpp b/ghost/util.cpp deleted file mode 100644 index 6f158c0..0000000 --- a/ghost/util.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#include "ghost.h" -#include "util.h" - -#include - -BYTEARRAY UTIL_CreateByteArray( unsigned char *a, int size ) -{ - if( size < 1 ) - return BYTEARRAY( ); - - return BYTEARRAY( a, a + size ); -} - -BYTEARRAY UTIL_CreateByteArray( unsigned char c ) -{ - BYTEARRAY result; - result.push_back( c ); - return result; -} - -BYTEARRAY UTIL_CreateByteArray( uint16_t i, bool reverse ) -{ - BYTEARRAY result; - result.push_back( (unsigned char)i ); - result.push_back( (unsigned char)( i >> 8 ) ); - - if( reverse ) - return BYTEARRAY( result.rbegin( ), result.rend( ) ); - else - return result; -} - -BYTEARRAY UTIL_CreateByteArray( uint32_t i, bool reverse ) -{ - BYTEARRAY result; - result.push_back( (unsigned char)i ); - result.push_back( (unsigned char)( i >> 8 ) ); - result.push_back( (unsigned char)( i >> 16 ) ); - result.push_back( (unsigned char)( i >> 24 ) ); - - if( reverse ) - return BYTEARRAY( result.rbegin( ), result.rend( ) ); - else - return result; -} - -uint16_t UTIL_ByteArrayToUInt16( BYTEARRAY b, bool reverse, unsigned int start ) -{ - if( b.size( ) < start + 2 ) - return 0; - - BYTEARRAY temp = BYTEARRAY( b.begin( ) + start, b.begin( ) + start + 2 ); - - if( reverse ) - temp = BYTEARRAY( temp.rbegin( ), temp.rend( ) ); - - return (uint16_t)( temp[1] << 8 | temp[0] ); -} - -uint32_t UTIL_ByteArrayToUInt32( BYTEARRAY b, bool reverse, unsigned int start ) -{ - if( b.size( ) < start + 4 ) - return 0; - - BYTEARRAY temp = BYTEARRAY( b.begin( ) + start, b.begin( ) + start + 4 ); - - if( reverse ) - temp = BYTEARRAY( temp.rbegin( ), temp.rend( ) ); - - return (uint32_t)( temp[3] << 24 | temp[2] << 16 | temp[1] << 8 | temp[0] ); -} - -string UTIL_ByteArrayToDecString( BYTEARRAY b ) -{ - if( b.empty( ) ) - return string( ); - - string result = UTIL_ToString( b[0] ); - - for( BYTEARRAY :: iterator i = b.begin( ) + 1; i != b.end( ); i++ ) - result += " " + UTIL_ToString( *i ); - - return result; -} - -string UTIL_ByteArrayToHexString( BYTEARRAY b ) -{ - if( b.empty( ) ) - return string( ); - - string result = UTIL_ToHexString( b[0] ); - - for( BYTEARRAY :: iterator i = b.begin( ) + 1; i != b.end( ); i++ ) - { - if( *i < 16 ) - result += " 0" + UTIL_ToHexString( *i ); - else - result += " " + UTIL_ToHexString( *i ); - } - - return result; -} - -void UTIL_AppendByteArray( BYTEARRAY &b, BYTEARRAY append ) -{ - b.insert( b.end( ), append.begin( ), append.end( ) ); -} - -void UTIL_AppendByteArrayFast( BYTEARRAY &b, BYTEARRAY &append ) -{ - b.insert( b.end( ), append.begin( ), append.end( ) ); -} - -void UTIL_AppendByteArray( BYTEARRAY &b, unsigned char *a, int size ) -{ - UTIL_AppendByteArray( b, UTIL_CreateByteArray( a, size ) ); -} - -void UTIL_AppendByteArray( BYTEARRAY &b, string append, bool terminator ) -{ - // append the string plus a null terminator - - b.insert( b.end( ), append.begin( ), append.end( ) ); - - if( terminator ) - b.push_back( 0 ); -} - -void UTIL_AppendByteArrayFast( BYTEARRAY &b, string &append, bool terminator ) -{ - // append the string plus a null terminator - - b.insert( b.end( ), append.begin( ), append.end( ) ); - - if( terminator ) - b.push_back( 0 ); -} - -void UTIL_AppendByteArray( BYTEARRAY &b, uint16_t i, bool reverse ) -{ - UTIL_AppendByteArray( b, UTIL_CreateByteArray( i, reverse ) ); -} - -void UTIL_AppendByteArray( BYTEARRAY &b, uint32_t i, bool reverse ) -{ - UTIL_AppendByteArray( b, UTIL_CreateByteArray( i, reverse ) ); -} - -BYTEARRAY UTIL_ExtractCString( BYTEARRAY &b, unsigned int start ) -{ - // start searching the byte array at position 'start' for the first null value - // if found, return the subarray from 'start' to the null value but not including the null value - - if( start < b.size( ) ) - { - for( unsigned int i = start; i < b.size( ); i++ ) - { - if( b[i] == 0 ) - return BYTEARRAY( b.begin( ) + start, b.begin( ) + i ); - } - - // no null value found, return the rest of the byte array - - return BYTEARRAY( b.begin( ) + start, b.end( ) ); - } - - return BYTEARRAY( ); -} - -unsigned char UTIL_ExtractHex( BYTEARRAY &b, unsigned int start, bool reverse ) -{ - // consider the byte array to contain a 2 character ASCII encoded hex value at b[start] and b[start + 1] e.g. "FF" - // extract it as a single decoded byte - - if( start + 1 < b.size( ) ) - { - unsigned int c; - string temp = string( b.begin( ) + start, b.begin( ) + start + 2 ); - - if( reverse ) - temp = string( temp.rend( ), temp.rbegin( ) ); - - stringstream SS; - SS << temp; - SS >> hex >> c; - return c; - } - - return 0; -} - -BYTEARRAY UTIL_ExtractNumbers( string s, unsigned int count ) -{ - // consider the string to contain a bytearray in dec-text form, e.g. "52 99 128 1" - - BYTEARRAY result; - unsigned int c; - stringstream SS; - SS << s; - - for( unsigned int i = 0; i < count; i++ ) - { - if( SS.eof( ) ) - break; - - SS >> c; - - // todotodo: if c > 255 handle the error instead of truncating - - result.push_back( (unsigned char)c ); - } - - return result; -} - -BYTEARRAY UTIL_ExtractHexNumbers( string s ) -{ - // consider the string to contain a bytearray in hex-text form, e.g. "4e 17 b7 e6" - - BYTEARRAY result; - unsigned int c; - stringstream SS; - SS << s; - - while( !SS.eof( ) ) - { - SS >> hex >> c; - - // todotodo: if c > 255 handle the error instead of truncating - - result.push_back( (unsigned char)c ); - } - - return result; -} - -string UTIL_ToString( unsigned long i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( unsigned short i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( unsigned int i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( long i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( short i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( int i ) -{ - string result; - stringstream SS; - SS << i; - SS >> result; - return result; -} - -string UTIL_ToString( float f, int digits ) -{ - string result; - stringstream SS; - SS << std :: fixed << std :: setprecision( digits ) << f; - SS >> result; - return result; -} - -string UTIL_ToString( double d, int digits ) -{ - string result; - stringstream SS; - SS << std :: fixed << std :: setprecision( digits ) << d; - SS >> result; - return result; -} - -string UTIL_ToHexString( uint32_t i ) -{ - string result; - stringstream SS; - SS << std :: hex << i; - SS >> result; - return result; -} - -// todotodo: these UTIL_ToXXX functions don't fail gracefully, they just return garbage (in the uint case usually just -1 casted to an unsigned type it looks like) - -uint16_t UTIL_ToUInt16( string &s ) -{ - uint16_t result; - stringstream SS; - SS << s; - SS >> result; - return result; -} - -uint32_t UTIL_ToUInt32( string &s ) -{ - uint32_t result; - stringstream SS; - SS << s; - SS >> result; - return result; -} - -int16_t UTIL_ToInt16( string &s ) -{ - int16_t result; - stringstream SS; - SS << s; - SS >> result; - return result; -} - -int32_t UTIL_ToInt32( string &s ) -{ - int32_t result; - stringstream SS; - SS << s; - SS >> result; - return result; -} - -double UTIL_ToDouble( string &s ) -{ - double result; - stringstream SS; - SS << s; - SS >> result; - return result; -} - -string UTIL_MSToString( uint32_t ms ) -{ - string MinString = UTIL_ToString( ( ms / 1000 ) / 60 ); - string SecString = UTIL_ToString( ( ms / 1000 ) % 60 ); - - if( MinString.size( ) == 1 ) - MinString.insert( 0, "0" ); - - if( SecString.size( ) == 1 ) - SecString.insert( 0, "0" ); - - return MinString + "m" + SecString + "s"; -} - -bool UTIL_FileExists( string file ) -{ - struct stat fileinfo; - - if( stat( file.c_str( ), &fileinfo ) == 0 ) - return true; - - return false; -} - -string UTIL_FileRead( string file, uint32_t start, uint32_t length ) -{ - ifstream IS; - IS.open( file.c_str( ), ios :: binary ); - - if( IS.fail( ) ) - { - CONSOLE_Print( "[UTIL] warning - unable to read file part [" + file + "]" ); - return string( ); - } - - // get length of file - - IS.seekg( 0, ios :: end ); - uint32_t FileLength = IS.tellg( ); - - if( start > FileLength ) - { - IS.close( ); - return string( ); - } - - IS.seekg( start, ios :: beg ); - - // read data - - char *Buffer = new char[length]; - IS.read( Buffer, length ); - string BufferString = string( Buffer, IS.gcount( ) ); - IS.close( ); - delete [] Buffer; - return BufferString; -} - -string UTIL_FileRead( string file ) -{ - ifstream IS; - IS.open( file.c_str( ), ios :: binary ); - - if( IS.fail( ) ) - { - CONSOLE_Print( "[UTIL] warning - unable to read file [" + file + "]" ); - return string( ); - } - - // get length of file - - IS.seekg( 0, ios :: end ); - uint32_t FileLength = IS.tellg( ); - IS.seekg( 0, ios :: beg ); - - // read data - - char *Buffer = new char[FileLength]; - IS.read( Buffer, FileLength ); - string BufferString = string( Buffer, IS.gcount( ) ); - IS.close( ); - delete [] Buffer; - - if( BufferString.size( ) == FileLength ) - return BufferString; - else - return string( ); -} - -bool UTIL_FileWrite( string file, unsigned char *data, uint32_t length ) -{ - ofstream OS; - OS.open( file.c_str( ), ios :: binary ); - - if( OS.fail( ) ) - { - CONSOLE_Print( "[UTIL] warning - unable to write file [" + file + "]" ); - return false; - } - - // write data - - OS.write( (const char *)data, length ); - OS.close( ); - return true; -} - -string UTIL_FileSafeName( string fileName ) -{ - string :: size_type BadStart = fileName.find_first_of( "\\/:*?<>|" ); - - while( BadStart != string :: npos ) - { - fileName.replace( BadStart, 1, 1, '_' ); - BadStart = fileName.find_first_of( "\\/:*?<>|" ); - } - - return fileName; -} - -string UTIL_AddPathSeperator( string path ) -{ - if( path.empty( ) ) - return string( ); - -#ifdef WIN32 - char Seperator = '\\'; -#else - char Seperator = '/'; -#endif - - if( *(path.end( ) - 1) == Seperator ) - return path; - else - return path + string( 1, Seperator ); -} - -BYTEARRAY UTIL_EncodeStatString( BYTEARRAY &data ) -{ - unsigned char Mask = 1; - BYTEARRAY Result; - - for( unsigned int i = 0; i < data.size( ); i++ ) - { - if( ( data[i] % 2 ) == 0 ) - Result.push_back( data[i] + 1 ); - else - { - Result.push_back( data[i] ); - Mask |= 1 << ( ( i % 7 ) + 1 ); - } - - if( i % 7 == 6 || i == data.size( ) - 1 ) - { - Result.insert( Result.end( ) - 1 - ( i % 7 ), Mask ); - Mask = 1; - } - } - - return Result; -} - -BYTEARRAY UTIL_DecodeStatString( BYTEARRAY &data ) -{ - unsigned char Mask; - BYTEARRAY Result; - - for( unsigned int i = 0; i < data.size( ); i++ ) - { - if( ( i % 8 ) == 0 ) - Mask = data[i]; - else - { - if( ( Mask & ( 1 << ( i % 8 ) ) ) == 0 ) - Result.push_back( data[i] - 1 ); - else - Result.push_back( data[i] ); - } - } - - return Result; -} - -bool UTIL_IsLanIP( BYTEARRAY ip ) -{ - if( ip.size( ) != 4 ) - return false; - - // thanks to LuCasn for this function - - // 127.0.0.1 - if( ip[0] == 127 && ip[1] == 0 && ip[2] == 0 && ip[3] == 1 ) - return true; - - // 10.x.x.x - if( ip[0] == 10 ) - return true; - - // 172.16.0.0-172.31.255.255 - if( ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31 ) - return true; - - // 192.168.x.x - if( ip[0] == 192 && ip[1] == 168 ) - return true; - - // RFC 3330 and RFC 3927 automatic address range - if( ip[0] == 169 && ip[1] == 254 ) - return true; - - return false; -} - -bool UTIL_IsLocalIP( BYTEARRAY ip, vector &localIPs ) -{ - if( ip.size( ) != 4 ) - return false; - - for( vector :: iterator i = localIPs.begin( ); i != localIPs.end( ); i++ ) - { - if( (*i).size( ) != 4 ) - continue; - - if( ip[0] == (*i)[0] && ip[1] == (*i)[1] && ip[2] == (*i)[2] && ip[3] == (*i)[3] ) - return true; - } - - return false; -} - -void UTIL_Replace( string &Text, string Key, string Value ) -{ - // don't allow any infinite loops - - if( Value.find( Key ) != string :: npos ) - return; - - string :: size_type KeyStart = Text.find( Key ); - - while( KeyStart != string :: npos ) - { - Text.replace( KeyStart, Key.size( ), Value ); - KeyStart = Text.find( Key ); - } -} - -vector UTIL_Tokenize( string s, char delim ) -{ - vector Tokens; - string Token; - - for( string :: iterator i = s.begin( ); i != s.end( ); i++ ) - { - if( *i == delim ) - { - if( Token.empty( ) ) - continue; - - Tokens.push_back( Token ); - Token.clear( ); - } - else - Token += *i; - } - - if( !Token.empty( ) ) - Tokens.push_back( Token ); - - return Tokens; -} - -uint32_t UTIL_Factorial( uint32_t x ) -{ - uint32_t Factorial = 1; - - for( uint32_t i = 2; i <= x; i++ ) - Factorial *= i; - - return Factorial; -} diff --git a/ghost/util.h b/ghost/util.h deleted file mode 100644 index 93c724f..0000000 --- a/ghost/util.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - - Copyright [2008] [Trevor Hogan] - - Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ - -*/ - -#ifndef UTIL_H -#define UTIL_H - -// byte arrays - -BYTEARRAY UTIL_CreateByteArray( unsigned char *a, int size ); -BYTEARRAY UTIL_CreateByteArray( unsigned char c ); -BYTEARRAY UTIL_CreateByteArray( uint16_t i, bool reverse ); -BYTEARRAY UTIL_CreateByteArray( uint32_t i, bool reverse ); -uint16_t UTIL_ByteArrayToUInt16( BYTEARRAY b, bool reverse, unsigned int start = 0 ); -uint32_t UTIL_ByteArrayToUInt32( BYTEARRAY b, bool reverse, unsigned int start = 0 ); -string UTIL_ByteArrayToDecString( BYTEARRAY b ); -string UTIL_ByteArrayToHexString( BYTEARRAY b ); -void UTIL_AppendByteArray( BYTEARRAY &b, BYTEARRAY append ); -void UTIL_AppendByteArrayFast( BYTEARRAY &b, BYTEARRAY &append ); -void UTIL_AppendByteArray( BYTEARRAY &b, unsigned char *a, int size ); -void UTIL_AppendByteArray( BYTEARRAY &b, string append, bool terminator = true ); -void UTIL_AppendByteArrayFast( BYTEARRAY &b, string &append, bool terminator = true ); -void UTIL_AppendByteArray( BYTEARRAY &b, uint16_t i, bool reverse ); -void UTIL_AppendByteArray( BYTEARRAY &b, uint32_t i, bool reverse ); -BYTEARRAY UTIL_ExtractCString( BYTEARRAY &b, unsigned int start ); -unsigned char UTIL_ExtractHex( BYTEARRAY &b, unsigned int start, bool reverse ); -BYTEARRAY UTIL_ExtractNumbers( string s, unsigned int count ); -BYTEARRAY UTIL_ExtractHexNumbers( string s ); - -// conversions - -string UTIL_ToString( unsigned long i ); -string UTIL_ToString( unsigned short i ); -string UTIL_ToString( unsigned int i ); -string UTIL_ToString( long i ); -string UTIL_ToString( short i ); -string UTIL_ToString( int i ); -string UTIL_ToString( float f, int digits ); -string UTIL_ToString( double d, int digits ); -string UTIL_ToHexString( uint32_t i ); -uint16_t UTIL_ToUInt16( string &s ); -uint32_t UTIL_ToUInt32( string &s ); -int16_t UTIL_ToInt16( string &s ); -int32_t UTIL_ToInt32( string &s ); -double UTIL_ToDouble( string &s ); -string UTIL_MSToString( uint32_t ms ); - -// files - -bool UTIL_FileExists( string file ); -string UTIL_FileRead( string file, uint32_t start, uint32_t length ); -string UTIL_FileRead( string file ); -bool UTIL_FileWrite( string file, unsigned char *data, uint32_t length ); -string UTIL_FileSafeName( string fileName ); -string UTIL_AddPathSeperator( string path ); - -// stat strings - -BYTEARRAY UTIL_EncodeStatString( BYTEARRAY &data ); -BYTEARRAY UTIL_DecodeStatString( BYTEARRAY &data ); - -// other - -bool UTIL_IsLanIP( BYTEARRAY ip ); -bool UTIL_IsLocalIP( BYTEARRAY ip, vector &localIPs ); -void UTIL_Replace( string &Text, string Key, string Value ); -vector UTIL_Tokenize( string s, char delim ); - -// math - -uint32_t UTIL_Factorial( uint32_t x ); - -#define nCr(n, r) (UTIL_Factorial(n) / UTIL_Factorial((n)-(r)) / UTIL_Factorial(r)) -#define nPr(n, r) (UTIL_Factorial(n) / UTIL_Factorial((n)-(r))) - -#endif diff --git a/bncsutil/src/bncsutil/gmp.h b/include/gmp.h similarity index 80% rename from bncsutil/src/bncsutil/gmp.h rename to include/gmp.h index 0a8c32c..28a9f2e 100644 --- a/bncsutil/src/bncsutil/gmp.h +++ b/include/gmp.h @@ -1,2189 +1,2108 @@ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- - -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007 Free Software Foundation, Inc. - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP 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 the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -#ifndef __GMP_H__ - -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#endif - - -#if ! defined (__GMP_WITHIN_CONFIGURE) -# if defined( _MSC_VER ) -# if defined( _WIN64 ) -# define __GMP_BITS_PER_MP_LIMB 64 -# define BITS_PER_MP_LIMB 64 -# define GMP_LIMB_BITS 64 -# define SIZEOF_MP_LIMB_T 8 -# define _LONG_LONG_LIMB 1 -# elif defined( _WIN32 ) -# define __GMP_BITS_PER_MP_LIMB 32 -# define BITS_PER_MP_LIMB 32 -# define GMP_LIMB_BITS 32 -# define SIZEOF_MP_LIMB_T 4 -# ifdef _LONG_LONG_LIMB -# undef _LONG_LONG_LIMB -# endif -# else -# error This is the wrong version of gmp.h -# endif -# endif -# define GMP_NAIL_BITS 0 -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) - - -/* The following (everything under ifndef __GNU_MP__) must be identical in - gmp.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 - -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t - - - -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ - -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif - - -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif - - -/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in - all other circumstances. - - When compiling objects for libgmp, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - - __GMP_DECLSPEC_XX is similarly used for libgmpxx. __GMP_WITHIN_GMPXX - indicates when building libgmpxx, and in that case libgmpxx functions are - exports, but libgmp functions which might get called are imports. - - libmp.la uses __GMP_DECLSPEC, just as if it were libgmp.la. libgmp and - libmp don't call each other, so there's no conflict or confusion. - - Libtool DLL_EXPORT define is not used. - - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - - In gcc __declspec can go at either the start or end of a prototype. - - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ - -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libgmp */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libgmp */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif - - -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif - -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; - -#endif /* __GNU_MP__ */ - - -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpz_struct mpz_t[1]; - -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined (_CRAY) && ! defined (_CRAYMPP) -/* plain `int' is much faster (48 bits) */ -#define __GMP_MP_SIZE_T_INT 1 -typedef int mp_size_t; -typedef int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif - -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; - -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ -typedef __mpq_struct mpq_t[1]; - -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; - -/* typedef __mpf_struct MP_FLOAT; */ -typedef __mpf_struct mpf_t[1]; - -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; - -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; - -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; - - -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libgmpxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libgmpxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif - - -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif - -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif - -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (__dj_include_stdio_h_) /* DJGPP */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif - -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif - -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ - -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif - -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif - -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif - - -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ - -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif - - -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ - -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif - - -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ - - /* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. - GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 - inline semantics, unless -fgnu89-inline is used. */ -#ifdef __GNUC__ -#ifdef __GNUC_STDC_INLINE__ -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 -#endif - -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libgmp. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif - -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif - -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif - - -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) - -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) - - -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif - -#ifdef _CRAY -#define __GMP_CRAY_Pragma(str) _Pragma (str) -#else -#define __GMP_CRAY_Pragma(str) -#endif - - -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) - - -#if defined (__cplusplus) -extern "C" { -#ifdef _GMP_H_HAVE_FILE -using std::FILE; -#endif -#endif - -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; - -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; - -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; - -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; - -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; - - -/**************** Random number routines. ****************/ - -/* obsolete */ -#define gmp_randinit __gmp_randinit -__GMP_DECLSPEC void gmp_randinit __GMP_PROTO ((gmp_randstate_t, gmp_randalg_t, ...)); - -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - unsigned long int)); - -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_set __gmp_randinit_set -void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); - -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); - -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); - -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_urandomb_ui __gmp_urandomb_ui -unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_urandomm_ui __gmp_urandomm_ui -unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - - -/**************** Formatted output routines. ****************/ - -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); - -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif - -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); - -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); - -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif - -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif - -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif - - -/**************** Formatted input routines. ****************/ - -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); - -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif - - -/**************** Integer (i.e. Z) routines. ****************/ - -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_abs __gmpz_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); - -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); - -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, unsigned long)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); - -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); - -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); - -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); - -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC unsigned long int mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); - -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); - -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, unsigned long)); - -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif - -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif - -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker mpz_jacobi /* alias */ - -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_legendre mpz_jacobi /* alias */ - -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ - -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); - -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_neg __gmpz_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif - -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif - -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC unsigned long int mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); - -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_random __gmpz_random -__GMP_DECLSPEC void mpz_random __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_random2 __gmpz_random2 -__GMP_DECLSPEC void mpz_random2 __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, unsigned long)); - -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, unsigned long int)); - -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC unsigned long int mpz_scan0 __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC unsigned long int mpz_scan1 __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); - -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif - -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); - -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); - -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; - -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, unsigned long int)); - -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); - -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - - -/**************** Rational (i.e. Q) routines. ****************/ - -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); - -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); - -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, unsigned long)); - -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); - -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); - -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif - -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, unsigned long)); - -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif - -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); - -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); - -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); - -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); - -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); - -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; - - -/**************** Float (i.e. F) routines. ****************/ - -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); - -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); - -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); - -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC unsigned long int mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC unsigned long int mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); - -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); - -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif - -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif - -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); - -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((unsigned long int)) __GMP_NOTHROW; - -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, unsigned long int)) __GMP_NOTHROW; - -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); - -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); - -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; - -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, unsigned long int)); - - -/************ Low level positive-integer (i.e. N) routines. ************/ - -/* This is ugly, but we need to make user calls reach the prefixed function. */ - -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); - -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) - -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) - -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); - -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); - -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC unsigned long int mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC unsigned long int mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); - -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC unsigned long int mpn_scan0 __GMP_PROTO ((mp_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC unsigned long int mpn_scan1 __GMP_PROTO ((mp_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); - -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - - -/**************** mpz inlines ****************/ - -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif - -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - unsigned long __gmp_result; - - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif - - -/**************** mpq inlines ****************/ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif - - -/**************** mpn inlines ****************/ - -/* The comments with __GMPN_ADD_1 below apply here too. - - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - - ysize==0 isn't a documented feature, but is used internally in a few - places. - - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ - -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) - -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) - - -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - - Alternatives: - - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ - -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) - -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) - - -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) - - -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif - -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - __GMP_CRAY_Pragma ("_CRI ivdep"); \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif - -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ - -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif - - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__cplusplus) -} -#endif - - -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) - -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif - - -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) - - -/**************** C++ routines ****************/ - -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif - - -/* Source-level compatibility with GMP 2 and earlier. */ -#define mpn_divmod(qp,np,nsize,dp,dsize) \ - mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize) - -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) - -/* Useful synonyms, but not quite compatible with GMP 1. */ -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp - -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; - -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 4 -#define __GNU_MP_VERSION_MINOR 2 -#define __GNU_MP_VERSION_PATCHLEVEL 2 - -#define __GMP_H__ -#endif /* __GMP_H__ */ +/* Definitions for GNU multiple precision functions. -*- mode: c -*- + +Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002 +Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The GNU MP 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 the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#ifndef __GMP_H__ + +#if defined (__cplusplus) +#include /* for istream, ostream */ +#endif + + +/* Instantiated by configure. */ +#if ! __GMP_WITHIN_CONFIGURE +#define __GMP_BITS_PER_MP_LIMB 32 +#define __GMP_HAVE_HOST_CPU_FAMILY_power 0 +#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0 +#define GMP_LIMB_BITS 32 +#define GMP_NAIL_BITS 0 +#endif +#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) +#define GMP_NUMB_MASK ((~(mp_limb_t) 0) >> GMP_NAIL_BITS) +#define GMP_NUMB_MAX GMP_NUMB_MASK +#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) + + +/* The following (everything under ifndef __GNU_MP__) must be identical in + gmp.h and mp.h to allow both to be included in an application or during + the library build. */ +#ifndef __GNU_MP__ +#define __GNU_MP__ 4 + +#define __need_size_t /* tell gcc stddef.h we only want size_t */ +#if defined (__cplusplus) +#include /* for size_t */ +#else +#include /* for size_t */ +#endif +#undef __need_size_t + +/* Instantiated by configure. */ +#if ! __GMP_WITHIN_CONFIGURE +/* #undef _LONG_LONG_LIMB */ +#define __GMP_LIBGMP_DLL 1 +#endif + + +/* __STDC__ - some ANSI compilers define this only to 0, hence the use of + "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 + sets __STDC__ to 0, but requires "##" for token pasting. + + _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but + don't always define __STDC__. + + _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 + mode, but doesn't define __STDC__. + + _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za + option is given (in which case it's 1). + + _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that + all w32 compilers are ansi. */ + +#if defined (__STDC__) \ + || defined (__cplusplus) \ + || defined (_AIX) \ + || defined (__DECC) \ + || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ + || defined (_MSC_VER) \ + || defined (_WIN32) +#define __GMP_HAVE_CONST 1 +#define __GMP_HAVE_PROTOTYPES 1 +#define __GMP_HAVE_TOKEN_PASTE 1 +#else +#define __GMP_HAVE_CONST 0 +#define __GMP_HAVE_PROTOTYPES 0 +#define __GMP_HAVE_TOKEN_PASTE 0 +#endif + + +#if __GMP_HAVE_CONST +#define __gmp_const const +#define __gmp_signed signed +#else +#define __gmp_const +#define __gmp_signed +#endif + + +/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in + all other circumstances. + + When compiling objects for libgmp, __GMP_DECLSPEC is an export directive, + or when compiling for an application it's an import directive. The two + cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles + (and not defined from an application). + + __GMP_DECLSPEC_XX is similarly used for libgmpxx. __GMP_WITHIN_GMPXX + indicates when building libgmpxx, and in that case libgmpxx functions are + exports, but libgmp functions which might get called are imports. + + libmp.la uses __GMP_DECLSPEC, just as if it were libgmp.la. libgmp and + libmp don't call each other, so there's no conflict or confusion. + + Libtool DLL_EXPORT define is not used. + + There's no attempt to support GMP built both static and DLL. Doing so + would mean applications would have to tell us which of the two is going + to be used when linking, and that seems very tedious and error prone if + using GMP by hand, and equally tedious from a package since autoconf and + automake don't give much help. + + __GMP_DECLSPEC is required on all documented global functions and + variables, the various internals in gmp-impl.h etc can be left unadorned. + But internals used by the test programs or speed measuring programs + should have __GMP_DECLSPEC, and certainly constants or variables must + have it or the wrong address will be resolved. */ + +#if defined (__GNUC__) || defined (_MSC_VER) || defined (__BORLANDC__) +#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) +#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) +#endif +#ifdef __WATCOMC__ +#define __GMP_DECLSPEC_EXPORT __export +#define __GMP_DECLSPEC_IMPORT __import +#endif +#ifdef __IBMC__ +#define __GMP_DECLSPEC_EXPORT _Export +#define __GMP_DECLSPEC_IMPORT _Import +#endif + +#if __GMP_LIBGMP_DLL +#if __GMP_WITHIN_GMP +/* compiling to go into a DLL libgmp */ +#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT +#else +/* compiling to go into an application which will link to a DLL libgmp */ +#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT +#endif +#else +/* all other cases */ +#define __GMP_DECLSPEC +#endif + + +#ifdef _SHORT_LIMB +typedef unsigned int mp_limb_t; +typedef int mp_limb_signed_t; +#else +#ifdef _LONG_LONG_LIMB +typedef unsigned long long int mp_limb_t; +typedef long long int mp_limb_signed_t; +#else +typedef unsigned long int mp_limb_t; +typedef long int mp_limb_signed_t; +#endif +#endif + +typedef mp_limb_t * mp_ptr; +typedef __gmp_const mp_limb_t * mp_srcptr; +#if defined (_CRAY) && ! defined (_CRAYMPP) +/* plain `int' is much faster (48 bits) */ +#define __GMP_MP_SIZE_T_INT 1 +typedef int mp_size_t; +typedef int mp_exp_t; +#else +#define __GMP_MP_SIZE_T_INT 0 +typedef long int mp_size_t; +typedef long int mp_exp_t; +#endif + +typedef struct +{ + int _mp_alloc; /* Number of *limbs* allocated and pointed + to by the _mp_d field. */ + int _mp_size; /* abs(_mp_size) is the number of limbs the + last field points to. If _mp_size is + negative this is a negative number. */ + mp_limb_t *_mp_d; /* Pointer to the limbs. */ +} __mpz_struct; +#endif /* __GNU_MP__ */ + +typedef __mpz_struct MP_INT; +typedef __mpz_struct mpz_t[1]; + +typedef struct +{ + __mpz_struct _mp_num; + __mpz_struct _mp_den; +} __mpq_struct; + +typedef __mpq_struct MP_RAT; +typedef __mpq_struct mpq_t[1]; + +typedef struct +{ + int _mp_prec; /* Max precision, in number of `mp_limb_t's. + Set by mpf_init and modified by + mpf_set_prec. The area pointed to by the + _mp_d field contains `prec' + 1 limbs. */ + int _mp_size; /* abs(_mp_size) is the number of limbs the + last field points to. If _mp_size is + negative this is a negative number. */ + mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ + mp_limb_t *_mp_d; /* Pointer to the limbs. */ +} __mpf_struct; + +/* typedef __mpf_struct MP_FLOAT; */ +typedef __mpf_struct mpf_t[1]; + +/* Available random number generation algorithms. */ +typedef enum +{ + GMP_RAND_ALG_DEFAULT = 0, + GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ +} gmp_randalg_t; + +/* Linear congruential data struct. */ +typedef struct { + mpz_t _mp_a; /* Multiplier. */ + unsigned long int _mp_c; /* Adder. */ + mpz_t _mp_m; /* Modulus (valid only if m2exp == 0). */ + unsigned long int _mp_m2exp; /* If != 0, modulus is 2 ^ m2exp. */ +} __gmp_randata_lc; + +/* Random state struct. */ +typedef struct +{ + mpz_t _mp_seed; /* Current seed. */ + gmp_randalg_t _mp_alg; /* Algorithm used. */ + union { /* Algorithm specific data. */ + __gmp_randata_lc *_mp_lc; /* Linear congruential. */ + } _mp_algdata; +} __gmp_randstate_struct; +typedef __gmp_randstate_struct gmp_randstate_t[1]; + +/* Types for function declarations in gmp files. */ +/* ??? Should not pollute user name space with these ??? */ +typedef __gmp_const __mpz_struct *mpz_srcptr; +typedef __mpz_struct *mpz_ptr; +typedef __gmp_const __mpf_struct *mpf_srcptr; +typedef __mpf_struct *mpf_ptr; +typedef __gmp_const __mpq_struct *mpq_srcptr; +typedef __mpq_struct *mpq_ptr; + + +/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common + section. */ +#if __GMP_LIBGMP_DLL +#if __GMP_WITHIN_GMPXX +/* compiling to go into a DLL libgmpxx */ +#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT +#else +/* compiling to go into a application which will link to a DLL libgmpxx */ +#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT +#endif +#else +/* all other cases */ +#define __GMP_DECLSPEC_XX +#endif + + +#if __GMP_HAVE_PROTOTYPES +#define __GMP_PROTO(x) x +#else +#define __GMP_PROTO(x) () +#endif + +#ifndef __MPN +#if __GMP_HAVE_TOKEN_PASTE +#define __MPN(x) __gmpn_##x +#else +#define __MPN(x) __gmpn_/**/x +#endif +#endif + +#if defined (FILE) \ + || defined (H_STDIO) \ + || defined (_H_STDIO) /* AIX */ \ + || defined (_STDIO_H) /* glibc, Sun, SCO */ \ + || defined (_STDIO_H_) /* BSD, OSF */ \ + || defined (__STDIO_H) /* Borland */ \ + || defined (__STDIO_H__) /* IRIX */ \ + || defined (_STDIO_INCLUDED) /* HPUX */ \ + || defined (__dj_include_stdio_h_) /* DJGPP */ \ + || defined (_FILE_DEFINED) /* Microsoft */ \ + || defined (__STDIO__) /* Apple MPW MrC */ +#define _GMP_H_HAVE_FILE 1 +#endif + +/* In ISO C, if a prototype involving "struct obstack *" is given without + that structure defined, then the struct is scoped down to just the + prototype, causing a conflict if it's subsequently defined for real. So + only give prototypes if we've got obstack.h. */ +#if defined (_OBSTACK_H) /* glibc */ +#define _GMP_H_HAVE_OBSTACK 1 +#endif + +/* The prototypes for gmp_vprintf etc are provided only if va_list is + available, via an application having included or . + Usually va_list is a typedef so can't be tested directly, but va_start is + almost certainly a macro, so look for that. + + will define some sort of va_list for vprintf and vfprintf, but + let's not bother trying to use that since it's not standard and since + application uses for gmp_vprintf etc will almost certainly require the + whole or anyway. */ + +#ifdef va_start +#define _GMP_H_HAVE_VA_LIST 1 +#endif + +/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ +#if defined (__GNUC__) && defined (__GNUC_MINOR__) +#define __GMP_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GMP_GNUC_PREREQ(maj, min) 0 +#endif + +/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically + it means a function does nothing but examine its arguments and memory + (global or via arguments) to generate a return value, but changes nothing + and has no side-effects. */ +#if __GMP_GNUC_PREREQ (2,96) +#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +#define __GMP_ATTRIBUTE_PURE +#endif + + +/* An empty "throw ()" means the function doesn't throw any C++ exceptions, + this can save some stack frame info in applications. + + Currently it's given only on functions which never divide-by-zero etc, + don't allocate memory, and are expected to never need to allocate memory. + This leaves open the possibility of a C++ throw from a future GMP + exceptions scheme. + + mpz_set_ui etc are omitted to leave open the lazy allocation scheme + described in doc/tasks.html. mpz_get_d etc are omitted to leave open + exceptions for float overflows. + + Note that __GMP_NOTHROW must be given on any inlines the same as on their + prototypes (for g++ at least, where they're used together). Note also + that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like + __GMP_ATTRIBUTE_PURE. */ + +#if defined (__cplusplus) +#define __GMP_NOTHROW throw () +#else +#define __GMP_NOTHROW +#endif + + +/* PORTME: What other compilers have a useful "extern inline"? "static + inline" would be an acceptable substitute if the compiler (or linker) + discards unused statics. */ + +/* gcc has __inline__ in all modes, including strict ansi. Give a prototype + for an inline too, so as to correctly specify "dllimport" on windows, in + case the function is called rather than inlined. */ +#ifdef __GNUC__ +#define __GMP_EXTERN_INLINE extern __inline__ +#define __GMP_INLINE_PROTOTYPES 1 +#endif + +/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict + ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes + place under -O. Without -O "foo" seems to be emitted whether it's used + or not, which is wasteful. "extern inline foo()" isn't useful, the + "extern" is apparently ignored, so foo is inlined if possible but also + emitted as a global, which causes multiple definition errors when + building a shared libgmp. */ +#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ + && ! defined (__GMP_EXTERN_INLINE) +#define __GMP_EXTERN_INLINE static inline +#endif + +/* C++ always has "inline" and since it's a normal feature the linker should + discard duplicate non-inlined copies, or if it doesn't then that's a + problem for everyone, not just GMP. */ +#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) +#define __GMP_EXTERN_INLINE inline +#endif + +/* By default, don't give a prototype when there's going to be an inline + version. Note in particular that Cray C++ objects to the combination of + prototype and inline. */ +#ifdef __GMP_EXTERN_INLINE +#ifndef __GMP_INLINE_PROTOTYPES +#define __GMP_INLINE_PROTOTYPES 0 +#endif +#else +#define __GMP_INLINE_PROTOTYPES 1 +#endif + + +#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) +#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) + +#define __GMP_UINT_MAX (~ (unsigned) 0) +#define __GMP_ULONG_MAX (~ (unsigned long) 0) +#define __GMP_USHRT_MAX ((unsigned short) ~0) + + +/* Allow direct user access to numerator and denominator of a mpq_t object. */ +#define mpq_numref(Q) (&((Q)->_mp_num)) +#define mpq_denref(Q) (&((Q)->_mp_den)) + + +#if defined (__cplusplus) +extern "C" { +#endif + +#define mp_set_memory_functions __gmp_set_memory_functions +__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), + void *(*) (void *, size_t, size_t), + void (*) (void *, size_t))) __GMP_NOTHROW; + +#define mp_bits_per_limb __gmp_bits_per_limb +__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; + +#define gmp_errno __gmp_errno +__GMP_DECLSPEC extern int gmp_errno; + +#define gmp_version __gmp_version +__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; + +/* The following for internal use only. + Enhancement: __gmp_allocate_func could have "__attribute__ ((malloc))", + but current gcc (3.0) doesn't seem to support that. */ +__GMP_DECLSPEC extern void * (*__gmp_allocate_func) __GMP_PROTO ((size_t)); +__GMP_DECLSPEC extern void * (*__gmp_reallocate_func) __GMP_PROTO ((void *, size_t, size_t)); +__GMP_DECLSPEC extern void (*__gmp_free_func) __GMP_PROTO ((void *, size_t)); + + +/**************** Random number routines. ****************/ + +/* obsolete */ +#define gmp_randinit __gmp_randinit +__GMP_DECLSPEC void gmp_randinit __GMP_PROTO ((gmp_randstate_t, gmp_randalg_t, ...)); + +#define gmp_randinit_default __gmp_randinit_default +__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); + +#define gmp_randinit_lc __gmp_randinit_lc +__GMP_DECLSPEC void gmp_randinit_lc __GMP_PROTO ((gmp_randstate_t, + mpz_srcptr, unsigned long int, mpz_srcptr)); + +#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp +__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, + mpz_srcptr, unsigned long int, + unsigned long int)); + +#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size +__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, unsigned long)); + +#define gmp_randseed __gmp_randseed +__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); + +#define gmp_randseed_ui __gmp_randseed_ui +__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); + +#define gmp_randclear __gmp_randclear +__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); + + +/**************** Formatted output routines. ****************/ + +#define gmp_asprintf __gmp_asprintf +__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, const char *, ...)); + +#define gmp_fprintf __gmp_fprintf +#if _GMP_H_HAVE_FILE +__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, const char *, ...)); +#endif + +#define gmp_obstack_printf __gmp_obstack_printf +#if _GMP_H_HAVE_OBSTACK +__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, const char *, ...)); +#endif + +#define gmp_obstack_vprintf __gmp_obstack_vprintf +#if _GMP_H_HAVE_OBSTACK && _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, const char *, va_list)); +#endif + +#define gmp_printf __gmp_printf +__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((const char *, ...)); + +#define gmp_snprintf __gmp_snprintf +__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, const char *, ...)); + +#define gmp_sprintf __gmp_sprintf +__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, const char *, ...)); + +#define gmp_vasprintf __gmp_vasprintf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, const char *, va_list)); +#endif + +#define gmp_vfprintf __gmp_vfprintf +#if _GMP_H_HAVE_FILE && _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, const char *, va_list)); +#endif + +#define gmp_vprintf __gmp_vprintf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((const char *, va_list)); +#endif + +#define gmp_vsnprintf __gmp_vsnprintf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, const char *, va_list)); +#endif + +#define gmp_vsprintf __gmp_vsprintf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, const char *, va_list)); +#endif + + +/**************** Formatted input routines. ****************/ + +#define gmp_fscanf __gmp_fscanf +#if _GMP_H_HAVE_FILE +__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, const char *, ...)); +#endif + +#define gmp_scanf __gmp_scanf +__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((const char *, ...)); + +#define gmp_sscanf __gmp_sscanf +__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((const char *, const char *, ...)); + +#define gmp_vfscanf __gmp_vfscanf +#if _GMP_H_HAVE_FILE && _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, const char *, va_list)); +#endif + +#define gmp_vscanf __gmp_vscanf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((const char *, va_list)); +#endif + +#define gmp_vsscanf __gmp_vsscanf +#if _GMP_H_HAVE_VA_LIST +__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((const char *, const char *, va_list)); +#endif + + +/**************** Integer (i.e. Z) routines. ****************/ + +#define _mpz_realloc __gmpz_realloc +#define mpz_realloc __gmpz_realloc +__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); + +#define mpz_abs __gmpz_abs +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_abs +__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); +#endif + +#define mpz_add __gmpz_add +__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_add_ui __gmpz_add_ui +__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_addmul __gmpz_addmul +__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_addmul_ui __gmpz_addmul_ui +__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_and __gmpz_and +__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_array_init __gmpz_array_init +__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); + +#define mpz_bin_ui __gmpz_bin_ui +__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_bin_uiui __gmpz_bin_uiui +__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); + +#define mpz_cdiv_q __gmpz_cdiv_q +__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp +__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); + +#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui +__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_cdiv_qr __gmpz_cdiv_qr +__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui +__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_cdiv_r __gmpz_cdiv_r +__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp +__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); + +#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui +__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_cdiv_ui __gmpz_cdiv_ui +__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpz_clear __gmpz_clear +__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); + +#define mpz_clrbit __gmpz_clrbit +__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_cmp __gmpz_cmp +__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_cmp_d __gmpz_cmp_d +__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; + +#define _mpz_cmp_si __gmpz_cmp_si +__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define _mpz_cmp_ui __gmpz_cmp_ui +__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_cmpabs __gmpz_cmpabs +__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_cmpabs_d __gmpz_cmpabs_d +__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; + +#define mpz_cmpabs_ui __gmpz_cmpabs_ui +__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_com __gmpz_com +__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); + +#define mpz_congruent_p __gmpz_congruent_p +__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p +__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, unsigned long)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_congruent_ui_p __gmpz_congruent_ui_p +__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; + +#define mpz_divexact __gmpz_divexact +__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_divexact_ui __gmpz_divexact_ui +__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); + +#define mpz_divisible_p __gmpz_divisible_p +__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_divisible_ui_p __gmpz_divisible_ui_p +__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; + +#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p +__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_dump __gmpz_dump +__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); + +#define mpz_export __gmpz_export +__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr z)); + +#define mpz_fac_ui __gmpz_fac_ui +__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_fdiv_q __gmpz_fdiv_q +__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp +__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui +__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_fdiv_qr __gmpz_fdiv_qr +__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui +__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_fdiv_r __gmpz_fdiv_r +__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp +__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui +__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_fdiv_ui __gmpz_fdiv_ui +__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpz_fib_ui __gmpz_fib_ui +__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_fib2_ui __gmpz_fib2_ui +__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); + +#define mpz_fits_sint_p __gmpz_fits_sint_p +__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_fits_slong_p __gmpz_fits_slong_p +__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_fits_sshort_p __gmpz_fits_sshort_p +__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_fits_uint_p __gmpz_fits_uint_p +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_fits_uint_p +__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_fits_ulong_p __gmpz_fits_ulong_p +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_fits_ulong_p +__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_fits_ushort_p __gmpz_fits_ushort_p +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_fits_ushort_p +__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_gcd __gmpz_gcd +__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_gcd_ui __gmpz_gcd_ui +__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_gcdext __gmpz_gcdext +__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_get_d __gmpz_get_d +__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_get_d_2exp __gmpz_get_d_2exp +__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); + +#define mpz_get_si __gmpz_get_si +__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_get_str __gmpz_get_str +__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); + +#define mpz_get_ui __gmpz_get_ui +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_get_ui +__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_getlimbn __gmpz_getlimbn +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_getlimbn +__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_hamdist __gmpz_hamdist +__GMP_DECLSPEC unsigned long int mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_import __gmpz_import +__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, const void *)); + +#define mpz_init __gmpz_init +__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); + +#define mpz_init2 __gmpz_init2 +__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, unsigned long)); + +#define mpz_init_set __gmpz_init_set +__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); + +#define mpz_init_set_d __gmpz_init_set_d +__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); + +#define mpz_init_set_si __gmpz_init_set_si +__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); + +#define mpz_init_set_str __gmpz_init_set_str +__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); + +#define mpz_init_set_ui __gmpz_init_set_ui +__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_inp_raw __gmpz_inp_raw +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); +#endif + +#define mpz_inp_str __gmpz_inp_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); +#endif + +#define mpz_invert __gmpz_invert +__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_ior __gmpz_ior +__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_jacobi __gmpz_jacobi +__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_kronecker mpz_jacobi /* alias */ + +#define mpz_kronecker_si __gmpz_kronecker_si +__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; + +#define mpz_kronecker_ui __gmpz_kronecker_ui +__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; + +#define mpz_si_kronecker __gmpz_si_kronecker +__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_ui_kronecker __gmpz_ui_kronecker +__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_lcm __gmpz_lcm +__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_lcm_ui __gmpz_lcm_ui +__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); + +#define mpz_legendre mpz_jacobi /* alias */ + +#define mpz_lucnum_ui __gmpz_lucnum_ui +__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_lucnum2_ui __gmpz_lucnum2_ui +__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); + +#define mpz_millerrabin __gmpz_millerrabin +__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; + +#define mpz_mod __gmpz_mod +__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_mul __gmpz_mul +__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_mul_2exp __gmpz_mul_2exp +__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_mul_si __gmpz_mul_si +__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); + +#define mpz_mul_ui __gmpz_mul_ui +__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_neg __gmpz_neg +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_neg +__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); +#endif + +#define mpz_nextprime __gmpz_nextprime +__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); + +#define mpz_out_raw __gmpz_out_raw +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); +#endif + +#define mpz_out_str __gmpz_out_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); +#endif + +#define mpz_perfect_power_p __gmpz_perfect_power_p +__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpz_perfect_square_p __gmpz_perfect_square_p +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_perfect_square_p +__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_popcount __gmpz_popcount +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_popcount +__GMP_DECLSPEC unsigned long int mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_pow_ui __gmpz_pow_ui +__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_powm __gmpz_powm +__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_powm_ui __gmpz_powm_ui +__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); + +#define mpz_probab_prime_p __gmpz_probab_prime_p +__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; + +#define mpz_random __gmpz_random +__GMP_DECLSPEC void mpz_random __GMP_PROTO ((mpz_ptr, mp_size_t)); + +#define mpz_random2 __gmpz_random2 +__GMP_DECLSPEC void mpz_random2 __GMP_PROTO ((mpz_ptr, mp_size_t)); + +#define mpz_realloc2 __gmpz_realloc2 +__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, unsigned long)); + +#define mpz_remove __gmpz_remove +__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_root __gmpz_root +__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_rrandomb __gmpz_rrandomb +__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, unsigned long int)); + +#define mpz_scan0 __gmpz_scan0 +__GMP_DECLSPEC unsigned long int mpz_scan0 __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_scan1 __gmpz_scan1 +__GMP_DECLSPEC unsigned long int mpz_scan1 __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_set __gmpz_set +__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); + +#define mpz_set_d __gmpz_set_d +__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); + +#define mpz_set_f __gmpz_set_f +__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); + +#define mpz_set_q __gmpz_set_q +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_set_q +__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); +#endif + +#define mpz_set_si __gmpz_set_si +__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); + +#define mpz_set_str __gmpz_set_str +__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); + +#define mpz_set_ui __gmpz_set_ui +__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_setbit __gmpz_setbit +__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, unsigned long int)); + +#define mpz_size __gmpz_size +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpz_size +__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpz_sizeinbase __gmpz_sizeinbase +__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_sqrt __gmpz_sqrt +__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); + +#define mpz_sqrtrem __gmpz_sqrtrem +__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); + +#define mpz_sub __gmpz_sub +__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_sub_ui __gmpz_sub_ui +__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_ui_sub __gmpz_ui_sub +__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); + +#define mpz_submul __gmpz_submul +__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_submul_ui __gmpz_submul_ui +__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_swap __gmpz_swap +__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; + +#define mpz_tdiv_ui __gmpz_tdiv_ui +__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpz_tdiv_q __gmpz_tdiv_q +__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp +__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui +__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_tdiv_qr __gmpz_tdiv_qr +__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui +__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_tdiv_r __gmpz_tdiv_r +__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + +#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp +__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui +__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); + +#define mpz_tstbit __gmpz_tstbit +__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpz_ui_pow_ui __gmpz_ui_pow_ui +__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); + +#define mpz_urandomb __gmpz_urandomb +__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, unsigned long int)); + +#define mpz_urandomm __gmpz_urandomm +__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); + +#define mpz_xor __gmpz_xor +#define mpz_eor __gmpz_xor +__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); + + +/**************** Rational (i.e. Q) routines. ****************/ + +#define mpq_abs __gmpq_abs +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpq_abs +__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); +#endif + +#define mpq_add __gmpq_add +__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); + +#define mpq_canonicalize __gmpq_canonicalize +__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); + +#define mpq_clear __gmpq_clear +__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); + +#define mpq_cmp __gmpq_cmp +__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define _mpq_cmp_si __gmpq_cmp_si +__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; + +#define _mpq_cmp_ui __gmpq_cmp_ui +__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpq_div __gmpq_div +__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); + +#define mpq_div_2exp __gmpq_div_2exp +__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, unsigned long)); + +#define mpq_equal __gmpq_equal +__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpq_get_num __gmpq_get_num +__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); + +#define mpq_get_den __gmpq_get_den +__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); + +#define mpq_get_d __gmpq_get_d +__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpq_get_str __gmpq_get_str +__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); + +#define mpq_init __gmpq_init +__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); + +#define mpq_inp_str __gmpq_inp_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); +#endif + +#define mpq_inv __gmpq_inv +__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); + +#define mpq_mul __gmpq_mul +__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); + +#define mpq_mul_2exp __gmpq_mul_2exp +__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, unsigned long)); + +#define mpq_neg __gmpq_neg +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpq_neg +__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); +#endif + +#define mpq_out_str __gmpq_out_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); +#endif + +#define mpq_set __gmpq_set +__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); + +#define mpq_set_d __gmpq_set_d +__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); + +#define mpq_set_den __gmpq_set_den +__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); + +#define mpq_set_f __gmpq_set_f +__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); + +#define mpq_set_num __gmpq_set_num +__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); + +#define mpq_set_si __gmpq_set_si +__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); + +#define mpq_set_str __gmpq_set_str +__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, const char *, int)); + +#define mpq_set_ui __gmpq_set_ui +__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); + +#define mpq_set_z __gmpq_set_z +__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); + +#define mpq_sub __gmpq_sub +__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); + +#define mpq_swap __gmpq_swap +__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; + + +/**************** Float (i.e. F) routines. ****************/ + +#define mpf_abs __gmpf_abs +__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_add __gmpf_add +__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); + +#define mpf_add_ui __gmpf_add_ui +__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +#define mpf_ceil __gmpf_ceil +__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_clear __gmpf_clear +__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); + +#define mpf_cmp __gmpf_cmp +__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_cmp_d __gmpf_cmp_d +__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; + +#define mpf_cmp_si __gmpf_cmp_si +__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_cmp_ui __gmpf_cmp_ui +__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_div __gmpf_div +__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); + +#define mpf_div_2exp __gmpf_div_2exp +__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_div_ui __gmpf_div_ui +__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_dump __gmpf_dump +__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); + +#define mpf_eq __gmpf_eq +__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_sint_p __gmpf_fits_sint_p +__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_slong_p __gmpf_fits_slong_p +__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_sshort_p __gmpf_fits_sshort_p +__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_uint_p __gmpf_fits_uint_p +__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_ulong_p __gmpf_fits_ulong_p +__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_fits_ushort_p __gmpf_fits_ushort_p +__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_floor __gmpf_floor +__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_get_d __gmpf_get_d +__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; + +#define mpf_get_d_2exp __gmpf_get_d_2exp +__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); + +#define mpf_get_default_prec __gmpf_get_default_prec +__GMP_DECLSPEC unsigned long int mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_get_prec __gmpf_get_prec +__GMP_DECLSPEC unsigned long int mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_get_si __gmpf_get_si +__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_get_str __gmpf_get_str +__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); + +#define mpf_get_ui __gmpf_get_ui +__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_init __gmpf_init +__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); + +#define mpf_init2 __gmpf_init2 +__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, unsigned long int)); + +#define mpf_init_set __gmpf_init_set +__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_init_set_d __gmpf_init_set_d +__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); + +#define mpf_init_set_si __gmpf_init_set_si +__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); + +#define mpf_init_set_str __gmpf_init_set_str +__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); + +#define mpf_init_set_ui __gmpf_init_set_ui +__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); + +#define mpf_inp_str __gmpf_inp_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); +#endif + +#define mpf_integer_p __gmpf_integer_p +__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_mul __gmpf_mul +__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); + +#define mpf_mul_2exp __gmpf_mul_2exp +__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_mul_ui __gmpf_mul_ui +__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_neg __gmpf_neg +__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_out_str __gmpf_out_str +#ifdef _GMP_H_HAVE_FILE +__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); +#endif + +#define mpf_pow_ui __gmpf_pow_ui +__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_random2 __gmpf_random2 +__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); + +#define mpf_reldiff __gmpf_reldiff +__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); + +#define mpf_set __gmpf_set +__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_set_d __gmpf_set_d +__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); + +#define mpf_set_default_prec __gmpf_set_default_prec +__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((unsigned long int)) __GMP_NOTHROW; + +#define mpf_set_prec __gmpf_set_prec +__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, unsigned long int)); + +#define mpf_set_prec_raw __gmpf_set_prec_raw +__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, unsigned long int)) __GMP_NOTHROW; + +#define mpf_set_q __gmpf_set_q +__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); + +#define mpf_set_si __gmpf_set_si +__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); + +#define mpf_set_str __gmpf_set_str +__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); + +#define mpf_set_ui __gmpf_set_ui +__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); + +#define mpf_set_z __gmpf_set_z +__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); + +#define mpf_size __gmpf_size +__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpf_sqrt __gmpf_sqrt +__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_sqrt_ui __gmpf_sqrt_ui +__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); + +#define mpf_sub __gmpf_sub +__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); + +#define mpf_sub_ui __gmpf_sub_ui +__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); + +#define mpf_swap __gmpf_swap +__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; + +#define mpf_trunc __gmpf_trunc +__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); + +#define mpf_ui_div __gmpf_ui_div +__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); + +#define mpf_ui_sub __gmpf_ui_sub +__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); + +#define mpf_urandomb __gmpf_urandomb +__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, unsigned long int)); + + +/************ Low level positive-integer (i.e. N) routines. ************/ + +/* This is ugly, but we need to make user calls reach the prefixed function. */ + +#define mpn_add __MPN(add) +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpn_add +__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); +#endif + +#define mpn_add_1 __MPN(add_1) +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpn_add_1 +__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; +#endif + +#define mpn_add_n __MPN(add_n) +__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); + +#define mpn_addmul_1 __MPN(addmul_1) +__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); + +#define mpn_bdivmod __MPN(bdivmod) +__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); + +#define mpn_cmp __MPN(cmp) +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpn_cmp +__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; +#endif + +#define mpn_divexact_by3(dst,src,size) \ + mpn_divexact_by3c (dst, src, size, (mp_limb_t) 0) + +#define mpn_divexact_by3c __MPN(divexact_by3c) +__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); + +#define mpn_divmod_1(qp,np,nsize,dlimb) \ + mpn_divrem_1 (qp, (mp_size_t) 0, np, nsize, dlimb) + +#define mpn_divrem __MPN(divrem) +__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); + +#define mpn_divrem_1 __MPN(divrem_1) +__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); + +#define mpn_divrem_2 __MPN(divrem_2) +__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); + +#define mpn_gcd __MPN(gcd) +__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); + +#define mpn_gcd_1 __MPN(gcd_1) +__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; + +#define mpn_gcdext __MPN(gcdext) +__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); + +#define mpn_get_str __MPN(get_str) +__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); + +#define mpn_hamdist __MPN(hamdist) +__GMP_DECLSPEC unsigned long int mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpn_lshift __MPN(lshift) +__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); + +#define mpn_mod_1 __MPN(mod_1) +__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; + +#define mpn_mul __MPN(mul) +__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); + +#define mpn_mul_1 __MPN(mul_1) +__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); + +#define mpn_mul_n __MPN(mul_n) +__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); + +#define mpn_perfect_square_p __MPN(perfect_square_p) +__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; + +#define mpn_popcount __MPN(popcount) +__GMP_DECLSPEC unsigned long int mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; + +#define mpn_pow_1 __MPN(pow_1) +__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); + +/* undocumented now, but retained here for upward compatibility */ +#define mpn_preinv_mod_1 __MPN(preinv_mod_1) +__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; + +#define mpn_random __MPN(random) +__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); + +#define mpn_random2 __MPN(random2) +__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); + +#define mpn_rshift __MPN(rshift) +__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); + +#define mpn_scan0 __MPN(scan0) +__GMP_DECLSPEC unsigned long int mpn_scan0 __GMP_PROTO ((mp_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpn_scan1 __MPN(scan1) +__GMP_DECLSPEC unsigned long int mpn_scan1 __GMP_PROTO ((mp_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; + +#define mpn_set_str __MPN(set_str) +__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); + +#define mpn_sqrtrem __MPN(sqrtrem) +__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); + +#define mpn_sub __MPN(sub) +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpn_sub +__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); +#endif + +#define mpn_sub_1 __MPN(sub_1) +#if __GMP_INLINE_PROTOTYPES || __GMP_FORCE_mpn_sub_1 +__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; +#endif + +#define mpn_sub_n __MPN(sub_n) +__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); + +#define mpn_submul_1 __MPN(submul_1) +__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); + +#define mpn_tdiv_qr __MPN(tdiv_qr) +__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); + + +/**************** mpz inlines ****************/ + +/* The following are provided as inlines where possible, but always exist as + library functions too, for binary compatibility. + + Within gmp itself this inlining generally isn't relied on, since it + doesn't get done for all compilers, whereas if something is worth + inlining then it's worth arranging always. + + There are two styles of inlining here. When the same bit of code is + wanted for the inline as for the library version, then __GMP_FORCE_foo + arranges for that code to be emitted and the __GMP_EXTERN_INLINE + directive suppressed, eg. mpz_fits_uint_p. When a different bit of code + is wanted for the inline than for the library version, then + __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ + +#if defined (__GMP_EXTERN_INLINE) && ! __GMP_FORCE_mpz_abs +__GMP_EXTERN_INLINE void +mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) +{ + if (__gmp_w != __gmp_u) + mpz_set (__gmp_w, __gmp_u); + __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); +} +#endif + +#if GMP_NAIL_BITS == 0 +#define __GMPZ_FITS_UTYPE_P(z,maxval) \ + mp_size_t __gmp_n = z->_mp_size; \ + mp_ptr __gmp_p = z->_mp_d; \ + return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); +#else +#define __GMPZ_FITS_UTYPE_P(z,maxval) \ + mp_size_t __gmp_n = z->_mp_size; \ + mp_ptr __gmp_p = z->_mp_d; \ + return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ + || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_fits_uint_p +#if ! __GMP_FORCE_mpz_fits_uint_p +__GMP_EXTERN_INLINE +#endif +int +mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW +{ + __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_fits_ulong_p +#if ! __GMP_FORCE_mpz_fits_ulong_p +__GMP_EXTERN_INLINE +#endif +int +mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW +{ + __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_fits_ushort_p +#if ! __GMP_FORCE_mpz_fits_ushort_p +__GMP_EXTERN_INLINE +#endif +int +mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW +{ + __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_get_ui +#if ! __GMP_FORCE_mpz_get_ui +__GMP_EXTERN_INLINE +#endif +unsigned long +mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW +{ + mp_ptr __gmp_p = __gmp_z->_mp_d; + mp_size_t __gmp_n = __gmp_z->_mp_size; + mp_limb_t __gmp_l = __gmp_p[0]; + if (__GMP_ULONG_MAX <= GMP_NUMB_MASK) + return __gmp_l & (-(mp_limb_t) (__gmp_n != 0)); +#if GMP_NAIL_BITS != 0 /* redundant #if, shuts up compiler warnings */ + else /* happens for nails, but not if LONG_LONG_LIMB */ + { /* assume two limbs are enough to fill an ulong */ + __gmp_n = __GMP_ABS (__gmp_n); + if (__gmp_n <= 1) + return __gmp_l & (-(mp_limb_t) (__gmp_n != 0)); + else + return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); + } +#endif +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_getlimbn +#if ! __GMP_FORCE_mpz_getlimbn +__GMP_EXTERN_INLINE +#endif +mp_limb_t +mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW +{ + if (__GMP_ABS (__gmp_z->_mp_size) <= __gmp_n || __gmp_n < 0) + return 0; + else + return __gmp_z->_mp_d[__gmp_n]; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) && ! __GMP_FORCE_mpz_neg +__GMP_EXTERN_INLINE void +mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) +{ + if (__gmp_w != __gmp_u) + mpz_set (__gmp_w, __gmp_u); + __gmp_w->_mp_size = - __gmp_w->_mp_size; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_perfect_square_p +#if ! __GMP_FORCE_mpz_perfect_square_p +__GMP_EXTERN_INLINE +#endif +int +mpz_perfect_square_p (mpz_srcptr __gmp_a) +{ + mp_size_t __gmp_asize = __gmp_a->_mp_size; + if (__gmp_asize <= 0) + return (__gmp_asize == 0); /* zero is a square, negatives are not */ + else + return mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_popcount +#if ! __GMP_FORCE_mpz_popcount +__GMP_EXTERN_INLINE +#endif +unsigned long +mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW +{ + mp_size_t __gmp_usize = __gmp_u->_mp_size; + + if (__gmp_usize <= 0) + return (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); + else + return mpn_popcount (__gmp_u->_mp_d, __gmp_usize); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_set_q +#if ! __GMP_FORCE_mpz_set_q +__GMP_EXTERN_INLINE +#endif +void +mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) +{ + mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpz_size +#if ! __GMP_FORCE_mpz_size +__GMP_EXTERN_INLINE +#endif +size_t +mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW +{ + return __GMP_ABS (__gmp_z->_mp_size); +} +#endif + + +/**************** mpq inlines ****************/ + +#if defined (__GMP_EXTERN_INLINE) && ! __GMP_FORCE_mpq_abs +__GMP_EXTERN_INLINE void +mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) +{ + if (__gmp_w != __gmp_u) + mpq_set (__gmp_w, __gmp_u); + __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); +} +#endif + +#if defined (__GMP_EXTERN_INLINE) && ! __GMP_FORCE_mpq_neg +__GMP_EXTERN_INLINE void +mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) +{ + if (__gmp_w != __gmp_u) + mpq_set (__gmp_w, __gmp_u); + __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; +} +#endif + + +/**************** mpn inlines ****************/ + +/* The comments with __GMPN_ADD_1 below apply here too. + + The test for FUNCTION returning 0 should predict well. If it's assumed + {yp,ysize} will usually have a random number of bits then the high limb + won't be full and a carry out will occur a good deal less than 50% of the + time. + + ysize==0 isn't a documented feature, but is used internally in a few + places. + + Producing cout last stops it using up a register during the main part of + the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" + doesn't seem able to move the true and false legs of the conditional up + to the two places cout is generated. */ + +#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ + do { \ + mp_size_t __gmp_i; \ + mp_limb_t __gmp_x; \ + \ + /* ASSERT ((ysize) >= 0); */ \ + /* ASSERT ((xsize) >= (ysize)); */ \ + /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ + /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ + \ + __gmp_i = (ysize); \ + if (__gmp_i != 0) \ + { \ + if (FUNCTION (wp, xp, yp, __gmp_i)) \ + { \ + do \ + { \ + if (__gmp_i >= (xsize)) \ + { \ + (cout) = 1; \ + goto __gmp_done; \ + } \ + __gmp_x = (xp)[__gmp_i]; \ + } \ + while (TEST); \ + } \ + } \ + if ((wp) != (xp)) \ + __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ + (cout) = 0; \ + __gmp_done: \ + ; \ + } while (0) + +#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ + __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ + (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) +#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ + __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ + (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) + + +/* The use of __gmp_i indexing is designed to ensure a compile time src==dst + remains nice and clear to the compiler, so that __GMPN_COPY_REST can + disappear, and the load/add/store gets a chance to become a + read-modify-write on CISC CPUs. + + Alternatives: + + Using a pair of pointers instead of indexing would be possible, but gcc + isn't able to recognise compile-time src==dst in that case, even when the + pointers are incremented more or less together. Other compilers would + very likely have similar difficulty. + + gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or + similar to detect a compile-time src==dst. This works nicely on gcc + 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems + to be always false, for a pointer p. But the current code form seems + good enough for src==dst anyway. + + gcc on x86 as usual doesn't give particularly good flags handling for the + carry/borrow detection. It's tempting to want some multi instruction asm + blocks to help it, and this was tried, but in truth there's only a few + instructions to save and any gain is all too easily lost by register + juggling setting up for the asm. */ + +#if GMP_NAIL_BITS == 0 +#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ + do { \ + mp_size_t __gmp_i; \ + mp_limb_t __gmp_x, __gmp_r; \ + \ + /* ASSERT ((n) >= 1); */ \ + /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ + \ + __gmp_x = (src)[0]; \ + __gmp_r = __gmp_x OP (v); \ + (dst)[0] = __gmp_r; \ + if (CB (__gmp_r, __gmp_x, (v))) \ + { \ + (cout) = 1; \ + for (__gmp_i = 1; __gmp_i < (n);) \ + { \ + __gmp_x = (src)[__gmp_i]; \ + __gmp_r = __gmp_x OP 1; \ + (dst)[__gmp_i] = __gmp_r; \ + ++__gmp_i; \ + if (!CB (__gmp_r, __gmp_x, 1)) \ + { \ + if ((src) != (dst)) \ + __GMPN_COPY_REST (dst, src, n, __gmp_i); \ + (cout) = 0; \ + break; \ + } \ + } \ + } \ + else \ + { \ + if ((src) != (dst)) \ + __GMPN_COPY_REST (dst, src, n, 1); \ + (cout) = 0; \ + } \ + } while (0) +#endif + +#if GMP_NAIL_BITS >= 1 +#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ + do { \ + mp_size_t __gmp_i; \ + mp_limb_t __gmp_x, __gmp_r; \ + \ + /* ASSERT ((n) >= 1); */ \ + /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ + \ + __gmp_x = (src)[0]; \ + __gmp_r = __gmp_x OP (v); \ + (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ + if (__gmp_r >> GMP_NUMB_BITS != 0) \ + { \ + (cout) = 1; \ + for (__gmp_i = 1; __gmp_i < (n);) \ + { \ + __gmp_x = (src)[__gmp_i]; \ + __gmp_r = __gmp_x OP 1; \ + (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ + ++__gmp_i; \ + if (__gmp_r >> GMP_NUMB_BITS == 0) \ + { \ + if ((src) != (dst)) \ + __GMPN_COPY_REST (dst, src, n, __gmp_i); \ + (cout) = 0; \ + break; \ + } \ + } \ + } \ + else \ + { \ + if ((src) != (dst)) \ + __GMPN_COPY_REST (dst, src, n, 1); \ + (cout) = 0; \ + } \ + } while (0) +#endif + +#define __GMPN_ADDCB(r,x,y) ((r) < (y)) +#define __GMPN_SUBCB(r,x,y) ((x) < (y)) + +#define __GMPN_ADD_1(cout, dst, src, n, v) \ + __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) +#define __GMPN_SUB_1(cout, dst, src, n, v) \ + __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) + + +/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or + negative. size==0 is allowed. On random data usually only one limb will + need to be examined to get a result, so it's worth having it inline. */ +#define __GMPN_CMP(result, xp, yp, size) \ + do { \ + mp_size_t __gmp_i; \ + mp_limb_t __gmp_x, __gmp_y; \ + \ + /* ASSERT ((size) >= 0); */ \ + \ + (result) = 0; \ + __gmp_i = (size); \ + while (--__gmp_i >= 0) \ + { \ + __gmp_x = (xp)[__gmp_i]; \ + __gmp_y = (yp)[__gmp_i]; \ + if (__gmp_x != __gmp_y) \ + { \ + /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ + (result) = (__gmp_x > __gmp_y ? 1 : -1); \ + break; \ + } \ + } \ + } while (0) + + +/* For power and powerpc we want an inline ldu/stu/bdnz loop for copying. + On ppc630 for instance this is optimal since it can sustain only 1 store + per cycle. + + gcc 2.95.x (powerpc64 -maix64, or powerpc32) doesn't recognise the "for" + loop in the generic code below can become ldu/stu/bdnz. The do/while + here helps it get to that. + + In gcc -mpowerpc64 mode, without -maix64, __size seems to want to be an + mp_limb_t to get into the ctr register, and even then the loop is a + curious ldu/stu/bdz/b. But let's not worry about that unless there's a + system using this. An asm block could force what we want if necessary. + + xlc 3.1 already generates ldu/stu/bdnz from the generic C, and does so + from this loop too. */ + +#if __GMP_HAVE_HOST_CPU_FAMILY_power || __GMP_HAVE_HOST_CPU_FAMILY_powerpc +#define __GMPN_COPY_INCR(dst, src, size) \ + do { \ + /* ASSERT ((size) >= 0); */ \ + /* ASSERT (MPN_SAME_OR_INCR_P (dst, src, size)); */ \ + if ((size) != 0) \ + { \ + mp_ptr __gmp_copy_incr_dst = (dst) - 1; \ + mp_srcptr __gmp_copy_incr_src = (src) - 1; \ + mp_size_t __gmp_copy_incr_size = (size); \ + do \ + *++__gmp_copy_incr_dst = *++__gmp_copy_incr_src; \ + while (--__gmp_copy_incr_size != 0); \ + } \ + } while (0) +#define __GMPN_COPY(dst, src, size) \ + do { \ + /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ + __GMPN_COPY_INCR (dst, src, size); \ + } while (0) +#endif + +#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) +#define __GMPN_COPY_REST(dst, src, size, start) \ + do { \ + /* ASSERT ((start) >= 0); */ \ + /* ASSERT ((start) <= (size)); */ \ + __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ + } while (0) +#endif + +/* Copy {src,size} to {dst,size}, starting at "start". This is designed to + keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, + __GMPN_ADD, etc. */ +#if ! defined (__GMPN_COPY_REST) +#define __GMPN_COPY_REST(dst, src, size, start) \ + do { \ + mp_size_t __gmp_j; \ + /* ASSERT ((size) >= 0); */ \ + /* ASSERT ((start) >= 0); */ \ + /* ASSERT ((start) <= (size)); */ \ + /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ + for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ + (dst)[__gmp_j] = (src)[__gmp_j]; \ + } while (0) +#endif + +/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use + mpn_copyi if there's a native version, and if we don't mind demanding + binary compatibility for it (on targets which use it). */ + +#if ! defined (__GMPN_COPY) +#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) +#endif + + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpn_add +#if ! __GMP_FORCE_mpn_add +__GMP_EXTERN_INLINE +#endif +mp_limb_t +mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) +{ + mp_limb_t __gmp_c; + __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); + return __gmp_c; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpn_add_1 +#if ! __GMP_FORCE_mpn_add_1 +__GMP_EXTERN_INLINE +#endif +mp_limb_t +mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW +{ + mp_limb_t __gmp_c; + __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); + return __gmp_c; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpn_cmp +#if ! __GMP_FORCE_mpn_cmp +__GMP_EXTERN_INLINE +#endif +int +mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW +{ + int __gmp_result; + __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); + return __gmp_result; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpn_sub +#if ! __GMP_FORCE_mpn_sub +__GMP_EXTERN_INLINE +#endif +mp_limb_t +mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) +{ + mp_limb_t __gmp_c; + __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); + return __gmp_c; +} +#endif + +#if defined (__GMP_EXTERN_INLINE) || __GMP_FORCE_mpn_sub_1 +#if ! __GMP_FORCE_mpn_sub_1 +__GMP_EXTERN_INLINE +#endif +mp_limb_t +mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW +{ + mp_limb_t __gmp_c; + __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); + return __gmp_c; +} +#endif + +#if defined (__cplusplus) +} +#endif + + +/* Allow faster testing for negative, zero, and positive. */ +#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) +#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) +#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) + +/* When using GCC, optimize certain common comparisons. */ +#if defined (__GNUC__) +#define mpz_cmp_ui(Z,UI) \ + (__builtin_constant_p (UI) && (UI) == 0 \ + ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) +#define mpz_cmp_si(Z,SI) \ + (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ + : __builtin_constant_p (SI) && (SI) > 0 \ + ? _mpz_cmp_ui (Z, (unsigned long int) SI) \ + : _mpz_cmp_si (Z,SI)) +#define mpq_cmp_ui(Q,NUI,DUI) \ + (__builtin_constant_p (NUI) && (NUI) == 0 \ + ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) +#define mpq_cmp_si(q,n,d) \ + (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ + ? mpq_cmp_ui (q, (unsigned long) (n), d) \ + : _mpq_cmp_si (q, n, d)) +#else +#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) +#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) +#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) +#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) +#endif + + +/* Using "&" rather than "&&" means these can come out branch-free. Every + mpz_t has at least one limb allocated, so fetching the low limb is always + allowed. */ +#define mpz_odd_p(z) ((int) ((z)->_mp_size != 0) & (int) (z)->_mp_d[0]) +#define mpz_even_p(z) (! mpz_odd_p (z)) + + +/**************** C++ routines ****************/ + +#ifdef __cplusplus +__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); +__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); +__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); +__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); +__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); +__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); +#endif + + +/* Compatibility with GMP 2 and earlier. */ +#define mpn_divmod(qp,np,nsize,dp,dsize) \ + mpn_divrem (qp, (mp_size_t) 0, np, nsize, dp, dsize) + +/* Compatibility with GMP 1. */ +#define mpz_mdiv mpz_fdiv_q +#define mpz_mdivmod mpz_fdiv_qr +#define mpz_mmod mpz_fdiv_r +#define mpz_mdiv_ui mpz_fdiv_q_ui +#define mpz_mdivmod_ui(q,r,n,d) \ + ((r == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) +#define mpz_mmod_ui(r,n,d) \ + ((r == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) + +/* Useful synonyms, but not quite compatible with GMP 1. */ +#define mpz_div mpz_fdiv_q +#define mpz_divmod mpz_fdiv_qr +#define mpz_div_ui mpz_fdiv_q_ui +#define mpz_divmod_ui mpz_fdiv_qr_ui +#define mpz_mod_ui mpz_fdiv_r_ui +#define mpz_div_2exp mpz_fdiv_q_2exp +#define mpz_mod_2exp mpz_fdiv_r_2exp + +enum +{ + GMP_ERROR_NONE = 0, + GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, + GMP_ERROR_DIVISION_BY_ZERO = 2, + GMP_ERROR_SQRT_OF_NEGATIVE = 4, + GMP_ERROR_INVALID_ARGUMENT = 8, + GMP_ERROR_ALLOCATE = 16, + GMP_ERROR_BAD_STRING = 32, + GMP_ERROR_UNUSED_ERROR +}; + +/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ +#define __GNU_MP_VERSION 4 +#define __GNU_MP_VERSION_MINOR 1 +#define __GNU_MP_VERSION_PATCHLEVEL 0 + +#define __GMP_H__ +#endif /* __GMP_H__ */ diff --git a/mysql/include/mysql/config-win.h b/include/mysql/config-win.h similarity index 100% rename from mysql/include/mysql/config-win.h rename to include/mysql/config-win.h diff --git a/mysql/include/mysql/decimal.h b/include/mysql/decimal.h similarity index 100% rename from mysql/include/mysql/decimal.h rename to include/mysql/decimal.h diff --git a/mysql/include/mysql/errmsg.h b/include/mysql/errmsg.h similarity index 100% rename from mysql/include/mysql/errmsg.h rename to include/mysql/errmsg.h diff --git a/mysql/include/mysql/keycache.h b/include/mysql/keycache.h similarity index 100% rename from mysql/include/mysql/keycache.h rename to include/mysql/keycache.h diff --git a/mysql/include/mysql/libmysql.def b/include/mysql/libmysql.def similarity index 100% rename from mysql/include/mysql/libmysql.def rename to include/mysql/libmysql.def diff --git a/mysql/include/mysql/libmysqld.def b/include/mysql/libmysqld.def similarity index 100% rename from mysql/include/mysql/libmysqld.def rename to include/mysql/libmysqld.def diff --git a/mysql/include/mysql/m_ctype.h b/include/mysql/m_ctype.h similarity index 100% rename from mysql/include/mysql/m_ctype.h rename to include/mysql/m_ctype.h diff --git a/mysql/include/mysql/m_string.h b/include/mysql/m_string.h similarity index 100% rename from mysql/include/mysql/m_string.h rename to include/mysql/m_string.h diff --git a/mysql/include/mysql/my_alloc.h b/include/mysql/my_alloc.h similarity index 100% rename from mysql/include/mysql/my_alloc.h rename to include/mysql/my_alloc.h diff --git a/mysql/include/mysql/my_attribute.h b/include/mysql/my_attribute.h similarity index 100% rename from mysql/include/mysql/my_attribute.h rename to include/mysql/my_attribute.h diff --git a/mysql/include/mysql/my_dbug.h b/include/mysql/my_dbug.h similarity index 100% rename from mysql/include/mysql/my_dbug.h rename to include/mysql/my_dbug.h diff --git a/mysql/include/mysql/my_dir.h b/include/mysql/my_dir.h similarity index 100% rename from mysql/include/mysql/my_dir.h rename to include/mysql/my_dir.h diff --git a/mysql/include/mysql/my_getopt.h b/include/mysql/my_getopt.h similarity index 100% rename from mysql/include/mysql/my_getopt.h rename to include/mysql/my_getopt.h diff --git a/mysql/include/mysql/my_global.h b/include/mysql/my_global.h similarity index 100% rename from mysql/include/mysql/my_global.h rename to include/mysql/my_global.h diff --git a/mysql/include/mysql/my_list.h b/include/mysql/my_list.h similarity index 100% rename from mysql/include/mysql/my_list.h rename to include/mysql/my_list.h diff --git a/mysql/include/mysql/my_net.h b/include/mysql/my_net.h similarity index 100% rename from mysql/include/mysql/my_net.h rename to include/mysql/my_net.h diff --git a/mysql/include/mysql/my_no_pthread.h b/include/mysql/my_no_pthread.h similarity index 100% rename from mysql/include/mysql/my_no_pthread.h rename to include/mysql/my_no_pthread.h diff --git a/mysql/include/mysql/my_pthread.h b/include/mysql/my_pthread.h similarity index 100% rename from mysql/include/mysql/my_pthread.h rename to include/mysql/my_pthread.h diff --git a/mysql/include/mysql/my_sys.h b/include/mysql/my_sys.h similarity index 100% rename from mysql/include/mysql/my_sys.h rename to include/mysql/my_sys.h diff --git a/mysql/include/mysql/my_xml.h b/include/mysql/my_xml.h similarity index 100% rename from mysql/include/mysql/my_xml.h rename to include/mysql/my_xml.h diff --git a/mysql/include/mysql/mysql.h b/include/mysql/mysql.h similarity index 100% rename from mysql/include/mysql/mysql.h rename to include/mysql/mysql.h diff --git a/mysql/include/mysql/mysql/plugin.h b/include/mysql/mysql/plugin.h similarity index 100% rename from mysql/include/mysql/mysql/plugin.h rename to include/mysql/mysql/plugin.h diff --git a/mysql/include/mysql/mysql_com.h b/include/mysql/mysql_com.h similarity index 100% rename from mysql/include/mysql/mysql_com.h rename to include/mysql/mysql_com.h diff --git a/mysql/include/mysql/mysql_embed.h b/include/mysql/mysql_embed.h similarity index 100% rename from mysql/include/mysql/mysql_embed.h rename to include/mysql/mysql_embed.h diff --git a/mysql/include/mysql/mysql_time.h b/include/mysql/mysql_time.h similarity index 100% rename from mysql/include/mysql/mysql_time.h rename to include/mysql/mysql_time.h diff --git a/mysql/include/mysql/mysql_version.h b/include/mysql/mysql_version.h similarity index 100% rename from mysql/include/mysql/mysql_version.h rename to include/mysql/mysql_version.h diff --git a/mysql/include/mysql/mysqld_ername.h b/include/mysql/mysqld_ername.h similarity index 100% rename from mysql/include/mysql/mysqld_ername.h rename to include/mysql/mysqld_ername.h diff --git a/mysql/include/mysql/mysqld_error.h b/include/mysql/mysqld_error.h similarity index 100% rename from mysql/include/mysql/mysqld_error.h rename to include/mysql/mysqld_error.h diff --git a/mysql/include/mysql/sql_common.h b/include/mysql/sql_common.h similarity index 100% rename from mysql/include/mysql/sql_common.h rename to include/mysql/sql_common.h diff --git a/mysql/include/mysql/sql_state.h b/include/mysql/sql_state.h similarity index 100% rename from mysql/include/mysql/sql_state.h rename to include/mysql/sql_state.h diff --git a/mysql/include/mysql/sslopt-case.h b/include/mysql/sslopt-case.h similarity index 100% rename from mysql/include/mysql/sslopt-case.h rename to include/mysql/sslopt-case.h diff --git a/mysql/include/mysql/sslopt-longopts.h b/include/mysql/sslopt-longopts.h similarity index 100% rename from mysql/include/mysql/sslopt-longopts.h rename to include/mysql/sslopt-longopts.h diff --git a/mysql/include/mysql/sslopt-vars.h b/include/mysql/sslopt-vars.h similarity index 100% rename from mysql/include/mysql/sslopt-vars.h rename to include/mysql/sslopt-vars.h diff --git a/mysql/include/mysql/typelib.h b/include/mysql/typelib.h similarity index 100% rename from mysql/include/mysql/typelib.h rename to include/mysql/typelib.h diff --git a/zlib/include/zconf.h b/include/zlib/zconf.h similarity index 100% rename from zlib/include/zconf.h rename to include/zlib/zconf.h diff --git a/zlib/include/zlib.h b/include/zlib/zlib.h similarity index 100% rename from zlib/include/zlib.h rename to include/zlib/zlib.h diff --git a/BNCSutil.dll b/lib/BNCSutil.dll similarity index 100% rename from BNCSutil.dll rename to lib/BNCSutil.dll diff --git a/lib/gmp.dll b/lib/gmp.dll new file mode 100644 index 0000000..26f4fbf Binary files /dev/null and b/lib/gmp.dll differ diff --git a/lib/gmp.txt b/lib/gmp.txt new file mode 100644 index 0000000..3030bd5 --- /dev/null +++ b/lib/gmp.txt @@ -0,0 +1,2 @@ +beware, old version 4.1.2 of libgmp (found it precompiled online, should be replaced with a more recent one) +Remember to replace the header in ../include too! \ No newline at end of file diff --git a/libmysql.dll b/lib/libmysql.dll similarity index 100% rename from libmysql.dll rename to lib/libmysql.dll diff --git a/zlib1.dll b/lib/zlib1.dll similarity index 100% rename from zlib1.dll rename to lib/zlib1.dll diff --git a/mysql/lib/opt/libmysql.lib b/mysql/lib/opt/libmysql.lib deleted file mode 100644 index 0608eff..0000000 Binary files a/mysql/lib/opt/libmysql.lib and /dev/null differ diff --git a/StormLib/Info.plist b/src/StormLib/Info.plist similarity index 100% rename from StormLib/Info.plist rename to src/StormLib/Info.plist diff --git a/StormLib/Storm.lib b/src/StormLib/Storm.lib similarity index 100% rename from StormLib/Storm.lib rename to src/StormLib/Storm.lib diff --git a/StormLib/StormDll.bat b/src/StormLib/StormDll.bat similarity index 100% rename from StormLib/StormDll.bat rename to src/StormLib/StormDll.bat diff --git a/StormLib/StormDll.sln b/src/StormLib/StormDll.sln similarity index 100% rename from StormLib/StormDll.sln rename to src/StormLib/StormDll.sln diff --git a/StormLib/StormDll.vcproj b/src/StormLib/StormDll.vcproj similarity index 100% rename from StormLib/StormDll.vcproj rename to src/StormLib/StormDll.vcproj diff --git a/StormLib/StormLib-Info.plist b/src/StormLib/StormLib-Info.plist similarity index 100% rename from StormLib/StormLib-Info.plist rename to src/StormLib/StormLib-Info.plist diff --git a/StormLib/StormLib.bat b/src/StormLib/StormLib.bat similarity index 100% rename from StormLib/StormLib.bat rename to src/StormLib/StormLib.bat diff --git a/StormLib/StormLib.sln b/src/StormLib/StormLib.sln similarity index 100% rename from StormLib/StormLib.sln rename to src/StormLib/StormLib.sln diff --git a/StormLib/StormLib.vcproj b/src/StormLib/StormLib.vcproj similarity index 100% rename from StormLib/StormLib.vcproj rename to src/StormLib/StormLib.vcproj diff --git a/StormLib/StormLib.xcodeproj/project.pbxproj b/src/StormLib/StormLib.xcodeproj/project.pbxproj similarity index 100% rename from StormLib/StormLib.xcodeproj/project.pbxproj rename to src/StormLib/StormLib.xcodeproj/project.pbxproj diff --git a/StormLib/StormLib64-Info.plist b/src/StormLib/StormLib64-Info.plist similarity index 100% rename from StormLib/StormLib64-Info.plist rename to src/StormLib/StormLib64-Info.plist diff --git a/StormLib/StormLibDll.sln b/src/StormLib/StormLibDll.sln similarity index 91% rename from StormLib/StormLibDll.sln rename to src/StormLib/StormLibDll.sln index 61fdb2a..a84df24 100644 --- a/StormLib/StormLibDll.sln +++ b/src/StormLib/StormLibDll.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StormLibDll", "StormLibDll.vcproj", "{A22DEC27-4BA6-479F-AF9C-0229ACFD7E3A}" EndProject Global diff --git a/StormLib/StormLibDll.vcproj b/src/StormLib/StormLibDll.vcproj similarity index 95% rename from StormLib/StormLibDll.vcproj rename to src/StormLib/StormLibDll.vcproj index b4ec7eb..6bb65ca 100644 --- a/StormLib/StormLibDll.vcproj +++ b/src/StormLib/StormLibDll.vcproj @@ -1,10 +1,11 @@ @@ -100,15 +103,12 @@ - - #include /* Myriad Utility Header */ #include /* CheckRevision / EXE info */ diff --git a/src/bncsutil/bncsutil.pro b/src/bncsutil/bncsutil.pro new file mode 100644 index 0000000..2a720a5 --- /dev/null +++ b/src/bncsutil/bncsutil.pro @@ -0,0 +1,24 @@ +# ------------------------------------------------- +# Project created by QtCreator 2010-04-19T13:31:03 +# ------------------------------------------------- +! include( ../lib.pri ) { + error( Couldn't find lib.pri! ) +} + +QT -= gui +TARGET = bncsutil +INCLUDEPATH += ../ ../../include + +DEFINES += MUTIL_LIB_BUILD + + +SOURCES += bsha1.cpp cdkeydecoder.cpp checkrevision.cpp decodekey.cpp file.cpp libinfo.cpp oldauth.cpp \ + nls.c pe.c sha1.c stack.c + +LIBS += -L../../lib -lgmp +#macx { +# LIBS += -framework CoreFoundation -framework CoreServices +# LIBS += -L. -L/usr/lib -lbz2 -lz +#} + +HEADERS += diff --git a/bncsutil/src/bncsutil/bsha1.cpp b/src/bncsutil/bsha1.cpp similarity index 99% rename from bncsutil/src/bncsutil/bsha1.cpp rename to src/bncsutil/bsha1.cpp index 4344f0f..622d050 100644 --- a/bncsutil/src/bncsutil/bsha1.cpp +++ b/src/bncsutil/bsha1.cpp @@ -139,7 +139,7 @@ MEXP(void) calcHashBuf(const char* input, unsigned int length, char* result) { #else -MEXP(void) calcHashBuf(const char* input, size_t length, char* result) { +void calcHashBuf(const char* input, size_t length, char* result) { int i; uint32_t a, b, c, d, e, g; uint32_t* ldata; diff --git a/bncsutil/src/bncsutil/bsha1.h b/src/bncsutil/bsha1.h similarity index 100% rename from bncsutil/src/bncsutil/bsha1.h rename to src/bncsutil/bsha1.h diff --git a/bncsutil/src/bncsutil/buffer.h b/src/bncsutil/buffer.h similarity index 100% rename from bncsutil/src/bncsutil/buffer.h rename to src/bncsutil/buffer.h diff --git a/bncsutil/src/bncsutil/cdkeydecoder.cpp b/src/bncsutil/cdkeydecoder.cpp similarity index 100% rename from bncsutil/src/bncsutil/cdkeydecoder.cpp rename to src/bncsutil/cdkeydecoder.cpp diff --git a/bncsutil/src/bncsutil/cdkeydecoder.h b/src/bncsutil/cdkeydecoder.h similarity index 100% rename from bncsutil/src/bncsutil/cdkeydecoder.h rename to src/bncsutil/cdkeydecoder.h diff --git a/bncsutil/src/bncsutil/checkrevision.cpp b/src/bncsutil/checkrevision.cpp similarity index 97% rename from bncsutil/src/bncsutil/checkrevision.cpp rename to src/bncsutil/checkrevision.cpp index 99819a6..4d01ac1 100644 --- a/bncsutil/src/bncsutil/checkrevision.cpp +++ b/src/bncsutil/checkrevision.cpp @@ -358,16 +358,16 @@ MEXP(int) getExeInfo(const char* file_name, char* exe_info, switch (platform) { case BNCSUTIL_PLATFORM_X86: #ifdef MOS_WINDOWS - infoSize = GetFileVersionInfoSize(file_name, &bytesRead); + infoSize = GetFileVersionInfoSizeA(file_name, &bytesRead); if (infoSize == 0) return 0; buf = (LPBYTE) VirtualAlloc(NULL, infoSize, MEM_COMMIT, PAGE_READWRITE); if (buf == NULL) return 0; - if (GetFileVersionInfo(file_name, NULL, infoSize, buf) == FALSE) + if (GetFileVersionInfoA(file_name, NULL, infoSize, buf) == FALSE) return 0; - if (!VerQueryValue(buf, "\\", (LPVOID*) &ffi, (PUINT) &infoSize)) + if (!VerQueryValueA(buf, "\\", (LPVOID*) &ffi, (PUINT) &infoSize)) return 0; *version = @@ -444,7 +444,7 @@ MEXP(int) getExeInfo(const char* file_name, char* exe_info, } #ifdef MOS_WINDOWS - hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, + hFile = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; diff --git a/bncsutil/src/bncsutil/checkrevision.h b/src/bncsutil/checkrevision.h similarity index 100% rename from bncsutil/src/bncsutil/checkrevision.h rename to src/bncsutil/checkrevision.h diff --git a/bncsutil/src/bncsutil/debug.c b/src/bncsutil/debug.c similarity index 100% rename from bncsutil/src/bncsutil/debug.c rename to src/bncsutil/debug.c diff --git a/bncsutil/src/bncsutil/debug.h b/src/bncsutil/debug.h similarity index 100% rename from bncsutil/src/bncsutil/debug.h rename to src/bncsutil/debug.h diff --git a/bncsutil/src/bncsutil/decodekey.cpp b/src/bncsutil/decodekey.cpp similarity index 100% rename from bncsutil/src/bncsutil/decodekey.cpp rename to src/bncsutil/decodekey.cpp diff --git a/bncsutil/src/bncsutil/decodekey.h b/src/bncsutil/decodekey.h similarity index 100% rename from bncsutil/src/bncsutil/decodekey.h rename to src/bncsutil/decodekey.h diff --git a/bncsutil/src/bncsutil/file.cpp b/src/bncsutil/file.cpp similarity index 96% rename from bncsutil/src/bncsutil/file.cpp rename to src/bncsutil/file.cpp index 2e4e783..85c0f15 100644 --- a/bncsutil/src/bncsutil/file.cpp +++ b/src/bncsutil/file.cpp @@ -8,7 +8,7 @@ #define BWIN 1 #include -typedef std::map mapping_map; +typedef std::map mapping_map; #else #define BWIN 0 #include @@ -57,7 +57,7 @@ file_t file_open(const char* filename, unsigned int mode) open_mode = CREATE_ALWAYS; } - file = CreateFile(filename, access, share_mode, NULL, open_mode, + file = CreateFileA(filename, access, share_mode, NULL, open_mode, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) { @@ -83,7 +83,11 @@ file_t file_open(const char* filename, unsigned int mode) delete data; return (file_t) 0; } +#ifdef _MSC_VER strcpy_s((char*) data->filename, filename_buf_len, filename); +#else + strncpy((char*) data->filename, filename, filename_buf_len); +#endif data->f = file; @@ -164,7 +168,7 @@ void* file_map(file_t file, size_t len, off_t offset) return base; } -void file_unmap(file_t file, const void* base) +void file_unmap(file_t file, void* base) { mapping_map::iterator item = file->mappings.find(base); HANDLE mapping; diff --git a/bncsutil/src/bncsutil/file.h b/src/bncsutil/file.h similarity index 96% rename from bncsutil/src/bncsutil/file.h rename to src/bncsutil/file.h index 4721e28..f64545b 100644 --- a/bncsutil/src/bncsutil/file.h +++ b/src/bncsutil/file.h @@ -53,7 +53,7 @@ size_t file_write(file_t file, const void* ptr, size_t size, size_t file_size(file_t file); void* file_map(file_t file, size_t len, off_t offset); -void file_unmap(file_t file, const void* mapping); +void file_unmap(file_t file, void* mapping); #ifdef __cplusplus } diff --git a/bncsutil/src/bncsutil/keytables.h b/src/bncsutil/keytables.h similarity index 100% rename from bncsutil/src/bncsutil/keytables.h rename to src/bncsutil/keytables.h diff --git a/bncsutil/src/bncsutil/libinfo.cpp b/src/bncsutil/libinfo.cpp similarity index 100% rename from bncsutil/src/bncsutil/libinfo.cpp rename to src/bncsutil/libinfo.cpp diff --git a/bncsutil/src/bncsutil/libinfo.h b/src/bncsutil/libinfo.h similarity index 100% rename from bncsutil/src/bncsutil/libinfo.h rename to src/bncsutil/libinfo.h diff --git a/bncsutil/src/bncsutil/ms_stdint.h b/src/bncsutil/ms_stdint.h similarity index 100% rename from bncsutil/src/bncsutil/ms_stdint.h rename to src/bncsutil/ms_stdint.h diff --git a/bncsutil/src/bncsutil/mutil.h b/src/bncsutil/mutil.h similarity index 100% rename from bncsutil/src/bncsutil/mutil.h rename to src/bncsutil/mutil.h diff --git a/bncsutil/src/bncsutil/mutil_types.h b/src/bncsutil/mutil_types.h similarity index 98% rename from bncsutil/src/bncsutil/mutil_types.h rename to src/bncsutil/mutil_types.h index aec9a3d..e64134e 100644 --- a/bncsutil/src/bncsutil/mutil_types.h +++ b/src/bncsutil/mutil_types.h @@ -26,9 +26,9 @@ #ifndef BNCSUTIL_MUTIL_TYPES_H_INCLUDED #define BNCSUTIL_MUTIL_TYPES_H_INCLUDED -#ifdef WIN32 - #include "ms_stdint.h" -#else +//#ifdef WIN32 +// #include "ms_stdint.h" +//#else #if defined(_MSC_VER) || (defined(HAVE_STDINT_H) && !HAVE_STDINT_H) // no stdint.h available @@ -140,6 +140,6 @@ typedef unsigned long long uintmax_t; #include #endif -#endif /* WIN32 */ +//#endif /* WIN32 */ #endif /* BNCSUTIL_MUTIL_TYPES_H_INCLUDED */ diff --git a/bncsutil/src/bncsutil/nls.c b/src/bncsutil/nls.c similarity index 100% rename from bncsutil/src/bncsutil/nls.c rename to src/bncsutil/nls.c diff --git a/bncsutil/src/bncsutil/nls.h b/src/bncsutil/nls.h similarity index 100% rename from bncsutil/src/bncsutil/nls.h rename to src/bncsutil/nls.h diff --git a/bncsutil/src/bncsutil/oldauth.cpp b/src/bncsutil/oldauth.cpp similarity index 100% rename from bncsutil/src/bncsutil/oldauth.cpp rename to src/bncsutil/oldauth.cpp diff --git a/bncsutil/src/bncsutil/oldauth.h b/src/bncsutil/oldauth.h similarity index 100% rename from bncsutil/src/bncsutil/oldauth.h rename to src/bncsutil/oldauth.h diff --git a/bncsutil/src/bncsutil/pe.c b/src/bncsutil/pe.c similarity index 100% rename from bncsutil/src/bncsutil/pe.c rename to src/bncsutil/pe.c diff --git a/bncsutil/src/bncsutil/pe.h b/src/bncsutil/pe.h similarity index 100% rename from bncsutil/src/bncsutil/pe.h rename to src/bncsutil/pe.h diff --git a/bncsutil/src/bncsutil/sha1.c b/src/bncsutil/sha1.c similarity index 100% rename from bncsutil/src/bncsutil/sha1.c rename to src/bncsutil/sha1.c diff --git a/bncsutil/src/bncsutil/sha1.h b/src/bncsutil/sha1.h similarity index 100% rename from bncsutil/src/bncsutil/sha1.h rename to src/bncsutil/sha1.h diff --git a/bncsutil/src/bncsutil/stack.c b/src/bncsutil/stack.c similarity index 100% rename from bncsutil/src/bncsutil/stack.c rename to src/bncsutil/stack.c diff --git a/bncsutil/src/bncsutil/stack.h b/src/bncsutil/stack.h similarity index 100% rename from bncsutil/src/bncsutil/stack.h rename to src/bncsutil/stack.h diff --git a/src/cli/cli.pro b/src/cli/cli.pro new file mode 100644 index 0000000..4b9cb9c --- /dev/null +++ b/src/cli/cli.pro @@ -0,0 +1,28 @@ +# ------------------------------------------------- +# Project created by QtCreator 2010-04-19T13:31:03 +# ------------------------------------------------- +QT += network sql +QT -= gui +TARGET = ghost++ +CONFIG += console debug_and_release link_prl +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += main.cpp +OTHER_FILES += w3g_format.txt \ + w3g_actions.txt \ + ghost.vcproj +INCLUDEPATH += ../ \ + ../libghost +# ../zlib/include +LIBS += -L../../lib \ + -lghost -lbncsutil -lgmp + +macx { + LIBS += -framework CoreFoundation -framework CoreServices + QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.5.sdk + LIBS += -L/usr/lib -lbz2 -lz +} + +#HEADERS += ghost.h + +DESTDIR = ../../bin diff --git a/src/cli/main.cpp b/src/cli/main.cpp new file mode 100644 index 0000000..60ddec5 --- /dev/null +++ b/src/cli/main.cpp @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include + +#include "ghost.h" +#include "util.h" +#include "config.h" +#ifdef WIN32 +#include "windows.h" +#endif + +QFile gLogFile; +QTextStream gLogStream(&gLogFile); + +QString gCFGFile; +quint32 gLogMethod; +CGHost *gGHost = NULL; + +void SignalCatcher2( int s ) +{ + CONSOLE_Print( "[!!!] caught signal " + QString::number( s ) + ", exiting NOW" ); + + if( gGHost ) + { + if( gGHost->GetExiting( ) ) + exit( 1 ); + else + gGHost->Exit( ); + } + else + exit( 1 ); +} + +void SignalCatcher( int s ) +{ + // signal( SIGABRT, SignalCatcher2 ); + signal( SIGINT, SignalCatcher2 ); + + CONSOLE_Print( "[!!!] caught signal " + QString::number( s ) + ", exiting nicely" ); + + if( gGHost ) + gGHost->EventExitNice(); + else + exit( 1 ); +} + +// +// main +// + +#include "mpqarchive.h" +#include "mpqfile.h" + +int main( int argc, char **argv ) +{ + QCoreApplication a(argc, argv); + + /*MPQArchive arch("/mnt/disk/Programme/Warcraft III/War3Patch.mpq"); + if (!arch.open() && arch.m_Error != MPQArchive::NO_FILE_LIST) + { + DEBUG_Print("Failed to open, error " + QString::number(arch.m_Error)); + exit(1); + }*/ + + + + /*if (!arch.m_ListFile->read()) + { + DEBUG_Print("Failed to read file list, error " + QString::number(arch.m_ListFile->m_Error)); + }*/ + + + /*DEBUG_Print("Successfully open MPQ file"); + + MPQFile* common_j = arch.getFile("Scripts\\common.j"); + + if (!common_j->read()) + { + DEBUG_Print("Failed to read common.j, error " + QString::number(common_j->m_Error)); + } + exit(0);*/ + + gCFGFile = "ghost.cfg"; + + if( argc > 1 && argv[1] ) + gCFGFile = argv[1]; + + // read config file + + CConfig CFG; + CFG.Read( "default.cfg" ); + CFG.Read( gCFGFile ); + gLogFile.setFileName(CFG.GetString( "bot_log", QString( ) )); + gLogMethod = CFG.GetInt( "bot_logmethod", 1 ); + + if( !gLogFile.fileName().isEmpty() ) + { + if( gLogMethod == 1 ) + { + // log method 1: open, append, and close the log for every message + // this works well on Linux but poorly on Windows, particularly as the log file grows in size + // the log file can be edited/moved/deleted while GHost++ is running + } + else if( gLogMethod == 2 ) + { + // log method 2: open the log on startup, flush the log for every message, close the log on shutdown + // the log file CANNOT be edited/moved/deleted while GHost++ is running + + gLogFile.open(QFile::WriteOnly | QFile::Append); + } + } + + CONSOLE_Print( "[GHOST] starting up" ); + + if( !gLogFile.fileName().isEmpty() ) + { + if( gLogMethod == 1 ) + CONSOLE_Print( "[GHOST] using log method 1, logging is enabled and [" + gLogFile.fileName() + "] will not be locked" ); + else if( gLogMethod == 2 ) + { + if( gLogFile.error() != QFile::NoError ) + CONSOLE_Print( "[GHOST] using log method 2 but unable to open [" + gLogFile.fileName() + "] for appending, logging is disabled" ); + else + CONSOLE_Print( "[GHOST] using log method 2, logging is enabled and [" + gLogFile.fileName() + "] is now locked" ); + } + } + else + CONSOLE_Print( "[GHOST] no log file specified, logging is disabled" ); + + // catch SIGABRT and SIGINT + + // signal( SIGABRT, SignalCatcher ); + signal( SIGINT, SignalCatcher ); + +#ifndef WIN32 + // disable SIGPIPE since some systems like OS X don't define MSG_NOSIGNAL + + signal( SIGPIPE, SIG_IGN ); +#endif + +#ifdef WIN32 + // increase process priority + + CONSOLE_Print( "[GHOST] setting process priority to \"above normal\"" ); + SetPriorityClass( GetCurrentProcess( ), ABOVE_NORMAL_PRIORITY_CLASS ); +#endif + + // initialize ghost + + gGHost = new CGHost( &CFG, gCFGFile ); + + QObject::connect(gGHost, SIGNAL(destroyed()), &a, SLOT(deleteLater())); + + return a.exec(); +} diff --git a/ghost configurator/ReadMe.txt b/src/ghost configurator/ReadMe.txt similarity index 100% rename from ghost configurator/ReadMe.txt rename to src/ghost configurator/ReadMe.txt diff --git a/ghost configurator/ghost configurator.sln b/src/ghost configurator/ghost configurator.sln similarity index 100% rename from ghost configurator/ghost configurator.sln rename to src/ghost configurator/ghost configurator.sln diff --git a/ghost configurator/ghost configurator/Form1.Designer.vb b/src/ghost configurator/ghost configurator/Form1.Designer.vb similarity index 100% rename from ghost configurator/ghost configurator/Form1.Designer.vb rename to src/ghost configurator/ghost configurator/Form1.Designer.vb diff --git a/ghost configurator/ghost configurator/Form1.resx b/src/ghost configurator/ghost configurator/Form1.resx similarity index 100% rename from ghost configurator/ghost configurator/Form1.resx rename to src/ghost configurator/ghost configurator/Form1.resx diff --git a/ghost configurator/ghost configurator/Form1.vb b/src/ghost configurator/ghost configurator/Form1.vb similarity index 100% rename from ghost configurator/ghost configurator/Form1.vb rename to src/ghost configurator/ghost configurator/Form1.vb diff --git a/ghost configurator/ghost configurator/My Project/Application.Designer.vb b/src/ghost configurator/ghost configurator/My Project/Application.Designer.vb similarity index 100% rename from ghost configurator/ghost configurator/My Project/Application.Designer.vb rename to src/ghost configurator/ghost configurator/My Project/Application.Designer.vb diff --git a/ghost configurator/ghost configurator/My Project/Application.myapp b/src/ghost configurator/ghost configurator/My Project/Application.myapp similarity index 100% rename from ghost configurator/ghost configurator/My Project/Application.myapp rename to src/ghost configurator/ghost configurator/My Project/Application.myapp diff --git a/ghost configurator/ghost configurator/My Project/AssemblyInfo.vb b/src/ghost configurator/ghost configurator/My Project/AssemblyInfo.vb similarity index 100% rename from ghost configurator/ghost configurator/My Project/AssemblyInfo.vb rename to src/ghost configurator/ghost configurator/My Project/AssemblyInfo.vb diff --git a/ghost configurator/ghost configurator/My Project/Resources.Designer.vb b/src/ghost configurator/ghost configurator/My Project/Resources.Designer.vb similarity index 100% rename from ghost configurator/ghost configurator/My Project/Resources.Designer.vb rename to src/ghost configurator/ghost configurator/My Project/Resources.Designer.vb diff --git a/ghost configurator/ghost configurator/My Project/Resources.resx b/src/ghost configurator/ghost configurator/My Project/Resources.resx similarity index 100% rename from ghost configurator/ghost configurator/My Project/Resources.resx rename to src/ghost configurator/ghost configurator/My Project/Resources.resx diff --git a/ghost configurator/ghost configurator/My Project/Settings.Designer.vb b/src/ghost configurator/ghost configurator/My Project/Settings.Designer.vb similarity index 100% rename from ghost configurator/ghost configurator/My Project/Settings.Designer.vb rename to src/ghost configurator/ghost configurator/My Project/Settings.Designer.vb diff --git a/ghost configurator/ghost configurator/My Project/Settings.settings b/src/ghost configurator/ghost configurator/My Project/Settings.settings similarity index 100% rename from ghost configurator/ghost configurator/My Project/Settings.settings rename to src/ghost configurator/ghost configurator/My Project/Settings.settings diff --git a/ghost configurator/ghost configurator/My Project/app.manifest b/src/ghost configurator/ghost configurator/My Project/app.manifest similarity index 100% rename from ghost configurator/ghost configurator/My Project/app.manifest rename to src/ghost configurator/ghost configurator/My Project/app.manifest diff --git a/ghost configurator/ghost configurator/Resources/parametres 3D.ico b/src/ghost configurator/ghost configurator/Resources/parametres 3D.ico similarity index 100% rename from ghost configurator/ghost configurator/Resources/parametres 3D.ico rename to src/ghost configurator/ghost configurator/Resources/parametres 3D.ico diff --git a/ghost configurator/ghost configurator/bin/Debug/ghost.cfg b/src/ghost configurator/ghost configurator/bin/Debug/ghost.cfg similarity index 100% rename from ghost configurator/ghost configurator/bin/Debug/ghost.cfg rename to src/ghost configurator/ghost configurator/bin/Debug/ghost.cfg diff --git a/ghost configurator/ghost configurator/ghost configurator.vbproj b/src/ghost configurator/ghost configurator/ghost configurator.vbproj similarity index 100% rename from ghost configurator/ghost configurator/ghost configurator.vbproj rename to src/ghost configurator/ghost configurator/ghost configurator.vbproj diff --git a/ghost configurator/ghost configurator/ghost configurator.vbproj.user b/src/ghost configurator/ghost configurator/ghost configurator.vbproj.user similarity index 100% rename from ghost configurator/ghost configurator/ghost configurator.vbproj.user rename to src/ghost configurator/ghost configurator/ghost configurator.vbproj.user diff --git a/src/lib.pri b/src/lib.pri new file mode 100644 index 0000000..cb0f962 --- /dev/null +++ b/src/lib.pri @@ -0,0 +1,7 @@ +CONFIG += staticlib create_prl +macx { + CONFIG += x86_64 x86 + QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.5.sdk +} +DESTDIR = ../../lib +TEMPLATE = lib diff --git a/ghost/StormLibRAS.lib b/src/libghost/StormLibRAS.lib similarity index 100% rename from ghost/StormLibRAS.lib rename to src/libghost/StormLibRAS.lib diff --git a/src/libghost/bncsutilinterface.cpp b/src/libghost/bncsutilinterface.cpp new file mode 100644 index 0000000..6a91cec --- /dev/null +++ b/src/libghost/bncsutilinterface.cpp @@ -0,0 +1,165 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "bncsutilinterface.h" + +#undef WIN32 + +#include +#include + +// +// CBNCSUtilInterface +// + +CBNCSUtilInterface :: CBNCSUtilInterface( QString userName, QString userPassword ) +{ + // m_nls = (void *)nls_init( userName.c_str( ), userPassword.c_str( ) ); + m_NLS = new NLS( userName.toStdString(), userPassword.toStdString() ); +} + +CBNCSUtilInterface :: ~CBNCSUtilInterface( ) +{ + // nls_free( (nls_t *)m_nls ); + delete (NLS *)m_NLS; +} + +void CBNCSUtilInterface :: Reset( QString userName, QString userPassword ) +{ + // nls_free( (nls_t *)m_nls ); + // m_nls = (void *)nls_init( userName.c_str( ), userPassword.c_str( ) ); + delete (NLS *)m_NLS; + m_NLS = new NLS( userName.toStdString(), userPassword.toStdString() ); +} + +bool CBNCSUtilInterface :: HELP_SID_AUTH_CHECK( bool TFT, const QByteArray& war3Path, const QByteArray & keyROC, + const QByteArray & keyTFT, const QByteArray & valueStringFormula, const QByteArray & mpqFileName, + const QByteArray & clientToken, const QByteArray & serverToken ) +{ + // set m_EXEVersion, m_EXEVersionHash, m_EXEInfo, m_InfoROC, m_InfoTFT + + QByteArray FileWar3EXE = war3Path + "war3.exe"; + QByteArray FileStormDLL = war3Path + "Storm.dll"; + + if( !QFile::exists( FileStormDLL ) ) + FileStormDLL = war3Path + "storm.dll"; + + QByteArray FileGameDLL = war3Path + "game.dll"; + bool ExistsWar3EXE = QFile::exists( FileWar3EXE ); + bool ExistsStormDLL = QFile::exists( FileStormDLL ); + bool ExistsGameDLL = QFile::exists( FileGameDLL ); + + if( ExistsWar3EXE && ExistsStormDLL && ExistsGameDLL ) + { + // todotodo: check getExeInfo return value to ensure 1024 bytes was enough + char buf[1024]; + quint32 EXEVersion; + getExeInfo( FileWar3EXE.data( ), (char *)&buf, 1024, (quint32 *)&EXEVersion, BNCSUTIL_PLATFORM_X86 ); + m_EXEInfo = buf; + m_EXEVersion = Util::fromUInt32( EXEVersion); + quint32 EXEVersionHash; + checkRevisionFlat( valueStringFormula.data( ), FileWar3EXE.data( ), FileStormDLL.data( ), FileGameDLL.data( ), extractMPQNumber( mpqFileName.data( ) ), (unsigned long *)&EXEVersionHash ); + m_EXEVersionHash = Util::fromUInt32( EXEVersionHash); + m_KeyInfoROC = CreateKeyInfo( keyROC, Util::extractUInt32(clientToken), Util::extractUInt32(serverToken) ); + + if( TFT ) + m_KeyInfoTFT = CreateKeyInfo( keyTFT, Util::extractUInt32(clientToken), Util::extractUInt32(serverToken) ); + + if( m_KeyInfoROC.size( ) == 36 && ( !TFT || m_KeyInfoTFT.size( ) == 36 ) ) + return true; + else + { + if( m_KeyInfoROC.size( ) != 36 ) + CONSOLE_Print( "[BNCSUI] unable to create ROC key info - invalid ROC key" ); + + if( TFT && m_KeyInfoTFT.size( ) != 36 ) + CONSOLE_Print( "[BNCSUI] unable to create TFT key info - invalid TFT key" ); + } + } + else + { + if( !ExistsWar3EXE ) + CONSOLE_Print( "[BNCSUI] unable to open [" + FileWar3EXE + "]" ); + + if( !ExistsStormDLL ) + CONSOLE_Print( "[BNCSUI] unable to open [" + FileStormDLL + "]" ); + + if( !ExistsGameDLL ) + CONSOLE_Print( "[BNCSUI] unable to open [" + FileGameDLL + "]" ); + } + + return false; +} + +bool CBNCSUtilInterface :: HELP_SID_AUTH_ACCOUNTLOGON( ) +{ + // set m_ClientKey + + char buf[32]; + // nls_get_A( (nls_t *)m_nls, buf ); + ( (NLS *)m_NLS )->getPublicKey( buf ); + m_ClientKey = QByteArray( (char *)buf, 32 ); + return true; +} + +bool CBNCSUtilInterface :: HELP_SID_AUTH_ACCOUNTLOGONPROOF( const QByteArray & salt, const QByteArray & serverKey ) +{ + // set m_M1 + + char buf[20]; + // nls_get_M1( (nls_t *)m_nls, buf, QString( serverKey.begin( ), serverKey.end( ) ).data( ), QString( salt.begin( ), salt.end( ) ).data( ) ); + ( (NLS *)m_NLS )->getClientSessionKey( buf, salt.data(), serverKey.data() ); + m_M1 = QByteArray( (char *)buf, 20 ); + return true; +} + +bool CBNCSUtilInterface :: HELP_PvPGNPasswordHash( const QByteArray &userPassword ) +{ + // set m_PvPGNPasswordHash + + char buf[20]; + hashPassword( userPassword.data( ), buf ); + m_PvPGNPasswordHash = QByteArray( (char *)buf, 20 ); + return true; +} + +QByteArray CBNCSUtilInterface :: CreateKeyInfo( const QByteArray & key, quint32 clientToken, quint32 serverToken ) +{ + unsigned char Zeros[] = { 0, 0, 0, 0 }; + QByteArray KeyInfo; + CDKeyDecoder Decoder( key.data(), key.size( ) ); + + if( Decoder.isKeyValid( ) ) + { + KeyInfo.append(Util::fromUInt32( key.size( ))); + KeyInfo.append(Util::fromUInt32( Decoder.getProduct( ))); + KeyInfo.append(Util::fromUInt32( Decoder.getVal1( ))); + KeyInfo.append(QByteArray( (char*)Zeros, 4 ) ); + size_t Length = Decoder.calculateHash( clientToken, serverToken ); + char *buf = new char[Length]; + Length = Decoder.getHash( buf ); + KeyInfo.append(QByteArray( buf, Length ) ); + delete [] buf; + } + + return KeyInfo; +} diff --git a/src/libghost/bncsutilinterface.h b/src/libghost/bncsutilinterface.h new file mode 100644 index 0000000..fe72cbb --- /dev/null +++ b/src/libghost/bncsutilinterface.h @@ -0,0 +1,70 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef BNCSUTIL_INTERFACE_H +#define BNCSUTIL_INTERFACE_H + +// +// CBNCSUtilInterface +// +#include "includes.h" + +class CBNCSUtilInterface +{ +private: + void *m_NLS; + QByteArray m_EXEVersion; // set in HELP_SID_AUTH_CHECK + QByteArray m_EXEVersionHash; // set in HELP_SID_AUTH_CHECK + QString m_EXEInfo; // set in HELP_SID_AUTH_CHECK + QByteArray m_KeyInfoROC; // set in HELP_SID_AUTH_CHECK + QByteArray m_KeyInfoTFT; // set in HELP_SID_AUTH_CHECK + QByteArray m_ClientKey; // set in HELP_SID_AUTH_ACCOUNTLOGON + QByteArray m_M1; // set in HELP_SID_AUTH_ACCOUNTLOGONPROOF + QByteArray m_PvPGNPasswordHash; // set in HELP_PvPGNPasswordHash + +public: + CBNCSUtilInterface( QString userName, QString userPassword ); + ~CBNCSUtilInterface( ); + + QByteArray GetEXEVersion( ) { return m_EXEVersion; } + QByteArray GetEXEVersionHash( ) { return m_EXEVersionHash; } + QString GetEXEInfo( ) { return m_EXEInfo; } + QByteArray GetKeyInfoROC( ) { return m_KeyInfoROC; } + QByteArray GetKeyInfoTFT( ) { return m_KeyInfoTFT; } + QByteArray GetClientKey( ) { return m_ClientKey; } + QByteArray GetM1( ) { return m_M1; } + QByteArray GetPvPGNPasswordHash( ) { return m_PvPGNPasswordHash; } + + void SetEXEVersion( QByteArray &nEXEVersion ) { m_EXEVersion = nEXEVersion; } + void SetEXEVersionHash( QByteArray &nEXEVersionHash ) { m_EXEVersionHash = nEXEVersionHash; } + + void Reset( QString userName, QString userPassword ); + + bool HELP_SID_AUTH_CHECK( bool TFT, const QByteArray & war3Path, const QByteArray & keyROC, const QByteArray & keyTFT, + const QByteArray & valueStringFormula, const QByteArray & mpqFileName, const QByteArray & clientToken, const QByteArray & serverToken ); + bool HELP_SID_AUTH_ACCOUNTLOGON( ); + bool HELP_SID_AUTH_ACCOUNTLOGONPROOF( const QByteArray & salt, const QByteArray & serverKey ); + bool HELP_PvPGNPasswordHash( const QByteArray & userPassword ); + +private: + QByteArray CreateKeyInfo( const QByteArray & key, quint32 clientToken, quint32 serverToken ); +}; + +#endif diff --git a/src/libghost/bnet.cpp b/src/libghost/bnet.cpp new file mode 100644 index 0000000..d9e1693 --- /dev/null +++ b/src/libghost/bnet.cpp @@ -0,0 +1,2535 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "config.h" +#include "language.h" +#include "commandpacket.h" +#include "ghostdb.h" +#include "bncsutilinterface.h" +#include "bnlsclient.h" +#include "bnetprotocol.h" +#include "bnet.h" +#include "map.h" +#include "packed.h" +#include "savegame.h" +#include "replay.h" +#include "gameprotocol.h" +#include "game.h" +#include "includes.h" + +#include +#include +#include +#include + +// +// CBNET +// + +CBNET :: CBNET( CGHost *nGHost, const QString &nServer, const QString &nServerAlias, const QString &nBNLSServer, quint16 nBNLSPort, quint32 nBNLSWardenCookie, + const QString &nCDKeyROC, const QString &nCDKeyTFT, const QString &nCountryAbbrev, const QString &nCountry, quint32 nLocaleID, const QString &nUserName, const QString &nUserPassword, + const QString &nFirstChannel, const QString &nRootAdmin, char nCommandTrigger, bool nHoldFriends, bool nHoldClan, bool nPublicCommands, + unsigned char nWar3Version, const QByteArray &nEXEVersion, const QByteArray &nEXEVersionHash, const QString &nPasswordHashType, const QString &nPVPGNRealmName, + quint32 nMaxMessageLength, quint32 nHostCounterID ) + : QObject(NULL) +{ + // todotodo: append path seperator to Warcraft3Path if needed + m_Retries = 0; + m_GHost = nGHost; + m_Socket = NULL; + ResetSocket( ); + + m_SendWindowLength = 10000; + m_SendNoWaitMaxCount = 2; + m_ConnectionTimeout = 10000; + m_ReconnectInterval = 90000; + + m_CallableUpdateTimer.setInterval(200); + m_CallableUpdateTimer.start(); + m_AdminListUpdateTimer.setInterval(60000); + m_AdminListUpdateTimer.start(); + m_BanListRefreshTimer.setInterval(3600000); + m_BanListRefreshTimer.start(); + m_KeepAliveTimer.setInterval(60000); + QObject::connect(&m_KeepAliveTimer, SIGNAL(timeout()), this, SLOT(sendKeepAlivePacket())); + + QObject::connect(&m_CallableUpdateTimer, SIGNAL(timeout()), this, SLOT(EventCallableUpdateTimeout())); + QObject::connect(&m_AdminListUpdateTimer, SIGNAL(timeout()), this, SLOT(EventUpdateAdminList())); + QObject::connect(&m_BanListRefreshTimer, SIGNAL(timeout()), this, SLOT(EventRefreshBanList())); + + m_Protocol = new CBNETProtocol( ); + m_BNLSClient = NULL; + m_BNCSUtil = new CBNCSUtilInterface( nUserName, nUserPassword ); + m_CallableAdminList = m_GHost->m_DB->ThreadedAdminList( nServer ); + m_CallableBanList = m_GHost->m_DB->ThreadedBanList( nServer ); + m_Server = nServer; + QString LowerServer = m_Server; + LowerServer = LowerServer.toLower(); + + if( !nServerAlias.isEmpty( ) ) + m_ServerAlias = nServerAlias; + else if( LowerServer == "useast.battle.net" ) + m_ServerAlias = "USEast"; + else if( LowerServer == "uswest.battle.net" ) + m_ServerAlias = "USWest"; + else if( LowerServer == "asia.battle.net" ) + m_ServerAlias = "Asia"; + else if( LowerServer == "europe.battle.net" ) + m_ServerAlias = "Europe"; + else + m_ServerAlias = m_Server; + + if( nPasswordHashType == "pvpgn" && !nBNLSServer.isEmpty( ) ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] pvpgn connection found with a configured BNLS server, ignoring BNLS server" ); + nBNLSPort = 0; + nBNLSWardenCookie = 0; + } + else + m_BNLSServer = nBNLSServer; + + m_BNLSPort = nBNLSPort; + m_BNLSWardenCookie = nBNLSWardenCookie; + m_CDKeyROC = nCDKeyROC.toAscii(); + m_CDKeyTFT = nCDKeyTFT.toAscii(); + + // remove dashes from CD keys and convert to uppercase + + m_CDKeyROC = m_CDKeyROC.replace('-', "").toLower(); + m_CDKeyTFT = m_CDKeyTFT.replace('-', "").toLower(); + + if( m_CDKeyROC.size( ) != 26 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - your ROC CD key is not 26 characters long and is probably invalid" ); + + if( m_GHost->m_TFT && m_CDKeyTFT.size( ) != 26 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - your TFT CD key is not 26 characters long and is probably invalid" ); + + m_CountryAbbrev = nCountryAbbrev; + m_Country = nCountry; + m_LocaleID = nLocaleID; + m_UserName = nUserName; + m_UserPassword = nUserPassword; + m_FirstChannel = nFirstChannel; + m_RootAdmin = nRootAdmin; + m_RootAdmins = nRootAdmin.split( QRegExp("\\s+") ); + m_RootAdmin = m_RootAdmin.toLower(); + m_CommandTrigger = nCommandTrigger; + m_War3Version = nWar3Version; + m_EXEVersion = nEXEVersion; + m_EXEVersionHash = nEXEVersionHash; + m_PasswordHashType = nPasswordHashType; + m_PVPGNRealmName = nPVPGNRealmName; + m_MaxMessageLength = nMaxMessageLength; + m_HostCounterID = nHostCounterID; + m_LastDisconnectedTime = 0; + m_LastConnectionAttemptTime = 0; + m_LastOutPacketSize = 0; + m_LastAdminRefreshTime = GetTime( ); + m_LastBanRefreshTime = GetTime( ); + m_LoggedIn = false; + m_InChat = false; + m_HoldFriends = nHoldFriends; + m_HoldClan = nHoldClan; + m_PublicCommands = nPublicCommands; +} + +CBNET :: ~CBNET( ) +{ + delete m_Socket; + delete m_Protocol; + delete m_BNLSClient; + + while( !m_Packets.isEmpty( ) ) + { + delete m_Packets.front( ); + m_Packets.dequeue( ); + } + + delete m_BNCSUtil; + + for( QList :: const_iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) + delete *i; + + for( QList :: const_iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) + delete *i; + + for( QList :: const_iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + if( m_CallableAdminList ) + m_GHost->m_Callables.push_back( m_CallableAdminList ); + + if( m_CallableBanList ) + m_GHost->m_Callables.push_back( m_CallableBanList ); + + for( QList :: const_iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) + delete *i; +} + +void CBNET :: ResetSocket( ) +{ + if (m_Socket) + { + m_Socket->abort(); + m_Socket->deleteLater(); + } + m_Socket = new QTcpSocket( ); + + QObject::connect(m_Socket, SIGNAL(connected()), this, SLOT(socketConnected())); + QObject::connect(m_Socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + QObject::connect(m_Socket, SIGNAL(readyRead()), this, SLOT(socketDataReady())); + QObject::connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError())); +} + +void CBNET::socketConnectTimeoutCheck() +{ + if( m_Socket->state() == QAbstractSocket::ConnectedState) + return; + CONSOLE_Print("[BNET: " + m_ServerAlias + "] connection attempt to [" + m_Server + "] on port 6112 timed out"); + socketDisconnected(); +} + +void CBNET::socketConnect() +{ + if( m_Socket->state() != QAbstractSocket::UnconnectedState) + return; + // attempt to connect to battle.net + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connecting to server [" + m_Server + "] on port 6112" ); + m_GHost->EventBNETConnecting( this ); + // connecting is not blocking anymore when using Qt sockets + m_Socket->connectToHost( m_Server, 6112 ); + QTimer::singleShot(m_ConnectionTimeout, this, SLOT(socketConnectTimeoutCheck())); + +// if( m_ServerIP.isEmpty( ) ) +// m_Socket->connectToHost( m_Server, 6112 ); +// else +// { +// // use cached server IP address since resolving takes time and is blocking +// +// CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using cached server IP address " + m_ServerIP ); +// m_Socket->connectToHost( m_ServerIP, 6112 ); +// } +// +// if (m_Socket->waitForConnected(15000)) +// { +// m_ServerIP = m_Socket->peerAddress().toString(); +// CONSOLE_Print( "[BNET: " + m_ServerAlias + "] resolved and cached server IP address " + m_ServerIP ); +// } +// +// else +// { +// // the connection attempt timed out (15 seconds) +// +// CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connect timed out" ); +// CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting 90 seconds to reconnect" ); +// m_GHost->EventBNETConnectTimedOut( this ); +// m_Socket->abort(); +// m_Socket->reset(); +// m_Socket->deleteLater(); +// m_Socket = NULL; +// m_LastDisconnectedTime = GetTime( ); +// QTimer::singleShot(90000, this, SLOT(socketConnect())); +// m_NULLTimer.stop(); +// } + + m_LastConnectionAttemptTime = GetTime( ); + m_Retries++; +} + +void CBNET::sendKeepAlivePacket() +{ + if( m_Socket->isOpen() ) + m_Socket->write( m_Protocol->SEND_SID_NULL( ) ); +} + +void CBNET::socketConnected() +{ + // the connection attempt completed + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] connected" ); + m_GHost->EventBNETConnected( this ); + m_Socket->write( m_Protocol->SEND_PROTOCOL_INITIALIZE_SELECTOR( ) ); + m_Socket->write( m_Protocol->SEND_SID_AUTH_INFO( m_War3Version, m_GHost->m_TFT, m_LocaleID, m_CountryAbbrev, m_Country ) ); + m_KeepAliveTimer.start(); + + while( !m_OutPackets.isEmpty( ) ) + m_OutPackets.dequeue( ); + + QTimer::singleShot(500, m_GHost, SLOT(EventAutoHost())); +} + +void CBNET::socketDisconnected() +{ + // the socket was disconnected + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] disconnected from battle.net" ); + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting " + QString::number(m_ReconnectInterval/1000) + " seconds to reconnect" ); + m_GHost->EventBNETDisconnected( this ); + delete m_BNLSClient; + m_BNLSClient = NULL; + m_BNCSUtil->Reset( m_UserName, m_UserPassword ); + m_Socket->abort(); + //m_Socket->deleteLater(); + //m_Socket = NULL; + m_LastDisconnectedTime = GetTime( ); + m_LoggedIn = false; + m_InChat = false; + m_KeepAliveTimer.stop(); + + if (m_Retries > 6) + { + CONSOLE_Print("[BNET: " + m_ServerAlias + "] giving up after 5 failed retries, waiting for 10 minutes to reconnect" ); + QTimer::singleShot(600000, this, SLOT(socketConnect())); + m_Retries = 0; + return; + } + //ResetSocket( ); + QTimer::singleShot(m_ReconnectInterval, this, SLOT(socketConnect())); +} + +void CBNET::sendWardenResponse(const QByteArray & response) +{ + if (m_Socket->state() != QAbstractSocket::ConnectedState) + return; + + m_Socket->write( m_Protocol->SEND_SID_WARDEN( response ) ); +} + +void CBNET::socketDataReady() +{ + // the socket is connected and everything appears to be working properly + + ExtractPackets( ); + ProcessPackets( ); +} + +void CBNET::EnqueuePacket(const QByteArray &pkg) +{ +// int ticks = getWaitTicks(); +// int pkgs = m_OutPackets.size(); + + m_OutPackets.enqueue(pkg); + SendPacket( ); + +// if (pkgs > 0) +// return; +// +// if (m_LastPacketSent.elapsed() >= ticks) +// { +// SendPacket(); +// return; +// } +// +// QTimer::singleShot(ticks - m_LastPacketSent.elapsed(), this, SLOT(SendPacket())); +} + +quint32 CBNET :: CalculateSendWaitTime(const QQueue &queue, const QList &messageLog) const +{ + if(messageLog.count() <= m_SendNoWaitMaxCount) + return 0; + // TODO: implement something clever, for now just wait 500ms for every packet previously sent + return 1000 * messageLog.count(); +} + +void CBNET::SendPacket() +{ + if( m_OutPackets.empty( ) ) + { + DEBUG_Print("Nice, empty query... but actually, this shouldn't happen..."); + return; + } + + if( m_OutPackets.size( ) > 7 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] packet queue warning - there are " + QString::number( m_OutPackets.size( ) ) + " packets waiting to be sent" ); + + QTime now = QTime::currentTime(); + while( !m_SentPackages.empty() && m_SentPackages.front().first.msecsTo(now) > m_SendWindowLength ) + m_SentPackages.pop_front(); + + quint32 waitTime = CalculateSendWaitTime(m_OutPackets, m_SentPackages); + if(waitTime > 0) + { + // TODO: this should probably not use a singleShot-timer, we might fire multiple times + QTimer::singleShot(waitTime, this, SLOT(SendPacket())); + return; + } + const QByteArray &data = m_OutPackets.front(); + m_Socket->write( data ); + m_LastOutPacketSize = m_OutPackets.front( ).size( ); + + m_SentPackages.append( TimeAndSizePair(QTime::currentTime(), data.size()) ); + + m_OutPackets.dequeue( ); + m_LastPacketSent.restart(); + + // there are still packets left, resend + if( !m_OutPackets.empty() ) + SendPacket( ); + +// if (m_OutPackets.size() > 0) +// QTimer::singleShot(getWaitTicks(), this, SLOT(SendPacket())); +} + +void CBNET::socketError() +{ + // the socket has an error + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] disconnected from battle.net due to socket error: " + m_Socket->errorString() ); + + if( m_Socket->error() == QAbstractSocket::RemoteHostClosedError && GetTime( ) - m_LastConnectionAttemptTime <= 15 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - you are probably temporarily IP banned from battle.net" ); + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] waiting 90 seconds to reconnect" ); + m_GHost->EventBNETDisconnected( this ); + delete m_BNLSClient; + m_BNLSClient = NULL; + m_BNCSUtil->Reset( m_UserName, m_UserPassword ); + m_Socket->abort(); + //m_Socket->deleteLater(); + //m_Socket = NULL; + m_LastDisconnectedTime = GetTime( ); + m_LoggedIn = false; + m_InChat = false; + m_KeepAliveTimer.stop(); + + QTimer::singleShot(90000, this, SLOT(socketConnect())); +} + +const QByteArray &CBNET :: GetUniqueName( ) const +{ + return m_Protocol->GetUniqueName( ); +} + +void CBNET::EventCallableUpdateTimeout() +{ + + // + // update callables + // + + for( QList :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); ) + { + if( i->second->GetReady( ) ) + { + quint32 Count = i->second->GetResult( ); + + if( Count == 0 ) + QueueChatCommand( m_GHost->GetLanguage( )->ThereAreNoAdmins( m_Server ), i->first, !i->first.isEmpty( ) ); + else if( Count == 1 ) + QueueChatCommand( m_GHost->GetLanguage( )->ThereIsAdmin( m_Server ), i->first, !i->first.isEmpty( ) ); + else + QueueChatCommand( m_GHost->GetLanguage( )->ThereAreAdmins( m_Server, QString::number( Count ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminCounts.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + AddAdmin( i->second->GetUser( ) ); + QueueChatCommand( m_GHost->GetLanguage( )->AddedUserToAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->ErrorAddingUserToAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminAdds.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + RemoveAdmin( i->second->GetUser( ) ); + QueueChatCommand( m_GHost->GetLanguage( )->DeletedUserFromAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->ErrorDeletingUserFromAdminDatabase( m_Server, i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminRemoves.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); ) + { + if( i->second->GetReady( ) ) + { + quint32 Count = i->second->GetResult( ); + + if( Count == 0 ) + QueueChatCommand( m_GHost->GetLanguage( )->ThereAreNoBannedUsers( m_Server ), i->first, !i->first.isEmpty( ) ); + else if( Count == 1 ) + QueueChatCommand( m_GHost->GetLanguage( )->ThereIsBannedUser( m_Server ), i->first, !i->first.isEmpty( ) ); + else + QueueChatCommand( m_GHost->GetLanguage( )->ThereAreBannedUsers( m_Server, QString::number( Count ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanCounts.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + AddBan( i->second->GetUser( ), i->second->GetIP( ), i->second->GetGameName( ), i->second->GetAdmin( ), i->second->GetReason( ) ); + QueueChatCommand( m_GHost->GetLanguage( )->BannedUser( i->second->GetServer( ), i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->ErrorBanningUser( i->second->GetServer( ), i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanAdds.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + RemoveBan( i->second->GetUser( ) ); + QueueChatCommand( m_GHost->GetLanguage( )->UnbannedUser( i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->ErrorUnbanningUser( i->second->GetUser( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanRemoves.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); ) + { + if( i->second->GetReady( ) ) + { + CDBGamePlayerSummary *GamePlayerSummary = i->second->GetResult( ); + + if( GamePlayerSummary ) + QueueChatCommand( m_GHost->GetLanguage( )->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), QString::number( GamePlayerSummary->GetTotalGames( ) ), QString::number( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 'g', 2 ), QString::number( GamePlayerSummary->GetAvgLeftPercent( ) ) ), i->first, !i->first.isEmpty( ) ); + else + QueueChatCommand( m_GHost->GetLanguage( )->HasntPlayedGamesWithThisBot( i->second->GetName( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedGPSChecks.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); ) + { + if( i->second->GetReady( ) ) + { + CDBDotAPlayerSummary *DotAPlayerSummary = i->second->GetResult( ); + + if( DotAPlayerSummary ) + { + QString Summary = m_GHost->GetLanguage( )->HasPlayedDotAGamesWithThisBot( i->second->GetName( ), + QString::number( DotAPlayerSummary->GetTotalGames( ) ), + QString::number( DotAPlayerSummary->GetTotalWins( ) ), + QString::number( DotAPlayerSummary->GetTotalLosses( ) ), + QString::number( DotAPlayerSummary->GetTotalKills( ) ), + QString::number( DotAPlayerSummary->GetTotalDeaths( ) ), + QString::number( DotAPlayerSummary->GetTotalCreepKills( ) ), + QString::number( DotAPlayerSummary->GetTotalCreepDenies( ) ), + QString::number( DotAPlayerSummary->GetTotalAssists( ) ), + QString::number( DotAPlayerSummary->GetTotalNeutralKills( ) ), + QString::number( DotAPlayerSummary->GetTotalTowerKills( ) ), + QString::number( DotAPlayerSummary->GetTotalRaxKills( ) ), + QString::number( DotAPlayerSummary->GetTotalCourierKills( ) ), + QString::number( DotAPlayerSummary->GetAvgKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgDeaths( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCreepKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCreepDenies( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgAssists( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgNeutralKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgTowerKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgRaxKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCourierKills( ), 'g', 2 ) ); + + QueueChatCommand( Summary, i->first, !i->first.isEmpty( ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ), i->first, !i->first.isEmpty( ) ); + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedDPSChecks.erase( i ); + } + else + i++; + } + + if( m_CallableAdminList && m_CallableAdminList->GetReady( ) ) + { + // CONSOLE_Print( "[BNET: " + m_ServerAlias + "] refreshed admin list (" + QString::number( m_Admins.size( ) ) + " -> " + QString::number( m_CallableAdminList->GetResult( ).size( ) ) + " admins)" ); + m_Admins = m_CallableAdminList->GetResult( ); + m_GHost->m_DB->RecoverCallable( m_CallableAdminList ); + delete m_CallableAdminList; + m_CallableAdminList = NULL; + m_LastAdminRefreshTime = GetTime( ); + } + + if( m_CallableBanList && m_CallableBanList->GetReady( ) ) + { + // CONSOLE_Print( "[BNET: " + m_ServerAlias + "] refreshed ban list (" + QString::number( m_Bans.size( ) ) + " -> " + QString::number( m_CallableBanList->GetResult( ).size( ) ) + " bans)" ); + + for( QList :: const_iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) + delete *i; + + m_Bans = m_CallableBanList->GetResult( ); + m_GHost->m_DB->RecoverCallable( m_CallableBanList ); + delete m_CallableBanList; + m_CallableBanList = NULL; + m_LastBanRefreshTime = GetTime( ); + } +} + +void CBNET::EventUpdateAdminList() +{ + // refresh the admin list every 5 minutes + + if( !m_CallableAdminList ) + m_CallableAdminList = m_GHost->m_DB->ThreadedAdminList( m_Server ); +} + +void CBNET::EventRefreshBanList() +{ + // refresh the ban list every 60 minutes + + if( !m_CallableBanList ) + m_CallableBanList = m_GHost->m_DB->ThreadedBanList( m_Server ); +} + +void CBNET :: ExtractPackets( ) +{ + // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes + + while( m_Socket->bytesAvailable() >= 4 ) + { + // byte 0 is always 255 + QByteArray header = m_Socket->peek(4); + + if( (unsigned char)header.at(0) != BNET_HEADER_CONSTANT ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error - received invalid packet from battle.net (bad header constant), disconnecting" ); + m_Socket->abort(); + return; + } + + // bytes 2 and 3 contain the length of the packet + + quint16 Length = Util::extractUInt16(header, 2); + + if( Length < 4 ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error - received invalid packet from battle.net (bad length), disconnecting" ); + m_Socket->abort(); + return; + } + + if( m_Socket->bytesAvailable() < Length ) + return; + + QByteArray Bytes = m_Socket->read(Length); + m_Packets.enqueue( new CCommandPacket( BNET_HEADER_CONSTANT, Bytes.at(1), Bytes ) ); + } +} + +void CBNET :: ProcessPackets( ) +{ + CIncomingGameHost *GameHost = NULL; + CIncomingChatEvent *ChatEvent = NULL; + QByteArray WardenData; + QList Friends; + QList Clans; + + // process all the received packets in the m_Packets queue + // this normally means sending some kind of response + + while( !m_Packets.isEmpty( ) ) + { + CCommandPacket *Packet = m_Packets.front( ); + m_Packets.dequeue( ); + + if( Packet->GetPacketType( ) == BNET_HEADER_CONSTANT ) + { + switch( Packet->GetID( ) ) + { + case CBNETProtocol :: SID_NULL: + // warning: we do not respond to NULL packets with a NULL packet of our own + // this is because PVPGN servers are programmed to respond to NULL packets so it will create a vicious cycle of useless traffic + // official battle.net servers do not respond to NULL packets + + m_Protocol->RECEIVE_SID_NULL( Packet->GetData( ) ); + break; + + case CBNETProtocol :: SID_GETADVLISTEX: + GameHost = m_Protocol->RECEIVE_SID_GETADVLISTEX( Packet->GetData( ) ); + + if( GameHost ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joining game [" + GameHost->GetGameName( ) + "]" ); + + delete GameHost; + GameHost = NULL; + break; + + case CBNETProtocol :: SID_ENTERCHAT: + if( m_Protocol->RECEIVE_SID_ENTERCHAT( Packet->GetData( ) ) ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joining channel [" + m_FirstChannel + "]" ); + m_InChat = true; + m_Socket->write( m_Protocol->SEND_SID_JOINCHANNEL( m_FirstChannel ) ); + } + + break; + + case CBNETProtocol :: SID_CHATEVENT: + ChatEvent = m_Protocol->RECEIVE_SID_CHATEVENT( Packet->GetData( ) ); + + if( ChatEvent ) + ProcessChatEvent( ChatEvent ); + + delete ChatEvent; + ChatEvent = NULL; + break; + + case CBNETProtocol :: SID_CHECKAD: + m_Protocol->RECEIVE_SID_CHECKAD( Packet->GetData( ) ); + break; + + case CBNETProtocol :: SID_STARTADVEX3: + if( m_Protocol->RECEIVE_SID_STARTADVEX3( Packet->GetData( ) ) ) + { + m_InChat = false; + m_GHost->EventBNETGameRefreshed( this ); + } + else + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] startadvex3 failed" ); + m_GHost->EventBNETGameRefreshFailed( this ); + } + + break; + + case CBNETProtocol :: SID_PING: + m_Socket->write( m_Protocol->SEND_SID_PING( m_Protocol->RECEIVE_SID_PING( Packet->GetData( ) ) ) ); + break; + + case CBNETProtocol :: SID_AUTH_INFO: + if( m_Protocol->RECEIVE_SID_AUTH_INFO( Packet->GetData( ) ) ) + { + if( m_BNCSUtil->HELP_SID_AUTH_CHECK( m_GHost->m_TFT, m_GHost->m_Warcraft3Path, m_CDKeyROC, m_CDKeyTFT, + m_Protocol->GetValueStringFormulaString( ), m_Protocol->GetIX86VerFileNameString( ), + m_Protocol->GetClientToken( ), m_Protocol->GetServerToken( ) ) ) + { + // override the exe information generated by bncsutil if specified in the config file + // apparently this is useful for pvpgn users + + if( m_EXEVersion.size( ) == 4 ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using custom exe version bnet_custom_exeversion = " + QString::number( m_EXEVersion[0] ) + " " + QString::number( m_EXEVersion[1] ) + " " + QString::number( m_EXEVersion[2] ) + " " + QString::number( m_EXEVersion[3] ) ); + m_BNCSUtil->SetEXEVersion( m_EXEVersion ); + } + + if( m_EXEVersionHash.size( ) == 4 ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using custom exe version hash bnet_custom_exeversionhash = " + QString::number( m_EXEVersionHash[0] ) + " " + QString::number( m_EXEVersionHash[1] ) + " " + QString::number( m_EXEVersionHash[2] ) + " " + QString::number( m_EXEVersionHash[3] ) ); + m_BNCSUtil->SetEXEVersionHash( m_EXEVersionHash ); + } + + if( m_GHost->m_TFT ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: The Frozen Throne" ); + else + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: Reign of Chaos" ); + + m_Socket->write( m_Protocol->SEND_SID_AUTH_CHECK( m_GHost->m_TFT, m_Protocol->GetClientToken( ), m_BNCSUtil->GetEXEVersion( ), + m_BNCSUtil->GetEXEVersionHash( ), m_BNCSUtil->GetKeyInfoROC( ), m_BNCSUtil->GetKeyInfoTFT( ), + m_BNCSUtil->GetEXEInfo( ), "GHost" ) ); + + // the Warden seed is the first 4 bytes of the ROC key hash + // initialize the Warden handler + + if( !m_BNLSServer.isEmpty( ) ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] creating BNLS client" ); + delete m_BNLSClient; + m_BNLSClient = new CBNLSClient( m_BNLSServer, m_BNLSPort, m_BNLSWardenCookie ); + m_BNLSClient->QueueWardenSeed( Util::extractUInt32(m_BNCSUtil->GetKeyInfoROC( ), 16) ); + + QObject::connect(m_BNLSClient, SIGNAL(newWardenResponse(QByteArray)), this, SLOT(sendWardenResponse(QByteArray))); + } + } + else + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - bncsutil key hash failed (check your Warcraft 3 path and cd keys), disconnecting" ); + m_Socket->abort(); + delete Packet; + return; + } + } + + break; + + case CBNETProtocol :: SID_AUTH_CHECK: + if( m_Protocol->RECEIVE_SID_AUTH_CHECK( Packet->GetData( ) ) ) + { + // cd keys accepted + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] cd keys accepted" ); + m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGON( ); + m_Socket->write( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGON( m_BNCSUtil->GetClientKey( ), m_UserName ) ); + } + else + { + // cd keys not accepted + + switch( Util::extractUInt32(m_Protocol->GetKeyState( )) ) + { + case CBNETProtocol :: KR_ROC_KEY_IN_USE: + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - ROC CD key in use by user [" + m_Protocol->GetKeyStateDescription( ) + "], disconnecting" ); + break; + case CBNETProtocol :: KR_TFT_KEY_IN_USE: + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - TFT CD key in use by user [" + m_Protocol->GetKeyStateDescription( ) + "], disconnecting" ); + break; + case CBNETProtocol :: KR_OLD_GAME_VERSION: + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - game version is too old, disconnecting" ); + break; + case CBNETProtocol :: KR_INVALID_VERSION: + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - game version is invalid, disconnecting" ); + break; + default: + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - cd keys not accepted ("+QString::number(Util::extractUInt32(m_Protocol->GetKeyState( )))+"), disconnecting" ); + break; + } + + m_Socket->abort(); + delete Packet; + return; + } + + break; + + case CBNETProtocol :: SID_AUTH_ACCOUNTLOGON: + if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGON( Packet->GetData( ) ) ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] username [" + m_UserName + "] accepted" ); + + if( m_PasswordHashType == "pvpgn" ) + { + // pvpgn logon + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using pvpgn logon type (for pvpgn servers only)" ); + m_BNCSUtil->HELP_PvPGNPasswordHash( m_UserPassword.toAscii() ); + m_Socket->write( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetPvPGNPasswordHash( ) ) ); + } + else + { + // battle.net logon + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] using battle.net logon type (for official battle.net servers only)" ); + m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGONPROOF( m_Protocol->GetSalt( ), m_Protocol->GetServerPublicKey( ) ); + m_Socket->write( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetM1( ) ) ); + } + } + else + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - invalid username, disconnecting" ); + m_Socket->abort( ); + delete Packet; + return; + } + + break; + + case CBNETProtocol :: SID_AUTH_ACCOUNTLOGONPROOF: + if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( Packet->GetData( ) ) ) + { + // logon successful + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon successful" ); + m_LoggedIn = true; + m_GHost->EventBNETLoggedIn( this ); + m_Socket->write( m_Protocol->SEND_SID_NETGAMEPORT( m_GHost->m_HostPort ) ); + m_Socket->write( m_Protocol->SEND_SID_ENTERCHAT( ) ); + m_Socket->write( m_Protocol->SEND_SID_FRIENDSLIST( ) ); + m_Socket->write( m_Protocol->SEND_SID_CLANMEMBERLIST( ) ); + } + else + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] logon failed - invalid password, disconnecting" ); + + // try to figure out if the user might be using the wrong logon type since too many people are confused by this + + QString Server = m_Server; + Server = Server.toLower(); + + if( m_PasswordHashType == "pvpgn" && ( Server == "useast.battle.net" || Server == "uswest.battle.net" || Server == "asia.battle.net" || Server == "europe.battle.net" ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] it looks like you're trying to connect to a battle.net server using a pvpgn logon type, check your config file's \"battle.net custom data\" section" ); + else if( m_PasswordHashType != "pvpgn" && ( Server != "useast.battle.net" && Server != "uswest.battle.net" && Server != "asia.battle.net" && Server != "europe.battle.net" ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] it looks like you're trying to connect to a pvpgn server using a battle.net logon type, check your config file's \"battle.net custom data\" section" ); + + m_Socket->abort( ); + delete Packet; + return; + } + + break; + + case CBNETProtocol :: SID_WARDEN: + WardenData = m_Protocol->RECEIVE_SID_WARDEN( Packet->GetData( ) ); + + if( m_BNLSClient ) + m_BNLSClient->QueueWardenRaw( WardenData ); + else + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] warning - received warden packet but no BNLS server is available, you will be kicked from battle.net soon" ); + + break; + + case CBNETProtocol :: SID_FRIENDSLIST: + Friends = m_Protocol->RECEIVE_SID_FRIENDSLIST( Packet->GetData( ) ); + + for( QList :: const_iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) + delete *i; + + m_Friends = Friends; + break; + + case CBNETProtocol :: SID_CLANMEMBERLIST: + QList Clans = m_Protocol->RECEIVE_SID_CLANMEMBERLIST( Packet->GetData( ) ); + + for( QList :: const_iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) + delete *i; + + m_Clans = Clans; + break; + } + } + + delete Packet; + } +} + +void CBNET :: ProcessChatEvent( CIncomingChatEvent *chatEvent ) +{ + CBNETProtocol :: IncomingChatEvent Event = chatEvent->GetChatEvent( ); + bool Whisper = ( Event == CBNETProtocol :: EID_WHISPER ); + QString User = chatEvent->GetUser( ); + QString Message = chatEvent->GetMessage( ); + + if( Event == CBNETProtocol :: EID_WHISPER || Event == CBNETProtocol :: EID_TALK ) + { + if( Event == CBNETProtocol :: EID_WHISPER ) + { + CONSOLE_Print( "[WHISPER: " + m_ServerAlias + "] [" + User + "] " + Message ); + m_GHost->EventBNETWhisper( this, User, Message ); + } + else + { + CONSOLE_Print( "[LOCAL: " + m_ServerAlias + "] [" + User + "] " + Message ); + m_GHost->EventBNETChat( this, User, Message ); + } + + // handle spoof checking for current game + // this case covers whispers - we assume that anyone who sends a whisper to the bot with message "spoofcheck" should be considered spoof checked + // note that this means you can whisper "spoofcheck" even in a public game to manually spoofcheck if the /whois fails + + if( Event == CBNETProtocol :: EID_WHISPER && m_GHost->GetCurrentGame( ) ) + { + if( Message == "s" || Message == "sc" || Message == "spoof" || Message == "check" || Message == "spoofcheck" ) + m_GHost->GetCurrentGame( )->AddToSpoofed( m_Server, User, true ); + else if( Message.indexOf( m_GHost->GetCurrentGame( )->GetGameName( ) ) != -1 ) + { + // look for messages like "entered a Warcraft III The Frozen Throne game called XYZ" + // we don't look for the English part of the text anymore because we want this to work with multiple languages + // it's a pretty safe bet that anyone whispering the bot with a message containing the game name is a valid spoofcheck + + if( m_PasswordHashType == "pvpgn" && User == m_PVPGNRealmName ) + { + // the equivalent pvpgn message is: [PvPGN Realm] Your friend abc has entered a Warcraft III Frozen Throne game named "xyz". + + QList Tokens = UTIL_Tokenize( Message, ' ' ); + + if( Tokens.size( ) >= 3 ) + m_GHost->GetCurrentGame( )->AddToSpoofed( m_Server, Tokens[2], false ); + } + else + m_GHost->GetCurrentGame( )->AddToSpoofed( m_Server, User, false ); + } + } + + // handle bot commands + + if( Message == "?trigger" && ( IsAdmin( User ) || IsRootAdmin( User ) || ( m_PublicCommands && m_OutPackets.size( ) <= 3 ) ) ) + QueueChatCommand( m_GHost->GetLanguage( )->CommandTrigger( QString( 1, m_CommandTrigger ) ), User, Whisper ); + else if( !Message.isEmpty( ) && Message[0] == m_CommandTrigger ) + { + // extract the command trigger, the command, and the payload + // e.g. "!say hello world" -> command: "say", payload: "hello world" + + QString Command; + QString Payload; + int PayloadStart = Message.indexOf( " " ); + + if( PayloadStart != -1 ) + { + Command = Message.mid( 1, PayloadStart - 1 ); + Payload = Message.mid( PayloadStart + 1 ); + } + else + Command = Message.mid( 1 ); + + emit SignalBnetCommand( this, User, Command, Payload, Whisper ); + + Command = Command.toLower(); + + if( IsAdmin( User ) || IsRootAdmin( User ) ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] admin [" + User + "] sent command [" + Message + "]" ); + + /***************** + * ADMIN COMMANDS * + ******************/ + + // + // !ADDADMIN + // + + if( Command == "addadmin" && !Payload.isEmpty( ) ) + { + if( IsRootAdmin( User ) ) + { + if( IsAdmin( Payload ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UserIsAlreadyAnAdmin( m_Server, Payload ), User, Whisper ); + else + m_PairedAdminAdds.push_back( PairedAdminAdd( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedAdminAdd( m_Server, Payload ) ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !ADDBAN + // !BAN + // + + if( ( Command == "addban" || Command == "ban" ) && !Payload.isEmpty( ) ) + { + // extract the victim and the reason + // e.g. "Varlock leaver after dying" -> victim: "Varlock", reason: "leaver after dying" + + QString Victim; + QString Reason; + QTextStream SS(&Payload); + SS >> Victim; + + if( !SS.atEnd( ) ) + { + Reason = SS.readLine(); + int Start = Reason.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + Reason = Reason.mid( Start ); + } + + if( IsBannedName( Victim ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UserIsAlreadyBanned( m_Server, Victim ), User, Whisper ); + else + m_PairedBanAdds.push_back( PairedBanAdd( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedBanAdd( m_Server, Victim, QString( ), QString( ), User, Reason ) ) ); + } + + // + // !ANNOUNCE + // + + if( Command == "announce" && m_GHost->GetCurrentGame( ) && !m_GHost->GetCurrentGame( )->GetCountDownStarted( ) ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + QueueChatCommand( m_GHost->GetLanguage( )->AnnounceMessageDisabled( ), User, Whisper ); + m_GHost->GetCurrentGame( )->SetAnnounce( 0, QString( ) ); + } + else + { + // extract the interval and the message + // e.g. "30 hello everyone" -> interval: "30", message: "hello everyone" + + quint32 Interval; + QString Message; + QTextStream SS(&Payload); + SS >> Interval; + + if( SS.status() != QTextStream::Ok || Interval == 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to announce command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to announce command" ); + else + { + Message = SS.readLine(); + int Start = Message.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + Message = Message.mid( Start ); + + QueueChatCommand( m_GHost->GetLanguage( )->AnnounceMessageEnabled( ), User, Whisper ); + m_GHost->GetCurrentGame( )->SetAnnounce( Interval, Message ); + } + } + } + } + + // + // !AUTOHOST + // + + if( Command == "autohost" ) + { + if( IsRootAdmin( User ) ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + QueueChatCommand( m_GHost->GetLanguage( )->AutoHostDisabled( ), User, Whisper ); + m_GHost->m_AutoHostGameName.clear( ); + m_GHost->m_AutoHostOwner.clear( ); + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = 0; + m_GHost->m_AutoHostAutoStartPlayers = 0; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + else + { + // extract the maximum games, auto start players, and the game name + // e.g. "5 10 BattleShips Pro" -> maximum games: "5", auto start players: "10", game name: "BattleShips Pro" + + quint32 MaximumGames; + quint32 AutoStartPlayers; + QString GameName; + QTextStream SS(&Payload); + SS >> MaximumGames; + + if( SS.status() != QTextStream::Ok || MaximumGames == 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to autohost command" ); + else + { + SS >> AutoStartPlayers; + + if( SS.status() != QTextStream::Ok || AutoStartPlayers == 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to autohost command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #3 to autohost command" ); + else + { + GameName = SS.readLine(); + int Start = GameName.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + GameName = GameName.mid( Start ); + + QueueChatCommand( m_GHost->GetLanguage( )->AutoHostEnabled( ), User, Whisper ); + + m_GHost->SetAutoHostMap( new CMap( *m_GHost->GetCurrentMap( ) ) ); + m_GHost->m_AutoHostGameName = GameName; + m_GHost->m_AutoHostOwner = User; + m_GHost->m_AutoHostServer = m_Server; + m_GHost->m_AutoHostMaximumGames = MaximumGames; + m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + } + } + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !AUTOHOSTMM + // + + if( Command == "autohostmm" ) + { + if( IsRootAdmin( User ) ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + QueueChatCommand( m_GHost->GetLanguage( )->AutoHostDisabled( ), User, Whisper ); + m_GHost->m_AutoHostGameName.clear( ); + m_GHost->m_AutoHostOwner.clear( ); + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = 0; + m_GHost->m_AutoHostAutoStartPlayers = 0; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + else + { + // extract the maximum games, auto start players, minimum score, maximum score, and the game name + // e.g. "5 10 800 1200 BattleShips Pro" -> maximum games: "5", auto start players: "10", minimum score: "800", maximum score: "1200", game name: "BattleShips Pro" + + quint32 MaximumGames; + quint32 AutoStartPlayers; + double MinimumScore; + double MaximumScore; + QString GameName; + QTextStream SS(&Payload); + SS >> MaximumGames; + + if( SS.status() != QTextStream::Ok || MaximumGames == 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to autohostmm command" ); + else + { + SS >> AutoStartPlayers; + + if( SS.status() != QTextStream::Ok || AutoStartPlayers == 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to autohostmm command" ); + else + { + SS >> MinimumScore; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #3 to autohostmm command" ); + else + { + SS >> MaximumScore; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #4 to autohostmm command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #5 to autohostmm command" ); + else + { + GameName = SS.readLine(); + int Start = GameName.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + GameName = GameName.mid( Start ); + + QueueChatCommand( m_GHost->GetLanguage( )->AutoHostEnabled( ), User, Whisper ); + + m_GHost->SetAutoHostMap( new CMap( *m_GHost->GetCurrentMap( ) ) ); + m_GHost->m_AutoHostGameName = GameName; + m_GHost->m_AutoHostOwner = User; + m_GHost->m_AutoHostServer = m_Server; + m_GHost->m_AutoHostMaximumGames = MaximumGames; + m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; + m_GHost->m_AutoHostMatchMaking = true; + m_GHost->m_AutoHostMinimumScore = MinimumScore; + m_GHost->m_AutoHostMaximumScore = MaximumScore; + } + } + } + } + } + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !AUTOSTART + // + + if( Command == "autostart" && m_GHost->GetCurrentGame( ) && !m_GHost->GetCurrentGame( )->GetCountDownStarted( ) ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + QueueChatCommand( m_GHost->GetLanguage( )->AutoStartDisabled( ), User, Whisper ); + m_GHost->GetCurrentGame( )->SetAutoStartPlayers( 0 ); + } + else + { + quint32 AutoStartPlayers = Payload.toUInt(); + + if( AutoStartPlayers != 0 ) + { + QueueChatCommand( m_GHost->GetLanguage( )->AutoStartEnabled( QString::number( AutoStartPlayers ) ), User, Whisper ); + m_GHost->GetCurrentGame( )->SetAutoStartPlayers( AutoStartPlayers ); + } + } + } + + // + // !CHANNEL (change channel) + // + + if( Command == "channel" && !Payload.isEmpty( ) ) + QueueChatCommand( "/join " + Payload ); + + // + // !CHECKADMIN + // + + if( Command == "checkadmin" && !Payload.isEmpty( ) ) + { + if( IsRootAdmin( User ) ) + { + if( IsAdmin( Payload ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UserIsAnAdmin( m_Server, Payload ), User, Whisper ); + else + QueueChatCommand( m_GHost->GetLanguage( )->UserIsNotAnAdmin( m_Server, Payload ), User, Whisper ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !CHECKBAN + // + + if( Command == "checkban" && !Payload.isEmpty( ) ) + { + CDBBan *Ban = IsBannedName( Payload ); + + if( Ban ) + QueueChatCommand( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( m_Server, Payload, Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ), User, Whisper ); + else + QueueChatCommand( m_GHost->GetLanguage( )->UserIsNotBanned( m_Server, Payload ), User, Whisper ); + } + + // + // !CLOSE (close slot) + // + + if( Command == "close" && !Payload.isEmpty( ) && m_GHost->GetCurrentGame( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + { + // close as many slots as specified, e.g. "5 10" closes slots 5 and 10 + + QTextStream SS(&Payload); + + while( !SS.atEnd( ) ) + { + quint32 SID; + SS >> SID; + + if( SS.status() != QTextStream::Ok ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to close command" ); + break; + } + else + m_GHost->GetCurrentGame( )->CloseSlot( (unsigned char)( SID - 1 ), true ); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !CLOSEALL + // + + if( Command == "closeall" && m_GHost->GetCurrentGame( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + m_GHost->GetCurrentGame( )->CloseAllSlots( ); + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !COUNTADMINS + // + + if( Command == "countadmins" ) + { + if( IsRootAdmin( User ) ) + m_PairedAdminCounts.push_back( PairedAdminCount( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedAdminCount( m_Server ) ) ); + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !COUNTBANS + // + + if( Command == "countbans" ) + m_PairedBanCounts.push_back( PairedBanCount( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedBanCount( m_Server ) ) ); + + // + // !DBSTATUS + // + + if( Command == "dbstatus" ) + QueueChatCommand( m_GHost->m_DB->GetStatus( ), User, Whisper ); + + // + // !DELADMIN + // + + if( Command == "deladmin" && !Payload.isEmpty( ) ) + { + if( IsRootAdmin( User ) ) + { + if( !IsAdmin( Payload ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UserIsNotAnAdmin( m_Server, Payload ), User, Whisper ); + else + m_PairedAdminRemoves.push_back( PairedAdminRemove( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedAdminRemove( m_Server, Payload ) ) ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !DELBAN + // !UNBAN + // + + if( ( Command == "delban" || Command == "unban" ) && !Payload.isEmpty( ) ) + m_PairedBanRemoves.push_back( PairedBanRemove( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedBanRemove( Payload ) ) ); + + // + // !DISABLE + // + + if( Command == "disable" ) + { + if( IsRootAdmin( User ) ) + { + QueueChatCommand( m_GHost->GetLanguage( )->BotDisabled( ), User, Whisper ); + m_GHost->DisableGameCreation( ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !DOWNLOADS + // + + if( Command == "downloads" && !Payload.isEmpty( ) ) + { + quint32 Downloads = Payload.toUInt(); + + if( Downloads == 0 ) + { + QueueChatCommand( m_GHost->GetLanguage( )->MapDownloadsDisabled( ), User, Whisper ); + m_GHost->m_AllowDownloads = 0; + } + else if( Downloads == 1 ) + { + QueueChatCommand( m_GHost->GetLanguage( )->MapDownloadsEnabled( ), User, Whisper ); + m_GHost->m_AllowDownloads = 1; + } + else if( Downloads == 2 ) + { + QueueChatCommand( m_GHost->GetLanguage( )->MapDownloadsConditional( ), User, Whisper ); + m_GHost->m_AllowDownloads = 2; + } + } + + // + // !ENABLE + // + + if( Command == "enable" ) + { + if( IsRootAdmin( User ) ) + { + QueueChatCommand( m_GHost->GetLanguage( )->BotEnabled( ), User, Whisper ); + m_GHost->EnableGameCreation( ); } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !END + // + + if( Command == "end" && !Payload.isEmpty( ) ) + { + // todotodo: what if a game ends just as you're typing this command and the numbering changes? + + int GameNumber = Payload.toUInt() - 1; + + if( GameNumber < m_GHost->m_Games.size( ) ) + { + // if the game owner is still in the game only allow the root admin to end the game + + if( m_GHost->m_Games[GameNumber]->GetPlayerFromName( m_GHost->m_Games[GameNumber]->GetOwnerName( ), false ) && !IsRootAdmin( User ) ) + QueueChatCommand( m_GHost->GetLanguage( )->CantEndGameOwnerIsStillPlaying( m_GHost->m_Games[GameNumber]->GetOwnerName( ) ), User, Whisper ); + else + { + QueueChatCommand( m_GHost->GetLanguage( )->EndingGame( m_GHost->m_Games[GameNumber]->GetDescription( ) ), User, Whisper ); + CONSOLE_Print( "[GAME: " + m_GHost->m_Games[GameNumber]->GetGameName( ) + "] is over (admin ended game)" ); + m_GHost->m_Games[GameNumber]->StopPlayers( "was disconnected (admin ended game)" ); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->GameNumberDoesntExist( Payload ), User, Whisper ); + } + + // + // !ENFORCESG + // + + if( Command == "enforcesg" && !Payload.isEmpty( ) ) + { + // only load files in the current directory just to be safe + + if( Payload.indexOf( "/" ) != -1 || Payload.indexOf( "\\" ) != -1 ) + QueueChatCommand( m_GHost->GetLanguage( )->UnableToLoadReplaysOutside( ), User, Whisper ); + else + { + QString File = m_GHost->m_ReplayPath + Payload + ".w3g"; + + if( QFile::exists( File ) ) + { + QueueChatCommand( m_GHost->GetLanguage( )->LoadingReplay( File ), User, Whisper ); + CReplay *Replay = new CReplay( ); + Replay->Load( File, false ); + Replay->ParseReplay( false ); + m_GHost->m_EnforcePlayers = Replay->GetPlayers( ); + delete Replay; + } + else + QueueChatCommand( m_GHost->GetLanguage( )->UnableToLoadReplayDoesntExist( File ), User, Whisper ); + } + } + + // + // !EXIT + // !QUIT + // + + if( Command == "exit" || Command == "quit" ) + { + if( IsRootAdmin( User ) ) + { + if( Payload == "nice" ) + m_GHost->ExitNice( ); + else if( Payload == "force" ) + m_GHost->deleteLater(); + else + { + if( m_GHost->GetCurrentGame( ) || !m_GHost->m_Games.isEmpty( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->AtLeastOneGameActiveUseForceToShutdown( ), User, Whisper ); + else + m_GHost->deleteLater(); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !GETCLAN + // + + if( Command == "getclan" ) + { + SendGetClanList( ); + QueueChatCommand( m_GHost->GetLanguage( )->UpdatingClanList( ), User, Whisper ); + } + + // + // !GETFRIENDS + // + + if( Command == "getfriends" ) + { + SendGetFriendsList( ); + QueueChatCommand( m_GHost->GetLanguage( )->UpdatingFriendsList( ), User, Whisper ); + } + + // + // !GETGAME + // + + if( Command == "getgame" && !Payload.isEmpty( ) ) + { + int GameNumber = Payload.toUInt() - 1; + + if( GameNumber < m_GHost->m_Games.size( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->GameNumberIs( Payload, m_GHost->m_Games[GameNumber]->GetDescription( ) ), User, Whisper ); + else + QueueChatCommand( m_GHost->GetLanguage( )->GameNumberDoesntExist( Payload ), User, Whisper ); + } + + // + // !GETGAMES + // + + if( Command == "getgames" ) + { + if( m_GHost->GetCurrentGame( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->GameIsInTheLobby( m_GHost->GetCurrentGame( )->GetDescription( ), QString::number( m_GHost->m_Games.size( ) ), QString::number( m_GHost->m_MaxGames ) ), User, Whisper ); + else + QueueChatCommand( m_GHost->GetLanguage( )->ThereIsNoGameInTheLobby( QString::number( m_GHost->m_Games.size( ) ), QString::number( m_GHost->m_MaxGames ) ), User, Whisper ); + } + + // + // !HOLD (hold a slot for someone) + // + + if( Command == "hold" && !Payload.isEmpty( ) && m_GHost->GetCurrentGame( ) ) + { + // hold as many players as specified, e.g. "Varlock Kilranin" holds players "Varlock" and "Kilranin" + + QTextStream SS(&Payload); + + while( !SS.atEnd( ) ) + { + QString HoldName; + SS >> HoldName; + + if( SS.status() != QTextStream::Ok ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to hold command" ); + break; + } + else + { + QueueChatCommand( m_GHost->GetLanguage( )->AddedPlayerToTheHoldList( HoldName ), User, Whisper ); + m_GHost->GetCurrentGame( )->AddToReserved( HoldName ); + } + } + } + + // + // !HOSTSG + // + + if( Command == "hostsg" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, true, Payload, User, User, m_Server, Whisper ); + + // + // !LOAD (load config file) + // + + if( Command == "load" ) + { + if( Payload.isEmpty( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->CurrentlyLoadedMapCFGIs( m_GHost->GetCurrentMap( )->GetCFGFile( ) ), User, Whisper ); + else + { + try + { + QDir MapCFGPath( m_GHost->m_MapCFGPath ); + QString Pattern = Payload.toLower(); + + if( !MapCFGPath.exists() ) + { + CONSOLE_Print( "[ADMINGAME] error listing map configs - map config path doesn't exist" ); + QueueChatCommand( m_GHost->GetLanguage( )->ErrorListingMapConfigs( ), User, Whisper ); + } + else + { + QStringList files = MapCFGPath.entryList(QStringList("*" + Pattern + "*"), QDir::Files, QDir::Name); + quint32 Matches = files.size(); + + if( Matches == 0 ) + QueueChatCommand( m_GHost->GetLanguage( )->NoMapConfigsFound( ), User, Whisper ); + else if (files.contains(Pattern)) + { + QueueChatCommand( m_GHost->GetLanguage( )->LoadingConfigFile( m_GHost->m_MapCFGPath + Pattern ), User, Whisper ); + CConfig MapCFG; + MapCFG.Read( Pattern ); + m_GHost->GetCurrentMap( )->Load( MapCFG, m_GHost->m_MapCFGPath + Pattern ); + } + else if (Matches == 1) + { + QString File = files.at(0); + QueueChatCommand( m_GHost->GetLanguage( )->LoadingConfigFile( m_GHost->m_MapCFGPath + File ), User, Whisper ); + CConfig MapCFG; + MapCFG.Read( m_GHost->m_MapCFGPath + File ); + m_GHost->GetCurrentMap( )->Load( MapCFG, m_GHost->m_MapCFGPath + File ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->FoundMapConfigs( files.join(", ") ), User, Whisper ); + } + } + catch( const exception &ex ) + { + CONSOLE_Print( QString( "[ADMINGAME] error listing map configs - caught exception [" ) + ex.what( ) + "]" ); + QueueChatCommand( m_GHost->GetLanguage( )->ErrorListingMapConfigs( ), User, Whisper ); + } + } + } + + // + // !LOADSG + // + + if( Command == "loadsg" && !Payload.isEmpty( ) ) + { + // only load files in the current directory just to be safe + + if( Payload.indexOf( "/" ) != -1 || Payload.indexOf( "\\" ) != -1 ) + QueueChatCommand( m_GHost->GetLanguage( )->UnableToLoadSaveGamesOutside( ), User, Whisper ); + else + { + QString File = m_GHost->m_SaveGamePath + Payload + ".w3z"; + + if( QFile::exists( File ) ) + { + if( m_GHost->GetCurrentGame( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UnableToLoadSaveGameGameInLobby( ), User, Whisper ); + else + { + QueueChatCommand( m_GHost->GetLanguage( )->LoadingSaveGame( File ), User, Whisper ); + m_GHost->LoadSavegame( File ); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->UnableToLoadSaveGameDoesntExist( File ), User, Whisper ); + } + } + + // + // !MAP (load map file) + // + + if( Command == "map" ) + { + if( Payload.isEmpty( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->CurrentlyLoadedMapCFGIs( m_GHost->GetCurrentMap( )->GetCFGFile( ) ), User, Whisper ); + else + { + QString FoundMaps; + + try + { + QDir MapPath( m_GHost->m_MapPath ); + QString Pattern = Payload.toLower(); + + if( !MapPath.exists() ) + { + CONSOLE_Print( "[ADMINGAME] error listing maps - map path doesn't exist" ); + QueueChatCommand( m_GHost->GetLanguage( )->ErrorListingMaps( ), User, Whisper ); + } + else + { + QStringList files = MapPath.entryList(QStringList("*"+Pattern+"*"), QDir::Files, QDir::Name); + quint32 Matches = files.size(); + + if( Matches == 0 ) + QueueChatCommand( m_GHost->GetLanguage( )->NoMapsFound( ), User, Whisper ); + else if (files.contains(Pattern)) + { + QueueChatCommand( m_GHost->GetLanguage( )->LoadingConfigFile( Pattern ), User, Whisper ); + + // hackhack: create a config file in memory with the required information to load the map + + CConfig MapCFG; + MapCFG.Set( "map_path", "Maps\\Download\\" + Pattern ); + MapCFG.Set( "map_localpath", Pattern ); + m_GHost->GetCurrentMap( )->Load( MapCFG, Pattern ); + } + else if( Matches == 1 ) + { + QString File = files.at(0); + QueueChatCommand( m_GHost->GetLanguage( )->LoadingConfigFile( File ), User, Whisper ); + + // hackhack: create a config file in memory with the required information to load the map + + CConfig MapCFG; + MapCFG.Set( "map_path", "Maps\\Download\\" + File ); + MapCFG.Set( "map_localpath", File ); + m_GHost->GetCurrentMap( )->Load( MapCFG, File ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->FoundMaps( files.join(", ") ), User, Whisper ); + } + } + catch( const exception &ex ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] error listing maps - caught exception [" + ex.what( ) + "]" ); + QueueChatCommand( m_GHost->GetLanguage( )->ErrorListingMaps( ), User, Whisper ); + } + } + } + + // + // !OPEN (open slot) + // + + if( Command == "open" && !Payload.isEmpty( ) && m_GHost->GetCurrentGame( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + { + // open as many slots as specified, e.g. "5 10" opens slots 5 and 10 + + QTextStream SS(&Payload); + + while( !SS.atEnd( ) ) + { + quint32 SID; + SS >> SID; + + if( SS.status() != QTextStream::Ok ) + { + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input to open command" ); + break; + } + else + m_GHost->GetCurrentGame( )->OpenSlot( (unsigned char)( SID - 1 ), true ); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !OPENALL + // + + if( Command == "openall" && m_GHost->GetCurrentGame( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + m_GHost->GetCurrentGame( )->OpenAllSlots( ); + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !PRIV (host private game) + // + + if( Command == "priv" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, false, Payload, User, User, m_Server, Whisper ); + + // + // !PRIVBY (host private game by other player) + // + + if( Command == "privby" && !Payload.isEmpty( ) ) + { + // extract the owner and the game name + // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" + + QString Owner; + QString GameName; + int GameNameStart = Payload.indexOf( " " ); + + if( GameNameStart != -1 ) + { + Owner = Payload.mid( 0, GameNameStart ); + GameName = Payload.mid( GameNameStart + 1 ); + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, false, GameName, Owner, User, m_Server, Whisper ); + } + } + + // + // !PUB (host public game) + // + + if( Command == "pub" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PUBLIC, false, Payload, User, User, m_Server, Whisper ); + + // + // !PUBBY (host public game by other player) + // + + if( Command == "pubby" && !Payload.isEmpty( ) ) + { + // extract the owner and the game name + // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" + + QString Owner; + QString GameName; + int GameNameStart = Payload.indexOf( " " ); + + if( GameNameStart != -1 ) + { + Owner = Payload.mid( 0, GameNameStart ); + GameName = Payload.mid( GameNameStart + 1 ); + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PUBLIC, false, GameName, Owner, User, m_Server, Whisper ); + } + } + + // + // !RELOAD + // + + if( Command == "reload" ) + { + if( IsRootAdmin( User ) ) + { + QueueChatCommand( m_GHost->GetLanguage( )->ReloadingConfigurationFiles( ), User, Whisper ); + m_GHost->ReloadConfigs( ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !SAY + // + + if( Command == "say" && !Payload.isEmpty( ) ) + QueueChatCommand( Payload ); + + // + // !SAYGAME + // + + if( Command == "saygame" && !Payload.isEmpty( ) ) + { + if( IsRootAdmin( User ) ) + { + // extract the game number and the message + // e.g. "3 hello everyone" -> game number: "3", message: "hello everyone" + + int GameNumber; + QString Message; + QTextStream SS(&Payload); + + SS >> GameNumber; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to saygame command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to saygame command" ); + else + { + Message = SS.readLine(); + int Start = Message.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + Message = Message.mid( Start ); + + if( GameNumber - 1 < m_GHost->m_Games.size( ) ) + m_GHost->m_Games[GameNumber - 1]->SendAllChat( "ADMIN: " + Message ); + else + QueueChatCommand( m_GHost->GetLanguage( )->GameNumberDoesntExist( QString::number( GameNumber ) ), User, Whisper ); + } + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !SAYGAMES + // + + if( Command == "saygames" && !Payload.isEmpty( ) ) + { + if( IsRootAdmin( User ) ) + { + if( m_GHost->GetCurrentGame( ) ) + m_GHost->GetCurrentGame( )->SendAllChat( Payload ); + + for( QList :: const_iterator i = m_GHost->m_Games.begin( ); i != m_GHost->m_Games.end( ); i++ ) + (*i)->SendAllChat( "ADMIN: " + Payload ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->YouDontHaveAccessToThatCommand( ), User, Whisper ); + } + + // + // !SP + // + + if( Command == "sp" && m_GHost->GetCurrentGame( ) && !m_GHost->GetCurrentGame( )->GetCountDownStarted( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + { + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->ShufflingPlayers( ) ); + m_GHost->GetCurrentGame( )->ShuffleSlots( ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !START + // + + if( Command == "start" && m_GHost->GetCurrentGame( ) && !m_GHost->GetCurrentGame( )->GetCountDownStarted( ) && m_GHost->GetCurrentGame( )->GetNumHumanPlayers( ) > 0 ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + { + // if the player sent "!start force" skip the checks and start the countdown + // otherwise check that the game is ready to start + + if( Payload == "force" ) + m_GHost->GetCurrentGame( )->StartCountDown( true ); + else + m_GHost->GetCurrentGame( )->StartCountDown( false ); + } + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !SWAP (swap slots) + // + + if( Command == "swap" && !Payload.isEmpty( ) && m_GHost->GetCurrentGame( ) ) + { + if( !m_GHost->GetCurrentGame( )->GetLocked( ) ) + { + quint32 SID1; + quint32 SID2; + QTextStream SS(&Payload); + + SS >> SID1; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #1 to swap command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] missing input #2 to swap command" ); + else + { + SS >> SID2; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] bad input #2 to swap command" ); + else + m_GHost->GetCurrentGame( )->SwapSlots( (unsigned char)( SID1 - 1 ), (unsigned char)( SID2 - 1 ) ); + } + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->TheGameIsLockedBNET( ), User, Whisper ); + } + + // + // !UNHOST + // + + if( Command == "unhost" ) + { + if( m_GHost->GetCurrentGame( ) ) + { + if( m_GHost->GetCurrentGame( )->GetCountDownStarted( ) ) + QueueChatCommand( m_GHost->GetLanguage( )->UnableToUnhostGameCountdownStarted( m_GHost->GetCurrentGame( )->GetDescription( ) ), User, Whisper ); + + // if the game owner is still in the game only allow the root admin to unhost the game + + else if( m_GHost->GetCurrentGame( )->GetPlayerFromName( m_GHost->GetCurrentGame( )->GetOwnerName( ), false ) && !IsRootAdmin( User ) ) + QueueChatCommand( m_GHost->GetLanguage( )->CantUnhostGameOwnerIsPresent( m_GHost->GetCurrentGame( )->GetOwnerName( ) ), User, Whisper ); + else + { + QueueChatCommand( m_GHost->GetLanguage( )->UnhostingGame( m_GHost->GetCurrentGame( )->GetDescription( ) ), User, Whisper ); + m_GHost->GetCurrentGame( )->deleteLater(); + } + } + else + QueueChatCommand( m_GHost->GetLanguage( )->UnableToUnhostGameNoGameInLobby( ), User, Whisper ); + } + + // + // !WARDENSTATUS + // + + if( Command == "wardenstatus" ) + { + if( m_BNLSClient ) + QueueChatCommand( "WARDEN STATUS --- " + QString::number( m_BNLSClient->GetTotalWardenIn( ) ) + " requests received, " + QString::number( m_BNLSClient->GetTotalWardenOut( ) ) + " responses sent.", User, Whisper ); + else + QueueChatCommand( "WARDEN STATUS --- Not connected to BNLS server.", User, Whisper ); + } + } + else + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] non-admin [" + User + "] sent command [" + Message + "]" ); + + /********************* + * NON ADMIN COMMANDS * + *********************/ + + // don't respond to non admins if there are more than 3 messages already in the queue + // this prevents malicious users from filling up the bot's chat queue and crippling the bot + // in some cases the queue may be full of legitimate messages but we don't really care if the bot ignores one of these commands once in awhile + // e.g. when several users join a game at the same time and cause multiple /whois messages to be queued at once + + if( IsAdmin( User ) || IsRootAdmin( User ) || ( m_PublicCommands && m_OutPackets.size( ) <= 3 ) ) + { + // + // !STATS + // + + if( Command == "stats" ) + { + QString StatsUser = User; + + if( !Payload.isEmpty( ) ) + StatsUser = Payload; + + // check for potential abuse + + if( !StatsUser.isEmpty( ) && StatsUser.size( ) < 16 && StatsUser[0] != '/' ) + m_PairedGPSChecks.push_back( PairedGPSCheck( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedGamePlayerSummaryCheck( StatsUser ) ) ); + } + + // + // !STATSDOTA + // + + if( Command == "statsdota" ) + { + QString StatsUser = User; + + if( !Payload.isEmpty( ) ) + StatsUser = Payload; + + // check for potential abuse + + if( !StatsUser.isEmpty( ) && StatsUser.size( ) < 16 && StatsUser[0] != '/' ) + m_PairedDPSChecks.push_back( PairedDPSCheck( Whisper ? User : QString( ), m_GHost->m_DB->ThreadedDotAPlayerSummaryCheck( StatsUser ) ) ); + } + + // + // !VERSION + // + + if( Command == "version" ) + { + if( IsAdmin( User ) || IsRootAdmin( User ) ) + QueueChatCommand( m_GHost->GetLanguage( )->VersionAdmin( m_GHost->GetVersion( ) ), User, Whisper ); + else + QueueChatCommand( m_GHost->GetLanguage( )->VersionNotAdmin( m_GHost->GetVersion( ) ), User, Whisper ); + } + } + } + } + else if( Event == CBNETProtocol :: EID_CHANNEL ) + { + // keep track of current channel so we can rejoin it after hosting a game + + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] joined channel [" + Message + "]" ); + m_CurrentChannel = Message; + } + else if( Event == CBNETProtocol :: EID_INFO ) + { + CONSOLE_Print( "[INFO: " + m_ServerAlias + "] " + Message ); + + // extract the first word which we hope is the username + // this is not necessarily true though since info messages also include channel MOTD's and such + + QString UserName; + int Split = Message.indexOf( " " ); + + if( Split != -1 ) + UserName = Message.mid( 0, Split ); + else + UserName = Message.mid( 0 ); + + // handle spoof checking for current game + // this case covers whois results which are used when hosting a public game (we send out a "/whois [player]" for each player) + // at all times you can still /w the bot with "spoofcheck" to manually spoof check + + if( m_GHost->GetCurrentGame( ) && m_GHost->GetCurrentGame( )->GetPlayerFromName( UserName, true ) ) + { + if( Message.indexOf( "is away" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofPossibleIsAway( UserName ) ); + else if( Message.indexOf( "is unavailable" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofPossibleIsUnavailable( UserName ) ); + else if( Message.indexOf( "is refusing messages" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofPossibleIsRefusingMessages( UserName ) ); + else if( Message.indexOf( "is using Warcraft III The Frozen Throne in the channel" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofDetectedIsNotInGame( UserName ) ); + else if( Message.indexOf( "is using Warcraft III The Frozen Throne in channel" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofDetectedIsNotInGame( UserName ) ); + else if( Message.indexOf( "is using Warcraft III The Frozen Throne in a private channel" ) != -1 ) + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofDetectedIsInPrivateChannel( UserName ) ); + + if( Message.indexOf( "is using Warcraft III The Frozen Throne in game" ) != -1 || Message.indexOf( "is using Warcraft III Frozen Throne and is currently in game" ) != -1 ) + { + // check both the current game name and the last game name against the /whois response + // this is because when the game is rehosted, players who joined recently will be in the previous game according to battle.net + // note: if the game is rehosted more than once it is possible (but unlikely) for a false positive because only two game names are checked + + if( Message.indexOf( m_GHost->GetCurrentGame( )->GetGameName( ) ) != -1 || Message.indexOf( m_GHost->GetCurrentGame( )->GetLastGameName( ) ) != -1 ) + m_GHost->GetCurrentGame( )->AddToSpoofed( m_Server, UserName, false ); + else + m_GHost->GetCurrentGame( )->SendAllChat( m_GHost->GetLanguage( )->SpoofDetectedIsInAnotherGame( UserName ) ); + } + } + } + else if( Event == CBNETProtocol :: EID_ERROR ) + CONSOLE_Print( "[ERROR: " + m_ServerAlias + "] " + Message ); + else if( Event == CBNETProtocol :: EID_EMOTE ) + { + CONSOLE_Print( "[EMOTE: " + m_ServerAlias + "] [" + User + "] " + Message ); + m_GHost->EventBNETEmote( this, User, Message ); + } +} + +void CBNET :: SendJoinChannel( const QString &channel ) +{ + if( m_LoggedIn && m_InChat ) + m_Socket->write( m_Protocol->SEND_SID_JOINCHANNEL( channel ) ); +} + +void CBNET :: SendGetFriendsList( ) +{ + if( m_LoggedIn ) + m_Socket->write( m_Protocol->SEND_SID_FRIENDSLIST( ) ); +} + +void CBNET :: SendGetClanList( ) +{ + if( m_LoggedIn ) + m_Socket->write( m_Protocol->SEND_SID_CLANMEMBERLIST( ) ); +} + +void CBNET :: QueueEnterChat( ) +{ + if( m_LoggedIn ) + EnqueuePacket( m_Protocol->SEND_SID_ENTERCHAT( ) ); +} + +void CBNET :: QueueChatCommand( const QString &chatCommand ) +{ + if( chatCommand.isEmpty( ) ) + return; + + if( m_LoggedIn ) + { + int maxTextLen = 255; + if( m_PasswordHashType == "pvpgn" ) + maxTextLen = m_MaxMessageLength; + QString cutCommand = chatCommand.mid( 0, maxTextLen ); + + if( m_OutPackets.size( ) > 10 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] attempted to queue chat command [" + cutCommand + "] but there are too many (" + QString::number( m_OutPackets.size( ) ) + ") packets queued, discarding" ); + else + { + CONSOLE_Print( "[QUEUED: " + m_ServerAlias + "] " + cutCommand ); + EnqueuePacket( m_Protocol->SEND_SID_CHATCOMMAND( cutCommand ) ); + } + } +} + +void CBNET :: QueueChatCommand( const QString &chatCommand, const QString &user, bool whisper ) +{ + if( chatCommand.isEmpty( ) ) + return; + + // if whisper is true send the chat command as a whisper to user, otherwise just queue the chat command + + if( whisper ) + QueueChatCommand( "/w " + user + " " + chatCommand ); + else + QueueChatCommand( chatCommand ); +} + +void CBNET :: QueueGameCreate( unsigned char state, const QString &gameName, const QString &hostName, CMap *map, CSaveGame *savegame, quint32 hostCounter ) +{ + if( m_LoggedIn && map ) + { + if( !m_CurrentChannel.isEmpty( ) ) + m_FirstChannel = m_CurrentChannel; + + m_InChat = false; + + // a game creation message is just a game refresh message with upTime = 0 + + QueueGameRefresh( state, gameName, hostName, map, savegame, 0, hostCounter ); + } +} + +void CBNET :: QueueGameRefresh( unsigned char state, const QString &gameName, const QString &hostName, CMap *map, CSaveGame *saveGame, quint32 upTime, quint32 hostCounter ) +{ + QString newHostName; + + if( hostName.isEmpty( ) ) + newHostName = m_Protocol->GetUniqueName( ); + else + newHostName = hostName; + + + if( m_LoggedIn && map ) + { + // construct a fixed host counter which will be used to identify players from this realm + // the fixed host counter's 4 most significant bits will contain a 4 bit ID (0-15) + // the rest of the fixed host counter will contain the 28 least significant bits of the actual host counter + // since we're destroying 4 bits of information here the actual host counter should not be greater than 2^28 which is a reasonable assumption + // when a player joins a game we can obtain the ID from the received host counter + // note: LAN broadcasts use an ID of 0, battle.net refreshes use an ID of 1-10, the rest are unused + + quint32 FixedHostCounter = ( hostCounter & 0x0FFFFFFF ) | ( m_HostCounterID << 28 ); + + // use an invalid map width/height to indicate reconnectable games + + QByteArray FakeMapWidth; + FakeMapWidth.push_back( 192 ); + FakeMapWidth.push_back( 7 ); + QByteArray FakeMapHeight; + FakeMapHeight.push_back( 192 ); + FakeMapHeight.push_back( 7 ); + + if( saveGame ) + { + quint32 MapGameType = MAPGAMETYPE_SAVEDGAME; + + // the state should always be private when creating a saved game + + if( state == GAME_PRIVATE ) + MapGameType |= MAPGAMETYPE_PRIVATEGAME; + + + + EnqueuePacket( m_Protocol->SEND_SID_STARTADVEX3( + state, + Util::fromUInt32( MapGameType), + map->GetMapGameFlags( ), + m_GHost->m_Reconnect ? FakeMapWidth : Util::EmptyData16(), + m_GHost->m_Reconnect ? FakeMapHeight : Util::EmptyData16(), + gameName, + newHostName, + upTime, + "Save\\Multiplayer\\" + saveGame->GetFileNameNoPath( ), + saveGame->GetMagicNumber( ), + map->GetMapSHA1( ), + FixedHostCounter ) ); + } + else + { + quint32 MapGameType = map->GetMapGameType( ); + MapGameType |= MAPGAMETYPE_UNKNOWN0; + + if( state == GAME_PRIVATE ) + MapGameType |= MAPGAMETYPE_PRIVATEGAME; + + if( m_GHost->m_Reconnect ) + EnqueuePacket( m_Protocol->SEND_SID_STARTADVEX3( state, Util::fromUInt32( MapGameType), map->GetMapGameFlags( ), FakeMapWidth, FakeMapHeight, gameName, newHostName, upTime, map->GetMapPath( ), map->GetMapCRC( ), map->GetMapSHA1( ), FixedHostCounter ) ); + else + EnqueuePacket( m_Protocol->SEND_SID_STARTADVEX3( state, Util::fromUInt32( MapGameType), map->GetMapGameFlags( ), map->GetMapWidth( ), map->GetMapHeight( ), gameName, newHostName, upTime, map->GetMapPath( ), map->GetMapCRC( ), map->GetMapSHA1( ), FixedHostCounter ) ); + } + } +} + +void CBNET :: QueueGameUncreate( ) +{ + if( m_LoggedIn ) + EnqueuePacket( m_Protocol->SEND_SID_STOPADV( ) ); +} + +void CBNET :: UnqueuePackets( unsigned char type ) +{ + QQueue Packets; + quint32 Unqueued = 0; + + while( !m_OutPackets.isEmpty( ) ) + { + // todotodo: it's very inefficient to have to copy all these packets while searching the queue + + QByteArray Packet = m_OutPackets.front( ); + m_OutPackets.dequeue( ); + + if( Packet.size( ) >= 2 && Packet.at(1) == type ) + Unqueued++; + else + Packets.enqueue( Packet ); + } + + m_OutPackets = Packets; + + if( Unqueued > 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] unqueued " + QString::number( Unqueued ) + " packets of type " + QString::number( type ) ); +} + +void CBNET :: UnqueueChatCommand( const QString &chatCommand ) +{ + // hackhack: this is ugly code + // generate the packet that would be sent for this chat command + // then search the queue for that exact packet + + QByteArray PacketToUnqueue = m_Protocol->SEND_SID_CHATCOMMAND( chatCommand ); + QQueue Packets; + quint32 Unqueued = 0; + + while( !m_OutPackets.isEmpty( ) ) + { + // todotodo: it's very inefficient to have to copy all these packets while searching the queue + + QByteArray Packet = m_OutPackets.front( ); + m_OutPackets.dequeue( ); + + if( Packet == PacketToUnqueue ) + Unqueued++; + else + Packets.enqueue( Packet ); + } + + m_OutPackets = Packets; + + if( Unqueued > 0 ) + CONSOLE_Print( "[BNET: " + m_ServerAlias + "] unqueued " + QString::number( Unqueued ) + " chat command packets" ); +} + +void CBNET :: UnqueueGameRefreshes( ) +{ + UnqueuePackets( CBNETProtocol :: SID_STARTADVEX3 ); +} + +bool CBNET :: IsAdmin( const QString &name ) const +{ + if( m_Admins.contains( name, Qt :: CaseInsensitive ) ) + return true; + return false; +} + +bool CBNET :: IsRootAdmin( const QString &name ) const +{ + if ( m_RootAdmins.contains(name, Qt :: CaseInsensitive ) ) { + return true; + } + + return false; +} + +CDBBan *CBNET :: IsBannedName( const QString &name ) const +{ + // todotodo: optimize this - maybe use a map? + + for( QList :: const_iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) + { + if( name.compare( (*i)->GetName( ), Qt :: CaseInsensitive ) == 0) + return *i; + } + + return NULL; +} + +CDBBan *CBNET :: IsBannedIP( const QString &ip ) const +{ + // todotodo: optimize this - maybe use a map? + + for( QList :: const_iterator i = m_Bans.begin( ); i != m_Bans.end( ); i++ ) + { + if( (*i)->GetIP( ) == ip ) + return *i; + } + + return NULL; +} + +void CBNET :: AddAdmin( const QString &name ) +{ + m_Admins.push_back( name.toLower() ); +} + +void CBNET :: AddBan( const QString &name, const QString &ip, const QString &gamename, const QString &admin, const QString &reason ) +{ + m_Bans.push_back( new CDBBan( m_Server, name.toLower(), ip, "N/A", gamename, admin, reason ) ); +} + +void CBNET :: RemoveAdmin( const QString &name ) +{ + m_Admins.removeOne( name.toLower( ) ); +} + +void CBNET :: RemoveBan( const QString &name ) +{ + for( QList :: iterator i = m_Bans.begin( ); i != m_Bans.end( ); ) + { + if( name.compare( (*i)->GetName( ), Qt :: CaseInsensitive ) == 0 ) + i = m_Bans.erase( i ); + else + i++; + } +} + +void CBNET :: HoldFriends( CBaseGame *game ) +{ + if( game ) + { + for( QList :: const_iterator i = m_Friends.begin( ); i != m_Friends.end( ); i++ ) + game->AddToReserved( (*i)->GetAccount( ) ); + } +} + +void CBNET :: HoldClan( CBaseGame *game ) +{ + if( game ) + { + for( QList :: const_iterator i = m_Clans.begin( ); i != m_Clans.end( ); i++ ) + game->AddToReserved( (*i)->GetName( ) ); + } +} diff --git a/src/libghost/bnet.h b/src/libghost/bnet.h new file mode 100644 index 0000000..c3b3118 --- /dev/null +++ b/src/libghost/bnet.h @@ -0,0 +1,246 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef BNET_H +#define BNET_H + +#include "includes.h" +#include +#include +#include + +class QTcpSocket; + +class CCommandPacket; +class CBNCSUtilInterface; +class CBNETProtocol; +class CBNLSClient; +class CIncomingFriendList; +class CIncomingClanList; +class CIncomingChatEvent; +class CCallableAdminCount; +class CCallableAdminAdd; +class CCallableAdminRemove; +class CCallableAdminList; +class CCallableBanCount; +class CCallableBanAdd; +class CCallableBanRemove; +class CCallableBanList; +class CCallableGamePlayerSummaryCheck; +class CCallableDotAPlayerSummaryCheck; +class CDBBan; +class CGHost; +class CSaveGame; +class CBaseGame; +class CMap; +class CBNETPrivate; + +typedef pair PairedAdminCount; +typedef pair PairedAdminAdd; +typedef pair PairedAdminRemove; +typedef pair PairedBanCount; +typedef pair PairedBanAdd; +typedef pair PairedBanRemove; +typedef pair PairedGPSCheck; +typedef pair PairedDPSCheck; + +typedef QPair TimeAndSizePair; + +// +// CBNET +// + +class CBNET : public QObject +{ + Q_OBJECT +private: + Q_DECLARE_PRIVATE(CBNET); +signals: + void SignalBnetCommand( CBNET *bnet, const QString &user, const QString &command, const QString &payload, bool whisper ); +public slots: + void socketConnected(); + void socketDisconnected(); + void socketDataReady(); + void socketConnect(); + void socketError(); + void socketConnectTimeoutCheck(); + void sendWardenResponse(const QByteArray & response); + void sendKeepAlivePacket(); + + void EventCallableUpdateTimeout(); + void EventUpdateAdminList(); + void EventRefreshBanList(); + +private: + QTimer m_KeepAliveTimer; + QTimer m_CallableUpdateTimer, m_AdminListUpdateTimer, m_BanListRefreshTimer; + +public: + CGHost *m_GHost; + +private: + int m_Retries; + QTcpSocket *m_Socket; // the connection to battle.net + CBNETProtocol *m_Protocol; // battle.net protocol + CBNLSClient *m_BNLSClient; // the BNLS client (for external warden handling) + QQueue m_Packets; // queue of incoming packets + CBNCSUtilInterface *m_BNCSUtil; // the interface to the bncsutil library (used for logging into battle.net) + QQueue m_OutPackets; // queue of outgoing packets to be sent (to prevent getting kicked for flooding) + QList m_SentPackages; // list of packets that have been sent (only time and size are saved) + int m_SendNoWaitMaxCount; // send the message instantly if only n messages were sent in the time window + int m_SendWindowLength; // how long the message queue should take into account messages sent earlier (in ms) + int m_ConnectionTimeout; // time in milliseconds until the connection attempt is aborted + int m_ReconnectInterval; // time in milliseconds to wait before reconnecting to bnet + QList m_Friends; // vector of friends + QList m_Clans; // vector of clan members + QList m_PairedAdminCounts; // vector of paired threaded database admin counts in progress + QList m_PairedAdminAdds; // vector of paired threaded database admin adds in progress + QList m_PairedAdminRemoves; // vector of paired threaded database admin removes in progress + QList m_PairedBanCounts; // vector of paired threaded database ban counts in progress + QList m_PairedBanAdds; // vector of paired threaded database ban adds in progress + QList m_PairedBanRemoves; // vector of paired threaded database ban removes in progress + QList m_PairedGPSChecks; // vector of paired threaded database game player summary checks in progress + QList m_PairedDPSChecks; // vector of paired threaded database DotA player summary checks in progress + CCallableAdminList *m_CallableAdminList; // threaded database admin list in progress + CCallableBanList *m_CallableBanList; // threaded database ban list in progress + QStringList m_Admins; // vector of cached admins + QStringList m_RootAdmins; // vector of rootadmins + QList m_Bans; // vector of cached bans + QString m_Server; // battle.net server to connect to + QString m_ServerIP; // battle.net server to connect to (the IP address so we don't have to resolve it every time we connect) + QString m_ServerAlias; // battle.net server alias (short name, e.g. "USEast") + QString m_BNLSServer; // BNLS server to connect to (for warden handling) + quint16 m_BNLSPort; // BNLS port + quint32 m_BNLSWardenCookie; // BNLS warden cookie + QByteArray m_CDKeyROC; // ROC CD key + QByteArray m_CDKeyTFT; // TFT CD key + QString m_CountryAbbrev; // country abbreviation + QString m_Country; // country + quint32 m_LocaleID; // see: http://msdn.microsoft.com/en-us/library/0h88fahh%28VS.85%29.aspx + QString m_UserName; // battle.net username + QString m_UserPassword; // battle.net password + QString m_FirstChannel; // the first chat channel to join upon entering chat (note: we hijack this to store the last channel when entering a game) + QString m_CurrentChannel; // the current chat channel + QString m_RootAdmin; // the root admin + char m_CommandTrigger; // the character prefix to identify commands + unsigned char m_War3Version; // custom warcraft 3 version for PvPGN users + QByteArray m_EXEVersion; // custom exe version for PvPGN users + QByteArray m_EXEVersionHash; // custom exe version hash for PvPGN users + QString m_PasswordHashType; // password hash type for PvPGN users + QString m_PVPGNRealmName; // realm name for PvPGN users (for mutual friend spoofchecks) + int m_MaxMessageLength; // maximum message length for PvPGN users + quint32 m_HostCounterID; // the host counter ID to identify players from this realm + quint32 m_LastDisconnectedTime; // GetTime when we were last disconnected from battle.net + quint32 m_LastConnectionAttemptTime; // GetTime when we last attempted to connect to battle.net + quint32 m_LastNullTime; // GetTime when the last null packet was sent for detecting disconnects + quint32 m_LastOutPacketSize; + quint32 m_LastAdminRefreshTime; // GetTime when the admin list was last refreshed from the database + quint32 m_LastBanRefreshTime; // GetTime when the ban list was last refreshed from the database + bool m_LoggedIn; // if we've logged into battle.net or not + bool m_InChat; // if we've entered chat or not (but we're not necessarily in a chat channel yet) + bool m_HoldFriends; // whether to auto hold friends when creating a game or not + bool m_HoldClan; // whether to auto hold clan members when creating a game or not + bool m_PublicCommands; // whether to allow public commands or not + + inline int getWaitTicks() + { + // this formula has changed many times but currently we wait 1 second if the last packet was "small", 3.5 seconds if it was "medium", and 4 seconds if it was "big" + if( m_LastOutPacketSize < 10 ) + return 1000; + + else if( m_LastOutPacketSize < 100 ) + return 3500; + + return 4000; + } + + QTime m_LastPacketSent; + + void ResetSocket(); + quint32 CalculateSendWaitTime(const QQueue &queue, const QList &messageLog) const; + +public slots: + void EnqueuePacket(const QByteArray &pkg); + void SendPacket(); + +public: + CBNET( CGHost *nGHost, const QString &nServer, const QString &nServerAlias, const QString &nBNLSServer, quint16 nBNLSPort, quint32 nBNLSWardenCookie, const QString &nCDKeyROC, const QString &nCDKeyTFT, const QString &nCountryAbbrev, const QString &nCountry, quint32 nLocaleID, const QString &nUserName, const QString &nUserPassword, const QString &nFirstChannel, const QString &nRootAdmin, char nCommandTrigger, bool nHoldFriends, bool nHoldClan, bool nPublicCommands, unsigned char nWar3Version, const QByteArray &nEXEVersion, const QByteArray &nEXEVersionHash, const QString &nPasswordHashType, const QString &nPVPGNRealmName, quint32 nMaxMessageLength, quint32 nHostCounterID ); + virtual ~CBNET( ); + + const QString &GetServer( ) const { return m_Server; } + const QString &GetServerAlias( ) const { return m_ServerAlias; } + QString GetCDKeyROC( ) const { return m_CDKeyROC; } + QString GetCDKeyTFT( ) const { return m_CDKeyTFT; } + const QString &GetUserName( ) const { return m_UserName; } + const QString &GetUserPassword( ) const { return m_UserPassword; } + const QString &GetFirstChannel( ) const { return m_FirstChannel; } + const QString &GetCurrentChannel( ) const { return m_CurrentChannel; } + const QString &GetRootAdmin( ) const { return m_RootAdmin; } + char GetCommandTrigger( ) const { return m_CommandTrigger; } + const QByteArray &GetEXEVersion( ) const { return m_EXEVersion; } + const QByteArray &GetEXEVersionHash( ) const { return m_EXEVersionHash; } + const QString &GetPasswordHashType( ) const { return m_PasswordHashType; } + const QString &GetPVPGNRealmName( ) const { return m_PVPGNRealmName; } + quint32 GetHostCounterID( ) const { return m_HostCounterID; } + bool GetLoggedIn( ) const { return m_LoggedIn; } + bool GetInChat( ) const { return m_InChat; } + bool GetHoldFriends( ) const { return m_HoldFriends; } + bool GetHoldClan( ) const { return m_HoldClan; } + bool GetPublicCommands( ) const { return m_PublicCommands; } + quint32 GetOutPacketsQueued( ) const { return m_OutPackets.size( ); } + const QByteArray &GetUniqueName( ) const; + + // processing functions + + void ExtractPackets( ); + void ProcessPackets( ); + void ProcessChatEvent( CIncomingChatEvent *chatEvent ); + + // functions to send packets to battle.net + + void SendJoinChannel( const QString &channel ); + void SendGetFriendsList( ); + void SendGetClanList( ); + void QueueEnterChat( ); + void QueueChatCommand( const QString &chatCommand ); + void QueueChatCommand( const QString &chatCommand, const QString &user, bool whisper ); + void QueueGameCreate( unsigned char state, const QString &gameName, const QString &hostName, CMap *map, CSaveGame *saveGame, quint32 hostCounter ); + void QueueGameRefresh( unsigned char state, const QString &gameName, const QString &hostName, CMap *map, CSaveGame *saveGame, quint32 upTime, quint32 hostCounter ); + void QueueGameUncreate( ); + + void UnqueuePackets( unsigned char type ); + void UnqueueChatCommand( const QString &chatCommand ); + void UnqueueGameRefreshes( ); + + // other functions + + bool IsAdmin( const QString &name ) const; + bool IsRootAdmin( const QString &name ) const; + CDBBan *IsBannedName( const QString &name ) const; + CDBBan *IsBannedIP( const QString &ip ) const; + void AddAdmin( const QString &name ); + void AddBan( const QString &name, const QString &ip, const QString &gamename, const QString &admin, const QString &reason ); + void RemoveAdmin( const QString &name ); + void RemoveBan( const QString &name ); + void HoldFriends( CBaseGame *game ); + void HoldClan( CBaseGame *game ); +}; + +#endif diff --git a/src/libghost/bnetprotocol.cpp b/src/libghost/bnetprotocol.cpp new file mode 100644 index 0000000..7aeead4 --- /dev/null +++ b/src/libghost/bnetprotocol.cpp @@ -0,0 +1,1167 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "bnetprotocol.h" + +CBNETProtocol :: CBNETProtocol( ) +{ + char ClientToken[] = { 220, 1, 203, 7 }; + m_ClientToken = QByteArray( (char*)ClientToken, 4 ); +} + +CBNETProtocol :: ~CBNETProtocol( ) +{ + +} + +/////////////////////// +// RECEIVE FUNCTIONS // +/////////////////////// + +bool CBNETProtocol :: RECEIVE_SID_NULL( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_NULL" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + + return ValidateLength( data ); +} + +CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_GETADVLISTEX" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> GamesFound + // if( GamesFound > 0 ) + // 10 bytes -> ??? + // 2 bytes -> Port + // 4 bytes -> IP + // null term QString -> GameName + // 2 bytes -> ??? + // 8 bytes -> HostCounter + + if( ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray GamesFound = data.mid(4, 4); + + if( Util::extractUInt32(GamesFound) > 0 && data.size( ) >= 25 ) + { + QByteArray Port = data.mid(18, 2); + QByteArray IP = data.mid(20, 4); + QByteArray GameName = UTIL_ExtractCString( data, 24 ); + + if( data.size( ) >= GameName.size( ) + 35 ) + { + QByteArray HostCounter; + HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) ); + HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) ); + HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) ); + HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) ); + return new CIncomingGameHost( IP, + Util::extractUInt16(Port), + GameName, + HostCounter ); + } + } + } + + return NULL; +} + +bool CBNETProtocol :: RECEIVE_SID_ENTERCHAT( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_ENTERCHAT" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // null terminated QString -> UniqueName + + if( ValidateLength( data ) && data.size( ) >= 5 ) + { + m_UniqueName = UTIL_ExtractCString( data, 4 ); + return true; + } + + return false; +} + +CIncomingChatEvent *CBNETProtocol :: RECEIVE_SID_CHATEVENT( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_CHATEVENT" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> EventID + // 4 bytes -> ??? + // 4 bytes -> Ping + // 12 bytes -> ??? + // null terminated QString -> User + // null terminated QString -> Message + + if( ValidateLength( data ) && data.size( ) >= 29 ) + { + QByteArray EventID = data.mid(4, 8 - 4); + QByteArray Ping = data.mid(12, 16 - 12); + QByteArray User = UTIL_ExtractCString( data, 28 ); + QByteArray Message = UTIL_ExtractCString( data, User.size( ) + 29 ); + + switch( Util::extractUInt32(EventID) ) + { + case CBNETProtocol :: EID_SHOWUSER: + case CBNETProtocol :: EID_JOIN: + case CBNETProtocol :: EID_LEAVE: + case CBNETProtocol :: EID_WHISPER: + case CBNETProtocol :: EID_TALK: + case CBNETProtocol :: EID_BROADCAST: + case CBNETProtocol :: EID_CHANNEL: + case CBNETProtocol :: EID_USERFLAGS: + case CBNETProtocol :: EID_WHISPERSENT: + case CBNETProtocol :: EID_CHANNELFULL: + case CBNETProtocol :: EID_CHANNELDOESNOTEXIST: + case CBNETProtocol :: EID_CHANNELRESTRICTED: + case CBNETProtocol :: EID_INFO: + case CBNETProtocol :: EID_ERROR: + case CBNETProtocol :: EID_EMOTE: + return new CIncomingChatEvent( (CBNETProtocol :: IncomingChatEvent)Util::extractUInt32(EventID), + Util::extractUInt32(Ping), + User, + Message ); + } + + } + + return NULL; +} + +bool CBNETProtocol :: RECEIVE_SID_CHECKAD( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_CHECKAD" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + + return ValidateLength( data ); +} + +bool CBNETProtocol :: RECEIVE_SID_STARTADVEX3( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_STARTADVEX3" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Status + + if( ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray Status = data.mid(4, 8 - 4); + + if( Util::extractUInt32(Status) == 0 ) + return true; + } + + return false; +} + +QByteArray CBNETProtocol :: RECEIVE_SID_PING( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_PING" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Ping + + if( ValidateLength( data ) && data.size( ) >= 8 ) + return data.mid(4, 8 - 4); + + return QByteArray( ); +} + +bool CBNETProtocol :: RECEIVE_SID_LOGONRESPONSE( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_LOGONRESPONSE" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Status + + if( ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray Status = data.mid(4, 8 - 4); + + if( Util::extractUInt32(Status) == 1 ) + return true; + } + + return false; +} + +bool CBNETProtocol :: RECEIVE_SID_AUTH_INFO( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_AUTH_INFO" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> LogonType + // 4 bytes -> ServerToken + // 4 bytes -> ??? + // 8 bytes -> MPQFileTime + // null terminated QString -> IX86VerFileName + // null terminated QString -> ValueStringFormula + + if( ValidateLength( data ) && data.size( ) >= 25 ) + { + m_LogonType = data.mid(4, 8 - 4); + m_ServerToken = data.mid(8, 12 - 8); + m_MPQFileTime = data.mid(16, 24 - 16); + m_IX86VerFileName = UTIL_ExtractCString( data, 24 ); + m_ValueStringFormula = UTIL_ExtractCString( data, m_IX86VerFileName.size( ) + 25 ); + return true; + } + + return false; +} + +bool CBNETProtocol :: RECEIVE_SID_AUTH_CHECK( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_AUTH_CHECK" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> KeyState + // null terminated QString -> KeyStateDescription + + if( ValidateLength( data ) && data.size( ) >= 9 ) + { + m_KeyState = data.mid(4, 8 - 4); + m_KeyStateDescription = UTIL_ExtractCString( data, 8 ); + + if( Util::extractUInt32(m_KeyState) == KR_GOOD ) + return true; + } + + return false; +} + +bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGON( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGON" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Status + // if( Status == 0 ) + // 32 bytes -> Salt + // 32 bytes -> ServerPublicKey + + if( ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray status = data.mid(4, 8 - 4); + + if( Util::extractUInt32(status) == 0 && data.size( ) >= 72 ) + { + m_Salt = data.mid(8, 40 - 8); + m_ServerPublicKey = data.mid(40, 72 - 40); + return true; + } + } + + return false; +} + +bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGONPROOF" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Status + + if( ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray Status = data.mid(4, 8 - 4); + + if( Util::extractUInt32(Status) == 0 ) + return true; + } + + return false; +} + +QByteArray CBNETProtocol :: RECEIVE_SID_WARDEN( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_WARDEN" ); + // DEBUG_PRINT( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // n bytes -> Data + + if( ValidateLength( data ) && data.size( ) >= 4 ) + return data.mid(4); + + return QByteArray( ); +} + +QList CBNETProtocol :: RECEIVE_SID_FRIENDSLIST( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_FRIENDSLIST" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 1 byte -> Total + // for( 1 .. Total ) + // null term QString -> Account + // 1 byte -> Status + // 1 byte -> Area + // 4 bytes -> ??? + // null term QString -> Location + + QList Friends; + + if( ValidateLength( data ) && data.size( ) >= 5 ) + { + unsigned int i = 5; + unsigned char Total = data[4]; + + while( Total > 0 ) + { + Total--; + + if( (unsigned int)data.size( ) < i + 1 ) + break; + + QByteArray Account = UTIL_ExtractCString( data, i ); + i += Account.size( ) + 1; + + if( (unsigned int)data.size( ) < i + 7 ) + break; + + unsigned char Status = data[i]; + unsigned char Area = data[i + 1]; + i += 6; + QByteArray Location = UTIL_ExtractCString( data, i ); + i += Location.size( ) + 1; + Friends.push_back( new CIncomingFriendList( Account, + Status, + Area, + Location ) ); + } + } + + return Friends; +} + +QList CBNETProtocol :: RECEIVE_SID_CLANMEMBERLIST( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_CLANMEMBERLIST" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> ??? + // 1 byte -> Total + // for( 1 .. Total ) + // null term QString -> Name + // 1 byte -> Rank + // 1 byte -> Status + // null term QString -> Location + + QList ClanList; + + if( ValidateLength( data ) && data.size( ) >= 9 ) + { + unsigned int i = 9; + unsigned char Total = data[8]; + + while( Total > 0 ) + { + Total--; + + if( (unsigned int)data.size( ) < i + 1 ) + break; + + QByteArray Name = UTIL_ExtractCString( data, i ); + i += Name.size( ) + 1; + + if( (unsigned int)data.size( ) < i + 3 ) + break; + + unsigned char Rank = data[i]; + unsigned char Status = data[i + 1]; + i += 2; + + // in the original VB source the location QString is read but discarded, so that's what I do here + + QByteArray Location = UTIL_ExtractCString( data, i ); + i += Location.size( ) + 1; + ClanList.push_back( new CIncomingClanList( Name, + Rank, + Status ) ); + } + } + + return ClanList; +} + +CIncomingClanList *CBNETProtocol :: RECEIVE_SID_CLANMEMBERSTATUSCHANGE( const QByteArray &data ) +{ + // DEBUG_Print( "RECEIVED SID_CLANMEMBERSTATUSCHANGE" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // null terminated QString -> Name + // 1 byte -> Rank + // 1 byte -> Status + // null terminated QString -> Location + + if( ValidateLength( data ) && data.size( ) >= 5 ) + { + QByteArray Name = UTIL_ExtractCString( data, 4 ); + + if( data.size( ) >= Name.size( ) + 7 ) + { + unsigned char Rank = data[Name.size( ) + 5]; + unsigned char Status = data[Name.size( ) + 6]; + + // in the original VB source the location QString is read but discarded, so that's what I do here + + QByteArray Location = UTIL_ExtractCString( data, Name.size( ) + 7 ); + return new CIncomingClanList( Name, + Rank, + Status ); + } + } + + return NULL; +} + +//////////////////// +// SEND FUNCTIONS // +//////////////////// + +QByteArray CBNETProtocol :: SEND_PROTOCOL_INITIALIZE_SELECTOR( ) +{ + QByteArray packet; + packet.push_back( 1 ); + // DEBUG_Print( "SENT PROTOCOL_INITIALIZE_SELECTOR" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_NULL( ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_NULL ); // SID_NULL + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + AssignLength( packet ); + // DEBUG_Print( "SENT SID_NULL" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_STOPADV( ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_STOPADV ); // SID_STOPADV + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + AssignLength( packet ); + // DEBUG_Print( "SENT SID_STOPADV" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_GETADVLISTEX( const QString &gameName ) +{ + char MapFilter1[] = { 255, 3, 0, 0 }; + char MapFilter2[] = { 255, 3, 0, 0 }; + char MapFilter3[] = { 0, 0, 0, 0 }; + char NumGames[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_GETADVLISTEX ); // SID_GETADVLISTEX + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(MapFilter1, 4)); // Map Filter + packet.append(QByteArray(MapFilter2, 4)); // Map Filter + packet.append(QByteArray(MapFilter3, 4)); // Map Filter + packet.append(QByteArray(NumGames, 4)); // maximum number of games to list + packet.append(gameName); // Game Name + packet.push_back( (char)0 ); // 0 term + packet.push_back( (char)0 ); // Game Password is NULL + packet.push_back( (char)0 ); // Game Stats is NULL + AssignLength( packet ); + // DEBUG_Print( "SENT SID_GETADVLISTEX" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_ENTERCHAT( ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_ENTERCHAT ); // SID_ENTERCHAT + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // Account Name is NULL on Warcraft III/The Frozen Throne + packet.push_back( (char)0 ); // Stat String is NULL on CDKEY'd products + AssignLength( packet ); + // DEBUG_Print( "SENT SID_ENTERCHAT" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_JOINCHANNEL( const QString &channel ) +{ + char NoCreateJoin[] = { 2, 0, 0, 0 }; + char FirstJoin[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_JOINCHANNEL ); // SID_JOINCHANNEL + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + + if( channel.size( ) > 0 ) + packet.append(QByteArray(NoCreateJoin, 4)); // flags for no create join + else + packet.append(QByteArray(FirstJoin, 4)); // flags for first join + + packet.append(channel); + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + // DEBUG_Print( "SENT SID_JOINCHANNEL" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_CHATCOMMAND( const QString &command ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_CHATCOMMAND ); // SID_CHATCOMMAND + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(command); // Message + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + // DEBUG_Print( "SENT SID_CHATCOMMAND" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_CHECKAD( ) +{ + char Zeros[] = { 0, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_CHECKAD ); // SID_CHECKAD + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(Zeros, 4)); // ??? + packet.append(QByteArray(Zeros, 4)); // ??? + packet.append(QByteArray(Zeros, 4)); // ??? + packet.append(QByteArray(Zeros, 4)); // ??? + AssignLength( packet ); + // DEBUG_Print( "SENT SID_CHECKAD" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_STARTADVEX3( + unsigned char state, + const QByteArray &mapGameType, + const QByteArray &mapFlags, + const QByteArray &mapWidth, + const QByteArray &mapHeight, + const QString &gameName, + const QString &hostName, + quint32 upTime, + const QString &mapPath, + const QByteArray &mapCRC, + const QByteArray &mapSHA1, + quint32 hostCounter ) +{ + // todotodo: sort out how GameType works, the documentation is horrendous + +/* + +Game type tag: (read W3GS_GAMEINFO for this field) + 0x00000001 - Custom + 0x00000009 - Blizzard/Ladder +Map author: (mask 0x00006000) can be combined +*0x00002000 - Blizzard + 0x00004000 - Custom +Battle type: (mask 0x00018000) cant be combined + 0x00000000 - Battle +*0x00010000 - Scenario +Map size: (mask 0x000E0000) can be combined with 2 nearest values + 0x00020000 - Small + 0x00040000 - Medium +*0x00080000 - Huge +Observers: (mask 0x00700000) cant be combined + 0x00100000 - Allowed observers + 0x00200000 - Observers on defeat +*0x00400000 - No observers +Flags: + 0x00000800 - Private game flag (not used in game list) + +*/ + + char Unknown[] = { 255, 3, 0, 0 }; + char CustomGame[] = { 0, 0, 0, 0 }; + + QString HostCounterString = QString::number(hostCounter, 16); + HostCounterString.prepend(QString(8 - HostCounterString.size(), '0')); + + QByteArray packet; + + // make the stat QString + + QByteArray StatString; + StatString.append(mapFlags); + StatString.push_back( (char)0 ); + StatString.append(mapWidth); + StatString.append(mapHeight); + StatString.append(mapCRC); + StatString.append(mapPath); + StatString.push_back( (char)0 ); // 0 term + StatString.append(hostName); + StatString.push_back( (char)0 ); // 0 term + StatString.push_back( (char)0 ); + StatString.append(mapSHA1); + StatString = UTIL_EncodeStatString( StatString ); + + if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && + !gameName.isEmpty( ) && !hostName.isEmpty( ) && !mapPath.isEmpty( ) && mapCRC.size( ) == 4 && mapSHA1.size( ) == 20 && + StatString.size( ) < 128 && HostCounterString.size( ) == 8 ) + { + // make the rest of the packet + + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_STARTADVEX3 ); // SID_STARTADVEX3 + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( state ); // State (16 = public, 17 = private, 18 = close) + packet.push_back( (char)0 ); // State continued... + packet.push_back( (char)0 ); // State continued... + packet.push_back( (char)0 ); // State continued... + packet.append(Util::fromUInt32(upTime)); // time since creation + packet.append(mapGameType); // Game Type, Parameter + packet.append(QByteArray(Unknown, 4)); // ??? + packet.append(QByteArray(CustomGame, 4)); // Custom Game + packet.append(gameName); // Game Name + packet.push_back( (char)0 ); // 0 term + packet.push_back( (char)0 ); // Game Password is NULL + packet.push_back( 98 ); // Slots Free (ascii 98 = char 'b' = 11 slots free) - note: do not reduce this as this is the # of PID's Warcraft III will allocate + packet.append(HostCounterString); // Host Counter + packet.append(StatString); // Stat String + packet.push_back( (char)0 ); // Stat String null terminator (the stat QString is encoded to remove all even numbers i.e. zeros) + AssignLength( packet ); + } + else + CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_STARTADVEX3" ); + + // DEBUG_Print( "SENT SID_STARTADVEX3" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_NOTIFYJOIN( const QString &gameName ) +{ + char ProductID[] = { 0, 0, 0, 0 }; + char ProductVersion[] = { 14, 0, 0, 0 }; // Warcraft III is 14 + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_NOTIFYJOIN ); // SID_NOTIFYJOIN + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(ProductID, 4)); // Product ID + packet.append(QByteArray(ProductVersion, 4)); // Product Version + packet.append(gameName); // Game Name + packet.push_back( (char)0 ); // 0 term + packet.push_back( (char)0 ); // Game Password is NULL + AssignLength( packet ); + // DEBUG_Print( "SENT SID_NOTIFYJOIN" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_PING( const QByteArray &pingValue ) +{ + QByteArray packet; + + if( pingValue.size( ) == 4 ) + { + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_PING ); // SID_PING + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(pingValue); // Ping Value + AssignLength( packet ); + } + else + CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_PING" ); + + // DEBUG_Print( "SENT SID_PING" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_LOGONRESPONSE( QByteArray clientToken, QByteArray serverToken, QByteArray passwordHash, QString accountName ) +{ + // todotodo: check that the passed QByteArray sizes are correct (don't know what they should be right now so I can't do this today) + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_LOGONRESPONSE ); // SID_LOGONRESPONSE + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(clientToken); // Client Token + packet.append(serverToken); // Server Token + packet.append(passwordHash); // Password Hash + packet.append(accountName); // Account Name + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + // DEBUG_Print( "SENT SID_LOGONRESPONSE" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_NETGAMEPORT( quint16 serverPort ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_NETGAMEPORT ); // SID_NETGAMEPORT + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt16(serverPort)); // local game server port + AssignLength( packet ); + // DEBUG_Print( "SENT SID_NETGAMEPORT" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_AUTH_INFO( unsigned char ver, bool TFT, quint32 localeID, QString countryAbbrev, QString country ) +{ + char ProtocolID[] = { 0, 0, 0, 0 }; + char PlatformID[] = { 54, 56, 88, 73 }; // "IX86" + char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" + char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" + char Version[] = { ver, 0, 0, 0 }; + char Language[] = { 83, 85, 110, 101 }; // "enUS" + char LocalIP[] = { 127, 0, 0, 1 }; + char TimeZoneBias[] = { 44, 1, 0, 0 }; // 300 minutes (GMT -0500) + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_AUTH_INFO ); // SID_AUTH_INFO + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(ProtocolID, 4)); // Protocol ID + packet.append(QByteArray(PlatformID, 4)); // Platform ID + + if( TFT ) + packet.append(QByteArray(ProductID_TFT, 4)); // Product ID (TFT) + else + packet.append(QByteArray(ProductID_ROC, 4)); // Product ID (ROC) + + packet.append(QByteArray(Version, 4)); // Version + packet.append(QByteArray(Language, 4)); // Language (hardcoded as enUS to ensure battle.net sends the bot messages in English) + packet.append(QByteArray(LocalIP, 4)); // Local IP for NAT compatibility + packet.append(QByteArray(TimeZoneBias, 4)); // Time Zone Bias + packet.append(Util::fromUInt32(localeID)); // Locale ID + packet.append(Util::fromUInt32(localeID)); // Language ID (copying the locale ID should be sufficient since we don't care about sublanguages) + packet.append(countryAbbrev); // Country Abbreviation + packet.push_back( (char)0 ); // 0 term + packet.append(country); // Country + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + // DEBUG_Print( "SENT SID_AUTH_INFO" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_AUTH_CHECK( bool TFT, QByteArray clientToken, QByteArray exeVersion, QByteArray exeVersionHash, QByteArray keyInfoROC, QByteArray keyInfoTFT, QString exeInfo, QString keyOwnerName ) +{ + quint32 NumKeys = 0; + + if( TFT ) + NumKeys = 2; + else + NumKeys = 1; + + QByteArray packet; + + if( clientToken.size( ) == 4 && exeVersion.size( ) == 4 && exeVersionHash.size( ) == 4 && keyInfoROC.size( ) == 36 && ( !TFT || keyInfoTFT.size( ) == 36 ) ) + { + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_AUTH_CHECK ); // SID_AUTH_CHECK + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(clientToken); // Client Token + packet.append(exeVersion); // EXE Version + packet.append(exeVersionHash); // EXE Version Hash + packet.append(Util::fromUInt32(NumKeys)); // number of keys in this packet + packet.append(Util::fromUInt32(0)); // boolean Using Spawn (32 bit) + packet.append(keyInfoROC); // ROC Key Info + + if( TFT ) + packet.append(keyInfoTFT); // TFT Key Info + + packet.append(exeInfo); // EXE Info + packet.push_back( (char)0 ); // 0 term + packet.append(keyOwnerName); // CD Key Owner Name + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + } + else + CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_CHECK" ); + + // DEBUG_Print( "SENT SID_AUTH_CHECK" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGON( QByteArray clientPublicKey, QString accountName ) +{ + QByteArray packet; + + if( clientPublicKey.size( ) == 32 ) + { + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_AUTH_ACCOUNTLOGON ); // SID_AUTH_ACCOUNTLOGON + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(clientPublicKey); // Client Key + packet.append(accountName); // Account Name + packet.push_back( (char)0 ); // 0 term + AssignLength( packet ); + } + else + CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" ); + + // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGON" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGONPROOF( QByteArray clientPasswordProof ) +{ + QByteArray packet; + + if( clientPasswordProof.size( ) == 20 ) + { + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_AUTH_ACCOUNTLOGONPROOF ); // SID_AUTH_ACCOUNTLOGONPROOF + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(clientPasswordProof); // Client Password Proof + AssignLength( packet ); + } + else + CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" ); + + // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGONPROOF" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_WARDEN( QByteArray wardenResponse ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_WARDEN ); // SID_WARDEN + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(wardenResponse); // warden response + AssignLength( packet ); + // DEBUG_Print( "SENT SID_WARDEN" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_FRIENDSLIST( ) +{ + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_FRIENDSLIST ); // SID_FRIENDSLIST + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + AssignLength( packet ); + // DEBUG_Print( "SENT SID_FRIENDSLIST" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CBNETProtocol :: SEND_SID_CLANMEMBERLIST( ) +{ + char Cookie[] = { 0, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant + packet.push_back( SID_CLANMEMBERLIST ); // SID_CLANMEMBERLIST + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(Cookie, 4)); // cookie + AssignLength( packet ); + // DEBUG_Print( "SENT SID_CLANMEMBERLIST" ); + // DEBUG_Print( packet ); + return packet; +} + +///////////////////// +// OTHER FUNCTIONS // +///////////////////// + +bool CBNETProtocol :: AssignLength( QByteArray &content ) const +{ + // insert the actual length of the content array into bytes 3 and 4 (indices 2 and 3) + + QByteArray LengthBytes; + + if( content.size( ) >= 4 && content.size( ) <= 65535 ) + { + LengthBytes = Util::fromUInt16(content.size( )); + content[2] = LengthBytes[0]; + content[3] = LengthBytes[1]; + return true; + } + + return false; +} + +bool CBNETProtocol :: ValidateLength( const QByteArray &content ) const +{ + // verify that bytes 3 and 4 (indices 2 and 3) of the content array describe the length + + quint16 Length; + QByteArray LengthBytes; + + if( content.size( ) >= 4 && content.size( ) <= 65535 ) + { + LengthBytes.push_back( content[2] ); + LengthBytes.push_back( content[3] ); + Length = Util::extractUInt16(LengthBytes); + + if( Length == content.size( ) ) + return true; + } + + return false; +} + +// +// CIncomingGameHost +// + +CIncomingGameHost :: CIncomingGameHost( QByteArray &nIP, quint16 nPort, QString nGameName, QByteArray &nHostCounter ) +{ + m_IP = nIP; + m_Port = nPort; + m_GameName = nGameName; + m_HostCounter = nHostCounter; +} + +CIncomingGameHost :: ~CIncomingGameHost( ) +{ + +} + +QString CIncomingGameHost :: GetIPString( ) +{ + QString Result; + + if( m_IP.size( ) >= 4 ) + { + for( unsigned int i = 0; i < 4; i++ ) + { + Result += QString::number( (unsigned int)m_IP[i] ); + + if( i < 3 ) + Result += "."; + } + } + + return Result; +} + +// +// CIncomingChatEvent +// + +CIncomingChatEvent :: CIncomingChatEvent( CBNETProtocol :: IncomingChatEvent nChatEvent, quint32 nPing, QString nUser, QString nMessage ) +{ + m_ChatEvent = nChatEvent; + m_Ping = nPing; + m_User = nUser; + m_Message = nMessage; +} + +CIncomingChatEvent :: ~CIncomingChatEvent( ) +{ + +} + +// +// CIncomingFriendList +// + +CIncomingFriendList :: CIncomingFriendList( QString nAccount, unsigned char nStatus, unsigned char nArea, QString nLocation ) +{ + m_Account = nAccount; + m_Status = nStatus; + m_Area = nArea; + m_Location = nLocation; +} + +CIncomingFriendList :: ~CIncomingFriendList( ) +{ + +} + +QString CIncomingFriendList :: GetDescription( ) +{ + QString Description; + Description += GetAccount( ) + "\n"; + Description += ExtractStatus( GetStatus( ) ) + "\n"; + Description += ExtractArea( GetArea( ) ) + "\n"; + Description += ExtractLocation( GetLocation( ) ) + "\n\n"; + return Description; +} + +QString CIncomingFriendList :: ExtractStatus( unsigned char status ) +{ + QString Result; + + if( status & 1 ) + Result += ""; + + if( status & 2 ) + Result += ""; + + if( status & 4 ) + Result += ""; + + if( Result.isEmpty( ) ) + Result = ""; + + return Result; +} + +QString CIncomingFriendList :: ExtractArea( unsigned char area ) +{ + switch( area ) + { + case 0: return ""; + case 1: return ""; + case 2: return ""; + case 3: return ""; + case 4: return ""; + case 5: return ""; + } + + return ""; +} + +QString CIncomingFriendList :: ExtractLocation( QString location ) +{ + QString Result; + + if( location.mid( 0, 4 ) == "PX3W" ) + Result = location.mid( 4 ); + + if( Result.isEmpty( ) ) + Result = "."; + + return Result; +} + +// +// CIncomingClanList +// + +CIncomingClanList :: CIncomingClanList( QString nName, unsigned char nRank, unsigned char nStatus ) +{ + m_Name = nName; + m_Rank = nRank; + m_Status = nStatus; +} + +CIncomingClanList :: ~CIncomingClanList( ) +{ + +} + +QString CIncomingClanList :: GetRank( ) +{ + switch( m_Rank ) + { + case 0: return "Recruit"; + case 1: return "Peon"; + case 2: return "Grunt"; + case 3: return "Shaman"; + case 4: return "Chieftain"; + } + + return "Rank Unknown"; +} + +QString CIncomingClanList :: GetStatus( ) +{ + if( m_Status == 0 ) + return "Offline"; + else + return "Online"; +} + +QString CIncomingClanList :: GetDescription( ) +{ + QString Description; + Description += GetName( ) + "\n"; + Description += GetStatus( ) + "\n"; + Description += GetRank( ) + "\n\n"; + return Description; +} diff --git a/src/libghost/bnetprotocol.h b/src/libghost/bnetprotocol.h new file mode 100644 index 0000000..081543c --- /dev/null +++ b/src/libghost/bnetprotocol.h @@ -0,0 +1,265 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef BNETPROTOCOL_H +#define BNETPROTOCOL_H + +// +// CBNETProtocol +// + +#include "includes.h" +#define BNET_HEADER_CONSTANT 255 + +class CIncomingGameHost; +class CIncomingChatEvent; +class CIncomingFriendList; +class CIncomingClanList; + +class CBNETProtocol +{ +public: + enum Protocol { + SID_NULL = 0, // 0x0 + SID_STOPADV = 2, // 0x2 + SID_GETADVLISTEX = 9, // 0x9 + SID_ENTERCHAT = 10, // 0xA + SID_JOINCHANNEL = 12, // 0xC + SID_CHATCOMMAND = 14, // 0xE + SID_CHATEVENT = 15, // 0xF + SID_CHECKAD = 21, // 0x15 + SID_STARTADVEX3 = 28, // 0x1C + SID_DISPLAYAD = 33, // 0x21 + SID_NOTIFYJOIN = 34, // 0x22 + SID_PING = 37, // 0x25 + SID_LOGONRESPONSE = 41, // 0x29 + SID_NETGAMEPORT = 69, // 0x45 + SID_AUTH_INFO = 80, // 0x50 + SID_AUTH_CHECK = 81, // 0x51 + SID_AUTH_ACCOUNTLOGON = 83, // 0x53 + SID_AUTH_ACCOUNTLOGONPROOF = 84, // 0x54 + SID_WARDEN = 94, // 0x5E + SID_FRIENDSLIST = 101, // 0x65 + SID_FRIENDSUPDATE = 102, // 0x66 + SID_CLANMEMBERLIST = 125, // 0x7D + SID_CLANMEMBERSTATUSCHANGE = 127 // 0x7F + }; + + enum KeyResult { + KR_GOOD = 0, + KR_OLD_GAME_VERSION = 256, + KR_INVALID_VERSION = 257, + KR_ROC_KEY_IN_USE = 513, + KR_TFT_KEY_IN_USE = 529 + }; + + enum IncomingChatEvent { + EID_SHOWUSER = 1, // received when you join a channel (includes users in the channel and their information) + EID_JOIN = 2, // received when someone joins the channel you're currently in + EID_LEAVE = 3, // received when someone leaves the channel you're currently in + EID_WHISPER = 4, // received a whisper message + EID_TALK = 5, // received when someone talks in the channel you're currently in + EID_BROADCAST = 6, // server broadcast + EID_CHANNEL = 7, // received when you join a channel (includes the channel's name, flags) + EID_USERFLAGS = 9, // user flags updates + EID_WHISPERSENT = 10, // sent a whisper message + EID_CHANNELFULL = 13, // channel is full + EID_CHANNELDOESNOTEXIST = 14, // channel does not exist + EID_CHANNELRESTRICTED = 15, // channel is restricted + EID_INFO = 18, // broadcast/information message + EID_ERROR = 19, // error message + EID_EMOTE = 23 // emote + }; + +private: + QByteArray m_ClientToken; // set in constructor + QByteArray m_LogonType; // set in RECEIVE_SID_AUTH_INFO + QByteArray m_ServerToken; // set in RECEIVE_SID_AUTH_INFO + QByteArray m_MPQFileTime; // set in RECEIVE_SID_AUTH_INFO + QByteArray m_IX86VerFileName; // set in RECEIVE_SID_AUTH_INFO + QByteArray m_ValueStringFormula; // set in RECEIVE_SID_AUTH_INFO + QByteArray m_KeyState; // set in RECEIVE_SID_AUTH_CHECK + QByteArray m_KeyStateDescription; // set in RECEIVE_SID_AUTH_CHECK + QByteArray m_Salt; // set in RECEIVE_SID_AUTH_ACCOUNTLOGON + QByteArray m_ServerPublicKey; // set in RECEIVE_SID_AUTH_ACCOUNTLOGON + QByteArray m_UniqueName; // set in RECEIVE_SID_ENTERCHAT + +public: + CBNETProtocol( ); + ~CBNETProtocol( ); + + const QByteArray &GetClientToken( ) { return m_ClientToken; } + const QByteArray &GetLogonType( ) { return m_LogonType; } + const QByteArray &GetServerToken( ) { return m_ServerToken; } + const QByteArray &GetMPQFileTime( ) { return m_MPQFileTime; } + const QByteArray &GetIX86VerFileName( ) { return m_IX86VerFileName; } + const QByteArray &GetIX86VerFileNameString( ) { return m_IX86VerFileName; } + const QByteArray &GetValueStringFormula( ) { return m_ValueStringFormula; } + const QByteArray &GetValueStringFormulaString( ) { return m_ValueStringFormula; } + const QByteArray &GetKeyState( ) { return m_KeyState; } + const QByteArray &GetKeyStateDescription( ) { return m_KeyStateDescription; } + const QByteArray &GetSalt( ) { return m_Salt; } + const QByteArray &GetServerPublicKey( ) { return m_ServerPublicKey; } + const QByteArray &GetUniqueName( ) { return m_UniqueName; } + + // receive functions + + bool RECEIVE_SID_NULL( const QByteArray &data ); + CIncomingGameHost *RECEIVE_SID_GETADVLISTEX( const QByteArray &data ); + bool RECEIVE_SID_ENTERCHAT( const QByteArray &data ); + CIncomingChatEvent *RECEIVE_SID_CHATEVENT( const QByteArray &data ); + bool RECEIVE_SID_CHECKAD( const QByteArray &data ); + bool RECEIVE_SID_STARTADVEX3( const QByteArray &data ); + QByteArray RECEIVE_SID_PING( const QByteArray &data ); + bool RECEIVE_SID_LOGONRESPONSE( const QByteArray &data ); + bool RECEIVE_SID_AUTH_INFO( const QByteArray &data ); + bool RECEIVE_SID_AUTH_CHECK( const QByteArray &data ); + bool RECEIVE_SID_AUTH_ACCOUNTLOGON( const QByteArray &data ); + bool RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( const QByteArray &data ); + QByteArray RECEIVE_SID_WARDEN( const QByteArray &data ); + QList RECEIVE_SID_FRIENDSLIST( const QByteArray &data ); + QList RECEIVE_SID_CLANMEMBERLIST( const QByteArray &data ); + CIncomingClanList *RECEIVE_SID_CLANMEMBERSTATUSCHANGE( const QByteArray &data ); + + // send functions + + QByteArray SEND_PROTOCOL_INITIALIZE_SELECTOR( ); + QByteArray SEND_SID_NULL( ); + QByteArray SEND_SID_STOPADV( ); + QByteArray SEND_SID_GETADVLISTEX( const QString &gameName ); + QByteArray SEND_SID_ENTERCHAT( ); + QByteArray SEND_SID_JOINCHANNEL( const QString &channel ); + QByteArray SEND_SID_CHATCOMMAND( const QString &command ); + QByteArray SEND_SID_CHECKAD( ); + QByteArray SEND_SID_STARTADVEX3( unsigned char state, const QByteArray &mapGameType, const QByteArray &mapFlags, const QByteArray &mapWidth, const QByteArray &mapHeight, const QString &gameName, const QString &hostName, quint32 upTime, const QString &mapPath, const QByteArray &mapCRC, const QByteArray &mapSHA1, quint32 hostCounter ); + QByteArray SEND_SID_NOTIFYJOIN( const QString &gameName ); + QByteArray SEND_SID_PING( const QByteArray &pingValue ); + QByteArray SEND_SID_LOGONRESPONSE( QByteArray clientToken, QByteArray serverToken, QByteArray passwordHash, QString accountName ); + QByteArray SEND_SID_NETGAMEPORT( quint16 serverPort ); + QByteArray SEND_SID_AUTH_INFO( unsigned char ver, bool TFT, quint32 localeID, QString countryAbbrev, QString country ); + QByteArray SEND_SID_AUTH_CHECK( bool TFT, QByteArray clientToken, QByteArray exeVersion, QByteArray exeVersionHash, QByteArray keyInfoROC, QByteArray keyInfoTFT, QString exeInfo, QString keyOwnerName ); + QByteArray SEND_SID_AUTH_ACCOUNTLOGON( QByteArray clientPublicKey, QString accountName ); + QByteArray SEND_SID_AUTH_ACCOUNTLOGONPROOF( QByteArray clientPasswordProof ); + QByteArray SEND_SID_WARDEN( QByteArray wardenResponse ); + QByteArray SEND_SID_FRIENDSLIST( ); + QByteArray SEND_SID_CLANMEMBERLIST( ); + + // other functions + +private: + bool AssignLength( QByteArray &content ) const; + bool ValidateLength( const QByteArray &content ) const; +}; + +// +// CIncomingGameHost +// + +class CIncomingGameHost +{ +private: + QByteArray m_IP; + quint16 m_Port; + QString m_GameName; + QByteArray m_HostCounter; + +public: + CIncomingGameHost( QByteArray &nIP, quint16 nPort, QString nGameName, QByteArray &nHostCounter ); + ~CIncomingGameHost( ); + + QByteArray GetIP( ) { return m_IP; } + QString GetIPString( ); + quint16 GetPort( ) { return m_Port; } + QString GetGameName( ) { return m_GameName; } + QByteArray GetHostCounter( ) { return m_HostCounter; } +}; + +// +// CIncomingChatEvent +// + +class CIncomingChatEvent +{ +private: + CBNETProtocol :: IncomingChatEvent m_ChatEvent; + quint32 m_Ping; + QString m_User; + QString m_Message; + +public: + CIncomingChatEvent( CBNETProtocol :: IncomingChatEvent nChatEvent, quint32 nPing, QString nUser, QString nMessage ); + ~CIncomingChatEvent( ); + + CBNETProtocol :: IncomingChatEvent GetChatEvent( ) { return m_ChatEvent; } + quint32 GetPing( ) { return m_Ping; } + QString GetUser( ) { return m_User; } + QString GetMessage( ) { return m_Message; } +}; + +// +// CIncomingFriendList +// + +class CIncomingFriendList +{ +private: + QString m_Account; + unsigned char m_Status; + unsigned char m_Area; + QString m_Location; + +public: + CIncomingFriendList( QString nAccount, unsigned char nStatus, unsigned char nArea, QString nLocation ); + ~CIncomingFriendList( ); + + QString GetAccount( ) { return m_Account; } + unsigned char GetStatus( ) { return m_Status; } + unsigned char GetArea( ) { return m_Area; } + QString GetLocation( ) { return m_Location; } + QString GetDescription( ); + +private: + QString ExtractStatus( unsigned char status ); + QString ExtractArea( unsigned char area ); + QString ExtractLocation( QString location ); +}; + +// +// CIncomingClanList +// + +class CIncomingClanList +{ +private: + QString m_Name; + unsigned char m_Rank; + unsigned char m_Status; + +public: + CIncomingClanList( QString nName, unsigned char nRank, unsigned char nStatus ); + ~CIncomingClanList( ); + + QString GetName( ) { return m_Name; } + QString GetRank( ); + QString GetStatus( ); + QString GetDescription( ); +}; + +#endif diff --git a/src/libghost/bnlsclient.cpp b/src/libghost/bnlsclient.cpp new file mode 100644 index 0000000..b26d453 --- /dev/null +++ b/src/libghost/bnlsclient.cpp @@ -0,0 +1,170 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "commandpacket.h" +#include "bnlsprotocol.h" +#include "bnlsclient.h" + +#include + +// +// CBNLSClient +// + +CBNLSClient :: CBNLSClient( QString nServer, quint16 nPort, quint32 nWardenCookie ) +{ + m_Socket = new QTcpSocket( ); + + QObject::connect(m_Socket, SIGNAL(connected()), this, SLOT(socketConnected())); + QObject::connect(m_Socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + QObject::connect(m_Socket, SIGNAL(readyRead()), this, SLOT(socketDataReady())); + QObject::connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError())); + QObject::connect(&m_NULLTimer, SIGNAL(timeout()), this, SLOT(timeout_NULL())); + + m_NULLTimer.setInterval(50000); + + m_Protocol = new CBNLSProtocol( ); + m_WasConnected = false; + m_Server = nServer; + m_Port = nPort; + m_LastNullTime = 0; + m_WardenCookie = nWardenCookie; + m_TotalWardenIn = 0; + m_TotalWardenOut = 0; + m_Retries = 0; +} + +void CBNLSClient::socketConnect() +{ + CONSOLE_Print( "[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] connecting to server [" + m_Server + "] on port " + QString::number( m_Port ) ); + m_Socket->connectToHost( QHostAddress(m_Server), m_Port ); + m_Retries++; +} + +void CBNLSClient::socketConnected() +{ + CONSOLE_Print( "[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] connected" ); + m_WasConnected = true; + m_NULLTimer.start(); +} + +void CBNLSClient::socketDisconnected() +{ + CONSOLE_Print( "[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] disconnected from BNLS server" ); + m_Socket->deleteLater(); + m_Socket = new QTcpSocket(); + + if (m_Retries > 6) + { + CONSOLE_Print("[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] giving up after 5 failed retries." ); + deleteLater(); + return; + } + + QTimer::singleShot(5000, this, SLOT(socketConnect())); + +} + +void CBNLSClient::timeout_NULL() +{ + m_Socket->write( m_Protocol->SEND_BNLS_NULL( ) ); +} + +void CBNLSClient::socketDataReady() +{ + ExtractPackets( ); + ProcessPackets( ); + + while( !m_OutPackets.isEmpty( ) ) + m_Socket->write( m_OutPackets.dequeue( ) ); +} + +void CBNLSClient::socketError() +{ + CONSOLE_Print( "[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] disconnected from BNLS server due to socket error" ); + m_Socket->deleteLater(); + m_Socket = NULL; +} + +CBNLSClient :: ~CBNLSClient( ) +{ + delete m_Socket; + delete m_Protocol; + + while( !m_Packets.isEmpty( ) ) + { + delete m_Packets.front( ); + m_Packets.dequeue( ); + } +} + +void CBNLSClient :: ExtractPackets( ) +{ + while( m_Socket->bytesAvailable() >= 3 ) + { + quint16 Length = Util::extractUInt16( m_Socket->peek(2) ); + + if( Length < 3 ) + { + CONSOLE_Print( "[BNLSC: " + m_Server + ":" + QString::number( m_Port ) + ":C" + QString::number( m_WardenCookie ) + "] error - received invalid packet from BNLS server (bad length), disconnecting" ); + m_Socket->abort(); + m_Socket->deleteLater(); + return; + } + + if( m_Socket->bytesAvailable() < Length ) + return; + + QByteArray Bytes = m_Socket->read(Length); + m_Packets.enqueue( new CCommandPacket( 0, Bytes.at(2), Bytes ) ); + } +} + +void CBNLSClient :: ProcessPackets( ) +{ + while( !m_Packets.isEmpty( ) ) + { + CCommandPacket *Packet = m_Packets.front( ); + m_Packets.dequeue( ); + + if( Packet->GetID( ) == CBNLSProtocol :: BNLS_WARDEN ) + { + QByteArray WardenResponse = m_Protocol->RECEIVE_BNLS_WARDEN( Packet->GetData( ) ); + + if( !WardenResponse.isEmpty( ) ) + emit newWardenResponse(WardenResponse); + } + + delete Packet; + } +} + +void CBNLSClient :: QueueWardenSeed( quint32 seed ) +{ + m_OutPackets.enqueue( m_Protocol->SEND_BNLS_WARDEN_SEED( m_WardenCookie, seed ) ); +} + +void CBNLSClient :: QueueWardenRaw( QByteArray wardenRaw ) +{ + m_OutPackets.enqueue( m_Protocol->SEND_BNLS_WARDEN_RAW( m_WardenCookie, wardenRaw ) ); + m_TotalWardenIn++; +} diff --git a/src/libghost/bnlsclient.h b/src/libghost/bnlsclient.h new file mode 100644 index 0000000..e729894 --- /dev/null +++ b/src/libghost/bnlsclient.h @@ -0,0 +1,83 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef BNLSCLIENT_H +#define BNLSCLIENT_H + +// +// CBNLSClient +// +#include "includes.h" +#include +#include + +class CBNLSProtocol; +class CCommandPacket; + +class CBNLSClient : public QObject +{ + Q_OBJECT + +public slots: + void socketConnected(); + void socketDisconnected(); + void socketDataReady(); + void socketConnect(); + void socketError(); + void timeout_NULL(); + +signals: + emit void newWardenResponse(const QByteArray &data); + +private: + QTimer m_NULLTimer; + QTcpSocket *m_Socket; // the connection to the BNLS server + CBNLSProtocol *m_Protocol; // battle.net protocol + QQueue m_Packets; // queue of incoming packets + bool m_WasConnected; + QString m_Server; + quint16 m_Port; + quint32 m_LastNullTime; + quint32 m_WardenCookie; // the warden cookie + QQueue m_OutPackets; // queue of outgoing packets to be sent + quint32 m_TotalWardenIn; + quint32 m_TotalWardenOut; + int m_Retries; + +public: + CBNLSClient( QString nServer, quint16 nPort, quint32 nWardenCookie ); + ~CBNLSClient( ); + + QByteArray GetWardenResponse( ); + quint32 GetTotalWardenIn( ) { return m_TotalWardenIn; } + quint32 GetTotalWardenOut( ) { return m_TotalWardenOut; } + + // processing functions + + void ExtractPackets( ); + void ProcessPackets( ); + + // other functions + + void QueueWardenSeed( quint32 seed ); + void QueueWardenRaw( QByteArray wardenRaw ); +}; + +#endif diff --git a/src/libghost/bnlsprotocol.cpp b/src/libghost/bnlsprotocol.cpp new file mode 100644 index 0000000..eef5ca1 --- /dev/null +++ b/src/libghost/bnlsprotocol.cpp @@ -0,0 +1,157 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "bnlsprotocol.h" + +CBNLSProtocol :: CBNLSProtocol( ) +{ + +} + +CBNLSProtocol :: ~CBNLSProtocol( ) +{ + +} + +/////////////////////// +// RECEIVE FUNCTIONS // +/////////////////////// + +QByteArray CBNLSProtocol :: RECEIVE_BNLS_WARDEN( QByteArray data ) +{ + // 2 bytes -> Length + // 1 byte -> ID + // (BYTE) -> Usage + // (DWORD) -> Cookie + // (BYTE) -> Result + // (WORD) -> Length of data + // (VOID) -> Data + + if( ValidateLength( data ) && data.size( ) >= 11 ) + { + //unsigned char Usage = data[3]; + //quint32 Cookie = UTIL_QByteArrayToUInt32( data, false, 4 ); + unsigned char Result = data[8]; + //quint16 Length = UTIL_QByteArrayToUInt16( data, false, 10 ); + + if( Result == 0x00 ) + return data.mid(11); + else + CONSOLE_Print( "[BNLSPROTO] received error code " + QString::number( data[8] ) ); + } + + return QByteArray( ); +} + +//////////////////// +// SEND FUNCTIONS // +//////////////////// + +QByteArray CBNLSProtocol :: SEND_BNLS_NULL( ) +{ + QByteArray packet; + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( BNLS_NULL ); // BNLS_NULL + AssignLength( packet ); + return packet; +} + +QByteArray CBNLSProtocol :: SEND_BNLS_WARDEN_SEED( quint32 cookie, quint32 seed ) +{ + char Client[] = { 80, 88, 51, 87 }; // "W3XP" + + QByteArray packet; + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( BNLS_WARDEN ); // BNLS_WARDEN + packet.push_back( (char)0 ); // BNLS_WARDEN_SEED + packet.append(Util::fromUInt32(cookie)); // cookie + packet.append(QByteArray(Client, 4)); // Client + packet.append(Util::fromUInt16(4)); // length of seed + packet.append(Util::fromUInt32(seed)); // seed + packet.push_back( (char)0 ); // username is blank + packet.append(Util::fromUInt16(0)); // password length + // password + AssignLength( packet ); + return packet; +} + +QByteArray CBNLSProtocol :: SEND_BNLS_WARDEN_RAW( quint32 cookie, QByteArray raw ) +{ + QByteArray packet; + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( BNLS_WARDEN ); // BNLS_WARDEN + packet.push_back( 1 ); // BNLS_WARDEN_RAW + packet.append(Util::fromUInt32(cookie)); // cookie + packet.append(Util::fromUInt16(raw.size( ))); // raw length + packet.append(raw); // raw + AssignLength( packet ); + return packet; +} + +QByteArray CBNLSProtocol :: SEND_BNLS_WARDEN_RUNMODULE( quint32 /*cookie*/ ) +{ + return QByteArray( ); +} + +///////////////////// +// OTHER FUNCTIONS // +///////////////////// + +bool CBNLSProtocol :: AssignLength( QByteArray &content ) +{ + // insert the actual length of the content array into bytes 1 and 2 (indices 0 and 1) + + QByteArray LengthBytes; + + if( content.size( ) >= 2 && content.size( ) <= 65535 ) + { + LengthBytes = Util::fromUInt16(content.size( )); + content[0] = LengthBytes[0]; + content[1] = LengthBytes[1]; + return true; + } + + return false; +} + +bool CBNLSProtocol :: ValidateLength( QByteArray &content ) +{ + // verify that bytes 1 and 2 (indices 0 and 1) of the content array describe the length + + quint16 Length; + QByteArray LengthBytes; + + if( content.size( ) >= 2 && content.size( ) <= 65535 ) + { + LengthBytes.push_back( content[0] ); + LengthBytes.push_back( content[1] ); + Length = Util::extractUInt16( LengthBytes ); + + if( Length == content.size( ) ) + return true; + } + + return false; +} diff --git a/ghost/bnlsprotocol.h b/src/libghost/bnlsprotocol.h similarity index 80% rename from ghost/bnlsprotocol.h rename to src/libghost/bnlsprotocol.h index d0f9f10..67681b4 100644 --- a/ghost/bnlsprotocol.h +++ b/src/libghost/bnlsprotocol.h @@ -65,20 +65,20 @@ class CBNLSProtocol // receive functions - BYTEARRAY RECEIVE_BNLS_WARDEN( BYTEARRAY data ); + QByteArray RECEIVE_BNLS_WARDEN( QByteArray data ); // send functions - BYTEARRAY SEND_BNLS_NULL( ); - BYTEARRAY SEND_BNLS_WARDEN_SEED( uint32_t cookie, uint32_t seed ); - BYTEARRAY SEND_BNLS_WARDEN_RAW( uint32_t cookie, BYTEARRAY raw ); - BYTEARRAY SEND_BNLS_WARDEN_RUNMODULE( uint32_t cookie ); + QByteArray SEND_BNLS_NULL( ); + QByteArray SEND_BNLS_WARDEN_SEED( quint32 cookie, quint32 seed ); + QByteArray SEND_BNLS_WARDEN_RAW( quint32 cookie, QByteArray raw ); + QByteArray SEND_BNLS_WARDEN_RUNMODULE( quint32 cookie ); // other functions private: - bool AssignLength( BYTEARRAY &content ); - bool ValidateLength( BYTEARRAY &content ); + bool AssignLength( QByteArray &content ); + bool ValidateLength( QByteArray &content ); }; #endif diff --git a/ghost/commandpacket.cpp b/src/libghost/commandpacket.cpp similarity index 88% rename from ghost/commandpacket.cpp rename to src/libghost/commandpacket.cpp index 9c22f74..2d19238 100644 --- a/ghost/commandpacket.cpp +++ b/src/libghost/commandpacket.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -25,7 +25,7 @@ // CCommandPacket // -CCommandPacket :: CCommandPacket( unsigned char nPacketType, int nID, BYTEARRAY nData ) +CCommandPacket :: CCommandPacket( unsigned char nPacketType, int nID, const QByteArray &nData ) { m_PacketType = nPacketType; m_ID = nID; diff --git a/ghost/commandpacket.h b/src/libghost/commandpacket.h similarity index 73% rename from ghost/commandpacket.h rename to src/libghost/commandpacket.h index dc75488..5ec7f95 100644 --- a/ghost/commandpacket.h +++ b/src/libghost/commandpacket.h @@ -30,15 +30,15 @@ class CCommandPacket private: unsigned char m_PacketType; int m_ID; - BYTEARRAY m_Data; + QByteArray m_Data; public: - CCommandPacket( unsigned char nPacketType, int nID, BYTEARRAY nData ); + CCommandPacket( unsigned char nPacketType, int nID, const QByteArray &nData ); ~CCommandPacket( ); - unsigned char GetPacketType( ) { return m_PacketType; } - int GetID( ) { return m_ID; } - BYTEARRAY GetData( ) { return m_Data; } + unsigned char GetPacketType( ) const { return m_PacketType; } + int GetID( ) const { return m_ID; } + const QByteArray &GetData( ) const { return m_Data; } }; #endif diff --git a/src/libghost/config.cpp b/src/libghost/config.cpp new file mode 100644 index 0000000..9301dd9 --- /dev/null +++ b/src/libghost/config.cpp @@ -0,0 +1,97 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "config.h" + +#include + +// +// CConfig +// + +CConfig :: CConfig( ) +{ + +} + +CConfig :: ~CConfig( ) +{ + +} + +#include +#include +void CConfig :: Read( const QString &file ) +{ + QFile f(file); + + if( !f.open(QFile::ReadOnly) ) + CONSOLE_Print( "[CONFIG] warning - unable to read file [" + file + "]" ); + else + { + CONSOLE_Print( "[CONFIG] loading file [" + file + "]" ); + QString Line; + + while( !f.atEnd() ) + { + Line = f.readLine(); + + // ignore blank lines and comments + + if( Line.isEmpty( ) || Line[0] == '#' ) + continue; + + // remove newlines and partial newlines to help fix issues with Windows formatted config files on Linux systems + + Line.replace('\r', "").replace('\n', ""); + + QStringList parts = Line.split('='); + + if (parts.size() == 2) + m_CFG[parts.at(0).trimmed()] = parts.at(1).trimmed(); + } + + f.close( ); + } +} + +bool CConfig :: Exists( const QString &key ) const +{ + return m_CFG.contains(key); +} + +int CConfig :: GetInt( const QString &key, int x ) const +{ + if( !m_CFG.contains( key ) ) + return x; + else + return m_CFG[key].toInt(); +} + +QString CConfig :: GetString( const QString &key, const QString &x ) const +{ + return m_CFG.value(key, x); +} + +void CConfig :: Set( const QString &key, const QString &x ) +{ + m_CFG[key] = x; +} diff --git a/ghost/config.h b/src/libghost/config.h similarity index 67% rename from ghost/config.h rename to src/libghost/config.h index ccd3b7f..2b4d04d 100644 --- a/ghost/config.h +++ b/src/libghost/config.h @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -28,17 +28,17 @@ class CConfig { private: - map m_CFG; + QMap m_CFG; public: CConfig( ); ~CConfig( ); - void Read( string file ); - bool Exists( string key ); - int GetInt( string key, int x ); - string GetString( string key, string x ); - void Set( string key, string x ); + void Read( const QString &file ); + bool Exists( const QString &key ) const; + int GetInt( const QString &key, int x ) const; + QString GetString( const QString &key, const QString &x ) const; + void Set( const QString &key, const QString &x ); }; #endif diff --git a/ghost/crc32.cpp b/src/libghost/crc32.cpp similarity index 64% rename from ghost/crc32.cpp rename to src/libghost/crc32.cpp index 510757c..c710395 100644 --- a/ghost/crc32.cpp +++ b/src/libghost/crc32.cpp @@ -14,9 +14,9 @@ void CCRC32 :: Initialize( ) } } -uint32_t CCRC32 :: Reflect( uint32_t ulReflect, char cChar ) +quint32 CCRC32 :: Reflect( quint32 ulReflect, char cChar ) { - uint32_t ulValue = 0; + quint32 ulValue = 0; for( int iPos = 1; iPos < ( cChar + 1 ); iPos++ ) { @@ -29,14 +29,14 @@ uint32_t CCRC32 :: Reflect( uint32_t ulReflect, char cChar ) return ulValue; } -uint32_t CCRC32 :: FullCRC( unsigned char *sData, uint32_t ulLength ) +quint32 CCRC32 :: FullCRC( const QByteArray& data ) { - uint32_t ulCRC = 0xFFFFFFFF; - PartialCRC( &ulCRC, sData, ulLength ); + quint32 ulCRC = 0xFFFFFFFF; + PartialCRC( &ulCRC, (const unsigned char*)data.data(), data.size() ); return ulCRC ^ 0xFFFFFFFF; } -void CCRC32 :: PartialCRC( uint32_t *ulInCRC, unsigned char *sData, uint32_t ulLength ) +void CCRC32 :: PartialCRC( quint32 *ulInCRC, const unsigned char *sData, quint32 ulLength ) { while( ulLength-- ) *ulInCRC = ( *ulInCRC >> 8 ) ^ ulTable[( *ulInCRC & 0xFF ) ^ *sData++]; diff --git a/src/libghost/crc32.h b/src/libghost/crc32.h new file mode 100644 index 0000000..28d75cf --- /dev/null +++ b/src/libghost/crc32.h @@ -0,0 +1,18 @@ +#ifndef CRC32_H +#define CRC32_H + +#define CRC32_POLYNOMIAL 0x04c11db7 + +class CCRC32 +{ +public: + void Initialize( ); + quint32 FullCRC( const QByteArray& data ); + void PartialCRC( quint32 *ulInCRC, const unsigned char *sData, quint32 ulLength ); + +private: + quint32 Reflect( quint32 ulReflect, char cChar ); + quint32 ulTable[256]; +}; + +#endif diff --git a/ghost/csvparser.cpp b/src/libghost/csvparser.cpp similarity index 79% rename from ghost/csvparser.cpp rename to src/libghost/csvparser.cpp index 47a2be0..99239ac 100644 --- a/ghost/csvparser.cpp +++ b/src/libghost/csvparser.cpp @@ -7,7 +7,7 @@ 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. +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 @@ -45,10 +45,10 @@ CSVParser::CSVParser() void CSVParser::SkipSpaces(void) { while (m_nPos < m_sData.length() && m_sData[m_nPos] == ' ') - m_nPos++; + m_nPos++; } -const CSVParser & CSVParser::operator <<(const string & sIn) +const CSVParser & CSVParser::operator <<(const QString & sIn) { this->m_sData = sIn; this->m_nPos = 0; @@ -64,29 +64,29 @@ const CSVParser & CSVParser::operator <<(const char *sIn) CSVParser & CSVParser::operator >>(int & nOut) { - string sTmp = ""; + QString sTmp = ""; SkipSpaces(); while (m_nPos < m_sData.length() && m_sData[m_nPos] != ',') - sTmp += m_sData[m_nPos++]; + sTmp += m_sData[m_nPos++]; m_nPos++; // skip past comma - nOut = atoi(sTmp.c_str()); + nOut = sTmp.toInt(); return *this; } CSVParser & CSVParser::operator >>(double & nOut) { - string sTmp = ""; + QString sTmp = ""; SkipSpaces(); while (m_nPos < m_sData.length() && m_sData[m_nPos] != ',') - sTmp += m_sData[m_nPos++]; + sTmp += m_sData[m_nPos++]; m_nPos++; // skip past comma - nOut = atof(sTmp.c_str()); + nOut = sTmp.toInt(); return *this; } -CSVParser & CSVParser::operator >>(string & sOut) +CSVParser & CSVParser::operator >>(QString & sOut) { bool bQuotes = false; sOut = ""; @@ -94,29 +94,29 @@ CSVParser & CSVParser::operator >>(string & sOut) // Jump past first " if necessary if (m_nPos < m_sData.length() && m_sData[m_nPos] == '"') { - bQuotes = true; - m_nPos++; + bQuotes = true; + m_nPos++; } - + while (m_nPos < m_sData.length()) { - if (!bQuotes && m_sData[m_nPos] == ',') - break; - if (bQuotes && m_sData[m_nPos] == '"') { - if (m_nPos + 1 >= m_sData.length() - 1) - break; - if (m_sData[m_nPos+1] == ',') - break; - } - sOut += m_sData[m_nPos++]; + if (!bQuotes && m_sData[m_nPos] == ',') + break; + if (bQuotes && m_sData[m_nPos] == '"') { + if (m_nPos + 1 >= m_sData.length() - 1) + break; + if (m_sData[m_nPos+1] == ',') + break; + } + sOut += m_sData[m_nPos++]; } // Jump past last " if necessary if (bQuotes && m_nPos < m_sData.length() && m_sData[m_nPos] == '"') - m_nPos++; + m_nPos++; // Jump past , if necessary if (m_nPos < m_sData.length() && m_sData[m_nPos] == ',') - m_nPos++; + m_nPos++; return *this; } diff --git a/ghost/csvparser.h b/src/libghost/csvparser.h similarity index 87% rename from ghost/csvparser.h rename to src/libghost/csvparser.h index 5c414a9..24cbe09 100644 --- a/ghost/csvparser.h +++ b/src/libghost/csvparser.h @@ -10,7 +10,7 @@ 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. +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 @@ -33,21 +33,20 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -using namespace std; +#include class CSVParser { private: - string m_sData; - string::size_type m_nPos; + QString m_sData; + int m_nPos; void SkipSpaces(void); public: CSVParser(); - const CSVParser & operator << (const string &sIn); + const CSVParser & operator << (const QString &sIn); const CSVParser & operator << (const char *sIn); CSVParser & operator >> (int &nOut); CSVParser & operator >> (double &nOut); - CSVParser & operator >> (string &sOut); + CSVParser & operator >> (QString &sOut); }; #endif diff --git a/ghost/game.cpp b/src/libghost/game.cpp similarity index 54% rename from ghost/game.cpp rename to src/libghost/game.cpp index f0c500e..024c935 100644 --- a/ghost/game.cpp +++ b/src/libghost/game.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,6 @@ #include "util.h" #include "config.h" #include "language.h" -#include "socket.h" #include "ghostdb.h" #include "bnet.h" #include "map.h" @@ -37,9 +36,16 @@ #include "statsw3mmd.h" #include -#include +#include +#include #include +#include +#include +#include +#include +#include + // // sorting classes // @@ -66,10 +72,10 @@ class CGamePlayerSortDescByPing // CGame // -CGame :: CGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nOwnerName, string nCreatorName, string nCreatorServer ) : CBaseGame( nGHost, nMap, nSaveGame, nHostPort, nGameState, nGameName, nOwnerName, nCreatorName, nCreatorServer ) +CGame :: CGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nOwnerName, QString nCreatorName, QString nCreatorServer ) : CBaseGame( nGHost, nMap, nSaveGame, nHostPort, nGameState, nGameName, nOwnerName, nCreatorName, nCreatorServer ) { m_DBBanLast = NULL; - m_DBGame = new CDBGame( 0, string( ), m_Map->GetMapPath( ), string( ), string( ), string( ), 0 ); + m_DBGame = new CDBGame( 0, QString( ), m_Map->GetMapPath( ), QString( ), QString( ), QString( ), 0 ); if( m_Map->GetMapType( ) == "w3mmd" ) m_Stats = new CStatsW3MMD( this, m_Map->GetMapStatsW3MMDCategory( ) ); @@ -81,50 +87,57 @@ CGame :: CGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHost m_CallableGameAdd = NULL; } -CGame :: ~CGame( ) +void CGame::EventGameDataSaved() { - if( m_CallableGameAdd && m_CallableGameAdd->GetReady( ) ) + if( m_CallableGameAdd->GetResult( ) > 0 ) { - if( m_CallableGameAdd->GetResult( ) > 0 ) - { - CONSOLE_Print( "[GAME: " + m_GameName + "] saving player/stats data to database" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] saving player/stats data to database" ); - // store the CDBGamePlayers in the database + // store the CDBGamePlayers in the database - for( vector :: iterator i = m_DBGamePlayers.begin( ); i != m_DBGamePlayers.end( ); i++ ) - m_GHost->m_Callables.push_back( m_GHost->m_DB->ThreadedGamePlayerAdd( m_CallableGameAdd->GetResult( ), (*i)->GetName( ), (*i)->GetIP( ), (*i)->GetSpoofed( ), (*i)->GetSpoofedRealm( ), (*i)->GetReserved( ), (*i)->GetLoadingTime( ), (*i)->GetLeft( ), (*i)->GetLeftReason( ), (*i)->GetTeam( ), (*i)->GetColour( ) ) ); + for( QList :: const_iterator i = m_DBGamePlayers.begin( ); i != m_DBGamePlayers.end( ); i++ ) + m_GHost->m_Callables.push_back( m_GHost->m_DB->ThreadedGamePlayerAdd( m_CallableGameAdd->GetResult( ), (*i)->GetName( ), (*i)->GetIP( ), (*i)->GetSpoofed( ), (*i)->GetSpoofedRealm( ), (*i)->GetReserved( ), (*i)->GetLoadingTime( ), (*i)->GetLeft( ), (*i)->GetLeftReason( ), (*i)->GetTeam( ), (*i)->GetColour( ) ) ); - // store the stats in the database + // store the stats in the database - if( m_Stats ) - m_Stats->Save( m_GHost, m_GHost->m_DB, m_CallableGameAdd->GetResult( ) ); - } - else - CONSOLE_Print( "[GAME: " + m_GameName + "] unable to save player/stats data to database" ); + if( m_Stats ) + m_Stats->Save( m_GHost, m_GHost->m_DB, m_CallableGameAdd->GetResult( ) ); + } + else + CONSOLE_Print( "[GAME: " + m_GameName + "] unable to save player/stats data to database" ); - m_GHost->m_DB->RecoverCallable( m_CallableGameAdd ); + m_GHost->m_DB->RecoverCallable( m_CallableGameAdd ); + delete m_CallableGameAdd; + m_CallableGameAdd = NULL; + deleteLater(); +} + +CGame :: ~CGame( ) +{ + if (m_CallableGameAdd != NULL) + { delete m_CallableGameAdd; m_CallableGameAdd = NULL; } - for( vector :: iterator i = m_PairedBanChecks.begin( ); i != m_PairedBanChecks.end( ); i++ ) + for( QList :: const_iterator i = m_PairedBanChecks.begin( ); i != m_PairedBanChecks.end( ); i++ ) m_GHost->m_Callables.push_back( i->second ); - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) + for( QList :: const_iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) m_GHost->m_Callables.push_back( i->second ); - for( vector :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); i++ ) + for( QList :: const_iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); i++ ) m_GHost->m_Callables.push_back( i->second ); - for( vector :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); i++ ) + for( QList :: const_iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); i++ ) m_GHost->m_Callables.push_back( i->second ); - for( vector :: iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) + for( QList :: const_iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) delete *i; delete m_DBGame; - for( vector :: iterator i = m_DBGamePlayers.begin( ); i != m_DBGamePlayers.end( ); i++ ) + for( QList :: const_iterator i = m_DBGamePlayers.begin( ); i != m_DBGamePlayers.end( ); i++ ) delete *i; delete m_Stats; @@ -141,20 +154,20 @@ CGame :: ~CGame( ) } } -bool CGame :: Update( void *fd, void *send_fd ) +void CGame::EventCallableUpdateTimeout() { // update callables - for( vector :: iterator i = m_PairedBanChecks.begin( ); i != m_PairedBanChecks.end( ); ) + for( QList :: iterator i = m_PairedBanChecks.begin( ); i != m_PairedBanChecks.end( ); ) { if( i->second->GetReady( ) ) { CDBBan *Ban = i->second->GetResult( ); if( Ban ) - SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( i->second->GetServer( ), i->second->GetUser( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( i->second->GetServer( ), i->second->GetUser( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); else - SendAllChat( m_GHost->m_Language->UserIsNotBanned( i->second->GetServer( ), i->second->GetUser( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserIsNotBanned( i->second->GetServer( ), i->second->GetUser( ) ) ); m_GHost->m_DB->RecoverCallable( i->second ); delete i->second; @@ -164,19 +177,19 @@ bool CGame :: Update( void *fd, void *send_fd ) i++; } - for( vector :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) + for( QList :: iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) { if( i->second->GetReady( ) ) { if( i->second->GetResult( ) ) { - for( vector :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) + for( QList :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) { if( (*j)->GetServer( ) == i->second->GetServer( ) ) (*j)->AddBan( i->second->GetUser( ), i->second->GetIP( ), i->second->GetGameName( ), i->second->GetAdmin( ), i->second->GetReason( ) ); } - SendAllChat( m_GHost->m_Language->PlayerWasBannedByPlayer( i->second->GetServer( ), i->second->GetUser( ), i->first ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerWasBannedByPlayer( i->second->GetServer( ), i->second->GetUser( ), i->first ) ); } m_GHost->m_DB->RecoverCallable( i->second ); @@ -187,7 +200,7 @@ bool CGame :: Update( void *fd, void *send_fd ) i++; } - for( vector :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); ) + for( QList :: iterator i = m_PairedGPSChecks.begin( ); i != m_PairedGPSChecks.end( ); ) { if( i->second->GetReady( ) ) { @@ -195,26 +208,26 @@ bool CGame :: Update( void *fd, void *send_fd ) if( GamePlayerSummary ) { - if( i->first.empty( ) ) - SendAllChat( m_GHost->m_Language->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), UTIL_ToString( GamePlayerSummary->GetTotalGames( ) ), UTIL_ToString( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 2 ), UTIL_ToString( GamePlayerSummary->GetAvgLeftPercent( ) ) ) ); + if( i->first.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), QString::number( GamePlayerSummary->GetTotalGames( ) ), QString::number( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 'g', 2 ), QString::number( GamePlayerSummary->GetAvgLeftPercent( ) ) ) ); else { CGamePlayer *Player = GetPlayerFromName( i->first, true ); if( Player ) - SendChat( Player, m_GHost->m_Language->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), UTIL_ToString( GamePlayerSummary->GetTotalGames( ) ), UTIL_ToString( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 2 ), UTIL_ToString( GamePlayerSummary->GetAvgLeftPercent( ) ) ) ); + SendChat( Player, m_GHost->GetLanguage( )->HasPlayedGamesWithThisBot( i->second->GetName( ), GamePlayerSummary->GetFirstGameDateTime( ), GamePlayerSummary->GetLastGameDateTime( ), QString::number( GamePlayerSummary->GetTotalGames( ) ), QString::number( (float)GamePlayerSummary->GetAvgLoadingTime( ) / 1000, 'g', 2 ), QString::number( GamePlayerSummary->GetAvgLeftPercent( ) ) ) ); } } else { - if( i->first.empty( ) ) - SendAllChat( m_GHost->m_Language->HasntPlayedGamesWithThisBot( i->second->GetName( ) ) ); + if( i->first.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->HasntPlayedGamesWithThisBot( i->second->GetName( ) ) ); else { CGamePlayer *Player = GetPlayerFromName( i->first, true ); if( Player ) - SendChat( Player, m_GHost->m_Language->HasntPlayedGamesWithThisBot( i->second->GetName( ) ) ); + SendChat( Player, m_GHost->GetLanguage( )->HasntPlayedGamesWithThisBot( i->second->GetName( ) ) ); } } @@ -226,7 +239,7 @@ bool CGame :: Update( void *fd, void *send_fd ) i++; } - for( vector :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); ) + for( QList :: iterator i = m_PairedDPSChecks.begin( ); i != m_PairedDPSChecks.end( ); ) { if( i->second->GetReady( ) ) { @@ -234,30 +247,30 @@ bool CGame :: Update( void *fd, void *send_fd ) if( DotAPlayerSummary ) { - string Summary = m_GHost->m_Language->HasPlayedDotAGamesWithThisBot( i->second->GetName( ), - UTIL_ToString( DotAPlayerSummary->GetTotalGames( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalWins( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalLosses( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalDeaths( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCreepKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCreepDenies( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalAssists( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalNeutralKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalTowerKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalRaxKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetTotalCourierKills( ) ), - UTIL_ToString( DotAPlayerSummary->GetAvgKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgDeaths( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCreepKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCreepDenies( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgAssists( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgNeutralKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgTowerKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgRaxKills( ), 2 ), - UTIL_ToString( DotAPlayerSummary->GetAvgCourierKills( ), 2 ) ); - - if( i->first.empty( ) ) + QString Summary = m_GHost->GetLanguage( )->HasPlayedDotAGamesWithThisBot( i->second->GetName( ), + QString::number( DotAPlayerSummary->GetTotalGames( ) ), + QString::number( DotAPlayerSummary->GetTotalWins( ) ), + QString::number( DotAPlayerSummary->GetTotalLosses( ) ), + QString::number( DotAPlayerSummary->GetTotalKills( ) ), + QString::number( DotAPlayerSummary->GetTotalDeaths( ) ), + QString::number( DotAPlayerSummary->GetTotalCreepKills( ) ), + QString::number( DotAPlayerSummary->GetTotalCreepDenies( ) ), + QString::number( DotAPlayerSummary->GetTotalAssists( ) ), + QString::number( DotAPlayerSummary->GetTotalNeutralKills( ) ), + QString::number( DotAPlayerSummary->GetTotalTowerKills( ) ), + QString::number( DotAPlayerSummary->GetTotalRaxKills( ) ), + QString::number( DotAPlayerSummary->GetTotalCourierKills( ) ), + QString::number( DotAPlayerSummary->GetAvgKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgDeaths( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCreepKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCreepDenies( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgAssists( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgNeutralKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgTowerKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgRaxKills( ), 'g', 2 ), + QString::number( DotAPlayerSummary->GetAvgCourierKills( ), 'g', 2 ) ); + + if( i->first.isEmpty( ) ) SendAllChat( Summary ); else { @@ -269,14 +282,14 @@ bool CGame :: Update( void *fd, void *send_fd ) } else { - if( i->first.empty( ) ) - SendAllChat( m_GHost->m_Language->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ) ); + if( i->first.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ) ); else { CGamePlayer *Player = GetPlayerFromName( i->first, true ); if( Player ) - SendChat( Player, m_GHost->m_Language->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ) ); + SendChat( Player, m_GHost->GetLanguage( )->HasntPlayedDotAGamesWithThisBot( i->second->GetName( ) ) ); } } @@ -288,12 +301,13 @@ bool CGame :: Update( void *fd, void *send_fd ) i++; } - return CBaseGame :: Update( fd, send_fd ); + return CBaseGame::EventCallableUpdateTimeout(); } -void CGame :: EventPlayerDeleted( CGamePlayer *player ) +void CGame :: EventPlayerDeleted() { - CBaseGame :: EventPlayerDeleted( player ); + CGamePlayer *player = (CGamePlayer*)QObject::sender(); + CBaseGame :: EventPlayerDeleted(); // record everything we need to know about the player for storing in the database later // since we haven't stored the game yet (it's not over yet!) we can't link the gameplayer to the game @@ -319,7 +333,7 @@ void CGame :: EventPlayerDeleted( CGamePlayer *player ) // also keep track of the last player to leave for the !banlast command - for( vector :: iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) + for( QList :: const_iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) { if( (*i)->GetName( ) == player->GetName( ) ) m_DBBanLast = *i; @@ -333,27 +347,27 @@ void CGame :: EventPlayerAction( CGamePlayer *player, CIncomingAction *action ) // give the stats class a chance to process the action - if( m_Stats && m_Stats->ProcessAction( action ) && m_GameOverTime == 0 ) + if( m_Stats && m_Stats->ProcessAction( action ) && !m_GameOverTimer.isActive() ) { CONSOLE_Print( "[GAME: " + m_GameName + "] gameover timer started (stats class reported game over)" ); SendEndMessage( ); - m_GameOverTime = GetTime( ); + m_GameOverTimer.start(); } } -bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string payload ) +bool CGame :: EventPlayerBotCommand( CGamePlayer *player, QString command, QString payload ) { bool HideCommand = CBaseGame :: EventPlayerBotCommand( player, command, payload ); // todotodo: don't be lazy - string User = player->GetName( ); - string Command = command; - string Payload = payload; + QString User = player->GetName( ); + QString Command = command; + QString Payload = payload; bool AdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == player->GetSpoofedRealm( ) && (*i)->IsAdmin( User ) ) { @@ -364,7 +378,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string bool RootAdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == player->GetSpoofedRealm( ) && (*i)->IsRootAdmin( User ) ) { @@ -392,7 +406,8 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( ( Command == "abort" || Command == "a" ) && m_CountDownStarted && !m_GameLoading && !m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->CountDownAborted( ) ); + SendAllChat( m_GHost->GetLanguage( )->CountDownAborted( ) ); + m_CountdownTimer.stop(); m_CountDownStarted = false; } @@ -401,42 +416,40 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !BAN // - if( ( Command == "addban" || Command == "ban" ) && !Payload.empty( ) && !m_GHost->m_BNETs.empty( ) ) + if( ( Command == "addban" || Command == "ban" ) && !Payload.isEmpty( ) && !m_GHost->m_BNETs.isEmpty( ) ) { // extract the victim and the reason // e.g. "Varlock leaver after dying" -> victim: "Varlock", reason: "leaver after dying" - string Victim; - string Reason; - stringstream SS; - SS << Payload; + QString Victim; + QString Reason; + QTextStream SS(&Payload); + SS >> Victim; - if( !SS.eof( ) ) + if( !SS.atEnd( ) ) { - getline( SS, Reason ); - string :: size_type Start = Reason.find_first_not_of( " " ); + Reason = SS.readLine(); + int Start = Reason.indexOf( QRegExp( "[^ ]" )); - if( Start != string :: npos ) - Reason = Reason.substr( Start ); + if( Start != -1 ) + Reason = Reason.mid( Start ); } if( m_GameLoaded ) { - string VictimLower = Victim; - transform( VictimLower.begin( ), VictimLower.end( ), VictimLower.begin( ), (int(*)(int))tolower ); - uint32_t Matches = 0; + QString VictimLower = Victim.toLower(); + quint32 Matches = 0; CDBBan *LastMatch = NULL; - // try to match each player with the passed string (e.g. "Varlock" would be matched with "lock") + // try to match each player with the passed QString (e.g. "Varlock" would be matched with "lock") // we use the m_DBBans vector for this in case the player already left and thus isn't in the m_Players vector anymore - for( vector :: iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) + for( QList :: const_iterator i = m_DBBans.begin( ); i != m_DBBans.end( ); i++ ) { - string TestName = (*i)->GetName( ); - transform( TestName.begin( ), TestName.end( ), TestName.begin( ), (int(*)(int))tolower ); + QString TestName = (*i)->GetName( ).toLower(); - if( TestName.find( VictimLower ) != string :: npos ) + if( TestName.indexOf( VictimLower ) != -1 ) { Matches++; LastMatch = *i; @@ -452,23 +465,23 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToBanNoMatchesFound( Victim ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToBanNoMatchesFound( Victim ) ); else if( Matches == 1 ) m_PairedBanAdds.push_back( PairedBanAdd( User, m_GHost->m_DB->ThreadedBanAdd( LastMatch->GetServer( ), LastMatch->GetName( ), LastMatch->GetIP( ), m_GameName, User, Reason ) ) ); else - SendAllChat( m_GHost->m_Language->UnableToBanFoundMoreThanOneMatch( Victim ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToBanFoundMoreThanOneMatch( Victim ) ); } else { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Victim, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Victim, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToBanNoMatchesFound( Victim ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToBanNoMatchesFound( Victim ) ); else if( Matches == 1 ) m_PairedBanAdds.push_back( PairedBanAdd( User, m_GHost->m_DB->ThreadedBanAdd( LastMatch->GetJoinedRealm( ), LastMatch->GetName( ), LastMatch->GetExternalIPString( ), m_GameName, User, Reason ) ) ); else - SendAllChat( m_GHost->m_Language->UnableToBanFoundMoreThanOneMatch( Victim ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToBanFoundMoreThanOneMatch( Victim ) ); } } @@ -478,37 +491,37 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "announce" && !m_CountDownStarted ) { - if( Payload.empty( ) || Payload == "off" ) + if( Payload.isEmpty( ) || Payload == "off" ) { - SendAllChat( m_GHost->m_Language->AnnounceMessageDisabled( ) ); - SetAnnounce( 0, string( ) ); + SendAllChat( m_GHost->GetLanguage( )->AnnounceMessageDisabled( ) ); + SetAnnounce( 0, QString( ) ); } else { // extract the interval and the message // e.g. "30 hello everyone" -> interval: "30", message: "hello everyone" - uint32_t Interval; - string Message; - stringstream SS; - SS << Payload; + quint32 Interval; + QString Message; + QTextStream SS(&Payload); + SS >> Interval; - if( SS.fail( ) || Interval == 0 ) + if( SS.status() != QTextStream::Ok || Interval == 0 ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to announce command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to announce command" ); else { - getline( SS, Message ); - string :: size_type Start = Message.find_first_not_of( " " ); + Message = SS.readLine(); + int Start = Message.indexOf( QRegExp( "[^ ]" )); - if( Start != string :: npos ) - Message = Message.substr( Start ); + if( Start != -1 ) + Message = Message.mid( Start ); - SendAllChat( m_GHost->m_Language->AnnounceMessageEnabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->AnnounceMessageEnabled( ) ); SetAnnounce( Interval, Message ); } } @@ -523,12 +536,12 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { if( Payload == "on" ) { - SendAllChat( m_GHost->m_Language->AutoSaveEnabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->AutoSaveEnabled( ) ); m_AutoSave = true; } else if( Payload == "off" ) { - SendAllChat( m_GHost->m_Language->AutoSaveDisabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->AutoSaveDisabled( ) ); m_AutoSave = false; } } @@ -539,18 +552,18 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "autostart" && !m_CountDownStarted ) { - if( Payload.empty( ) || Payload == "off" ) + if( Payload.isEmpty( ) || Payload == "off" ) { - SendAllChat( m_GHost->m_Language->AutoStartDisabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->AutoStartDisabled( ) ); m_AutoStartPlayers = 0; } else { - uint32_t AutoStartPlayers = UTIL_ToUInt32( Payload ); + quint32 AutoStartPlayers = Payload.toUInt(); if( AutoStartPlayers != 0 ) { - SendAllChat( m_GHost->m_Language->AutoStartEnabled( UTIL_ToString( AutoStartPlayers ) ) ); + SendAllChat( m_GHost->GetLanguage( )->AutoStartEnabled( QString::number( AutoStartPlayers ) ) ); m_AutoStartPlayers = AutoStartPlayers; } } @@ -560,7 +573,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !BANLAST // - if( Command == "banlast" && m_GameLoaded && !m_GHost->m_BNETs.empty( ) && m_DBBanLast ) + if( Command == "banlast" && m_GameLoaded && !m_GHost->m_BNETs.isEmpty( ) && m_DBBanLast ) m_PairedBanAdds.push_back( PairedBanAdd( User, m_GHost->m_DB->ThreadedBanAdd( m_DBBanLast->GetServer( ), m_DBBanLast->GetName( ), m_DBBanLast->GetIP( ), m_GameName, User, Payload ) ) ); // @@ -569,18 +582,18 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "check" ) { - if( !Payload.empty( ) ) + if( !Payload.isEmpty( ) ) { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToCheckPlayerNoMatchesFound( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToCheckPlayerNoMatchesFound( Payload ) ); else if( Matches == 1 ) { bool LastMatchAdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == LastMatch->GetSpoofedRealm( ) && (*i)->IsAdmin( LastMatch->GetName( ) ) ) { @@ -591,7 +604,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string bool LastMatchRootAdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == LastMatch->GetSpoofedRealm( ) && (*i)->IsRootAdmin( LastMatch->GetName( ) ) ) { @@ -600,23 +613,23 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } } - SendAllChat( m_GHost->m_Language->CheckedPlayer( LastMatch->GetName( ), LastMatch->GetNumPings( ) > 0 ? UTIL_ToString( LastMatch->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( UTIL_ByteArrayToUInt32( LastMatch->GetExternalIP( ), true ) ), LastMatchAdminCheck || LastMatchRootAdminCheck ? "Yes" : "No", IsOwner( LastMatch->GetName( ) ) ? "Yes" : "No", LastMatch->GetSpoofed( ) ? "Yes" : "No", LastMatch->GetSpoofedRealm( ).empty( ) ? "N/A" : LastMatch->GetSpoofedRealm( ), LastMatch->GetReserved( ) ? "Yes" : "No" ) ); + SendAllChat( m_GHost->GetLanguage( )->CheckedPlayer( LastMatch->GetName( ), LastMatch->GetNumPings( ) > 0 ? QString::number( LastMatch->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( Util::extractUInt32( Util::reverse(LastMatch->GetExternalIP( )) ) ), LastMatchAdminCheck || LastMatchRootAdminCheck ? "Yes" : "No", IsOwner( LastMatch->GetName( ) ) ? "Yes" : "No", LastMatch->GetSpoofed( ) ? "Yes" : "No", LastMatch->GetSpoofedRealm( ).isEmpty( ) ? "N/A" : LastMatch->GetSpoofedRealm( ), LastMatch->GetReserved( ) ? "Yes" : "No" ) ); } else - SendAllChat( m_GHost->m_Language->UnableToCheckPlayerFoundMoreThanOneMatch( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToCheckPlayerFoundMoreThanOneMatch( Payload ) ); } else - SendAllChat( m_GHost->m_Language->CheckedPlayer( User, player->GetNumPings( ) > 0 ? UTIL_ToString( player->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( UTIL_ByteArrayToUInt32( player->GetExternalIP( ), true ) ), AdminCheck || RootAdminCheck ? "Yes" : "No", IsOwner( User ) ? "Yes" : "No", player->GetSpoofed( ) ? "Yes" : "No", player->GetSpoofedRealm( ).empty( ) ? "N/A" : player->GetSpoofedRealm( ), player->GetReserved( ) ? "Yes" : "No" ) ); + SendAllChat( m_GHost->GetLanguage( )->CheckedPlayer( User, player->GetNumPings( ) > 0 ? QString::number( player->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( Util::extractUInt32(Util::reverse(player->GetExternalIP( ))) ), AdminCheck || RootAdminCheck ? "Yes" : "No", IsOwner( User ) ? "Yes" : "No", player->GetSpoofed( ) ? "Yes" : "No", player->GetSpoofedRealm( ).isEmpty( ) ? "N/A" : player->GetSpoofedRealm( ), player->GetReserved( ) ? "Yes" : "No" ) ); } // // !CHECKBAN // - if( Command == "checkban" && !Payload.empty( ) && !m_GHost->m_BNETs.empty( ) ) + if( Command == "checkban" && !Payload.isEmpty( ) && !m_GHost->m_BNETs.isEmpty( ) ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - m_PairedBanChecks.push_back( PairedBanCheck( User, m_GHost->m_DB->ThreadedBanCheck( (*i)->GetServer( ), Payload, string( ) ) ) ); + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + m_PairedBanChecks.push_back( PairedBanCheck( User, m_GHost->m_DB->ThreadedBanCheck( (*i)->GetServer( ), Payload, QString( ) ) ) ); } // @@ -626,26 +639,26 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "clearhcl" && !m_CountDownStarted ) { m_HCLCommandString.clear( ); - SendAllChat( m_GHost->m_Language->ClearingHCL( ) ); + SendAllChat( m_GHost->GetLanguage( )->ClearingHCL( ) ); } // // !CLOSE (close slot) // - if( Command == "close" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded ) + if( Command == "close" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded ) { // close as many slots as specified, e.g. "5 10" closes slots 5 and 10 - stringstream SS; - SS << Payload; + QTextStream SS(&Payload); - while( !SS.eof( ) ) + + while( !SS.atEnd( ) ) { - uint32_t SID; + quint32 SID; SS >> SID; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) { CONSOLE_Print( "[GAME: " + m_GameName + "] bad input to close command" ); break; @@ -666,25 +679,25 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !COMP (computer slot) // - if( Command == "comp" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) + if( Command == "comp" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) { // extract the slot and the skill // e.g. "1 2" -> slot: "1", skill: "2" - uint32_t Slot; - uint32_t Skill = 1; - stringstream SS; - SS << Payload; + quint32 Slot; + quint32 Skill = 1; + QTextStream SS(&Payload); + SS >> Slot; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to comp command" ); else { - if( !SS.eof( ) ) + if( !SS.atEnd( ) ) SS >> Skill; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #2 to comp command" ); else ComputerSlot( (unsigned char)( Slot - 1 ), (unsigned char)Skill, true ); @@ -695,28 +708,28 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !COMPCOLOUR (computer colour change) // - if( Command == "compcolour" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) + if( Command == "compcolour" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) { // extract the slot and the colour // e.g. "1 2" -> slot: "1", colour: "2" - uint32_t Slot; - uint32_t Colour; - stringstream SS; - SS << Payload; + quint32 Slot; + quint32 Colour; + QTextStream SS(&Payload); + SS >> Slot; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to compcolour command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to compcolour command" ); else { SS >> Colour; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #2 to compcolour command" ); else { @@ -736,28 +749,28 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !COMPHANDICAP (computer handicap change) // - if( Command == "comphandicap" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) + if( Command == "comphandicap" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) { // extract the slot and the handicap // e.g. "1 50" -> slot: "1", handicap: "50" - uint32_t Slot; - uint32_t Handicap; - stringstream SS; - SS << Payload; + quint32 Slot; + quint32 Handicap; + QTextStream SS(&Payload); + SS >> Slot; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to comphandicap command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to comphandicap command" ); else { SS >> Handicap; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #2 to comphandicap command" ); else { @@ -780,32 +793,31 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !COMPRACE (computer race change) // - if( Command == "comprace" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) + if( Command == "comprace" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) { // extract the slot and the race // e.g. "1 human" -> slot: "1", race: "human" - uint32_t Slot; - string Race; - stringstream SS; - SS << Payload; + quint32 Slot; + QString Race; + QTextStream SS(&Payload); + SS >> Slot; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to comprace command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to comprace command" ); else { - getline( SS, Race ); - string :: size_type Start = Race.find_first_not_of( " " ); + Race = SS.readLine().toLower(); + int Start = Race.indexOf( QRegExp( "[^ ]" )); - if( Start != string :: npos ) - Race = Race.substr( Start ); + if( Start != -1 ) + Race = Race.mid( Start ); - transform( Race.begin( ), Race.end( ), Race.begin( ), (int(*)(int))tolower ); unsigned char SID = (unsigned char)( Slot - 1 ); if( !( m_Map->GetMapOptions( ) & MAPOPT_FIXEDPLAYERSETTINGS ) && !( m_Map->GetMapFlags( ) & MAPFLAG_RANDOMRACES ) && SID < m_Slots.size( ) ) @@ -849,28 +861,28 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !COMPTEAM (computer team change) // - if( Command == "compteam" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) + if( Command == "compteam" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded && !m_SaveGame ) { // extract the slot and the team // e.g. "1 2" -> slot: "1", team: "2" - uint32_t Slot; - uint32_t Team; - stringstream SS; - SS << Payload; + quint32 Slot; + quint32 Team; + QTextStream SS(&Payload); + SS >> Slot; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to compteam command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to compteam command" ); else { SS >> Team; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #2 to compteam command" ); else { @@ -901,13 +913,13 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !DL // - if( ( Command == "download" || Command == "dl" ) && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded ) + if( ( Command == "download" || Command == "dl" ) && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded ) { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToStartDownloadNoMatchesFound( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToStartDownloadNoMatchesFound( Payload ) ); else if( Matches == 1 ) { if( !LastMatch->GetDownloadStarted( ) && !LastMatch->GetDownloadFinished( ) ) @@ -927,7 +939,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } } else - SendAllChat( m_GHost->m_Language->UnableToStartDownloadFoundMoreThanOneMatch( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToStartDownloadFoundMoreThanOneMatch( Payload ) ); } // @@ -945,6 +957,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { CONSOLE_Print( "[GAME: " + m_GameName + "] is over (admin ended game)" ); StopPlayers( "was disconnected (admin ended game)" ); + deleteLater(); } // @@ -965,10 +978,10 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "fppause" && m_FakePlayerPID != 255 && m_GameLoaded ) { - BYTEARRAY CRC; - BYTEARRAY Action; + QByteArray CRC; + QByteArray Action; Action.push_back( 1 ); - m_Actions.push( new CIncomingAction( m_FakePlayerPID, CRC, Action ) ); + m_Actions.enqueue( new CIncomingAction( m_FakePlayerPID, CRC, Action ) ); } // @@ -977,10 +990,10 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "fpresume" && m_FakePlayerPID != 255 && m_GameLoaded ) { - BYTEARRAY CRC; - BYTEARRAY Action; + QByteArray CRC; + QByteArray Action; Action.push_back( 2 ); - m_Actions.push( new CIncomingAction( m_FakePlayerPID, CRC, Action ) ); + m_Actions.enqueue( new CIncomingAction( m_FakePlayerPID, CRC, Action ) ); } // @@ -989,15 +1002,15 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "from" ) { - string Froms; + QString Froms; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { // we reverse the byte order on the IP because it's stored in network byte order Froms += (*i)->GetNameTerminated( ); Froms += ": ("; - Froms += m_GHost->m_DBLocal->FromCheck( UTIL_ByteArrayToUInt32( (*i)->GetExternalIP( ), true ) ); + Froms += m_GHost->m_DBLocal->FromCheck( Util::extractUInt32(Util::reverse((*i)->GetExternalIP( ))) ); Froms += ")"; if( i != m_Players.end( ) - 1 ) @@ -1012,7 +1025,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } } - if( !Froms.empty( ) ) + if( !Froms.isEmpty( ) ) SendAllChat( Froms ); } @@ -1022,51 +1035,51 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "hcl" && !m_CountDownStarted ) { - if( !Payload.empty( ) ) + if( !Payload.isEmpty( ) ) { if( Payload.size( ) <= m_Slots.size( ) ) { - string HCLChars = "abcdefghijklmnopqrstuvwxyz0123456789 -=,."; + QString HCLChars = "abcdefghijklmnopqrstuvwxyz0123456789 -=,."; - if( Payload.find_first_not_of( HCLChars ) == string :: npos ) + if( Payload.indexOf( QRegExp("[^" + HCLChars + "]") ) == -1 ) { m_HCLCommandString = Payload; - SendAllChat( m_GHost->m_Language->SettingHCL( m_HCLCommandString ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingHCL( m_HCLCommandString ) ); } else - SendAllChat( m_GHost->m_Language->UnableToSetHCLInvalid( ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToSetHCLInvalid( ) ); } else - SendAllChat( m_GHost->m_Language->UnableToSetHCLTooLong( ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToSetHCLTooLong( ) ); } else - SendAllChat( m_GHost->m_Language->TheHCLIs( m_HCLCommandString ) ); + SendAllChat( m_GHost->GetLanguage( )->TheHCLIs( m_HCLCommandString ) ); } // // !HOLD (hold a slot for someone) // - if( Command == "hold" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded ) + if( Command == "hold" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded ) { // hold as many players as specified, e.g. "Varlock Kilranin" holds players "Varlock" and "Kilranin" - stringstream SS; - SS << Payload; + QTextStream SS(&Payload); - while( !SS.eof( ) ) + + while( !SS.atEnd( ) ) { - string HoldName; + QString HoldName; SS >> HoldName; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) { CONSOLE_Print( "[GAME: " + m_GameName + "] bad input to hold command" ); break; } else { - SendAllChat( m_GHost->m_Language->AddedPlayerToTheHoldList( HoldName ) ); + SendAllChat( m_GHost->GetLanguage( )->AddedPlayerToTheHoldList( HoldName ) ); AddToReserved( HoldName ); } } @@ -1076,28 +1089,28 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !KICK (kick a player) // - if( Command == "kick" && !Payload.empty( ) ) + if( Command == "kick" && !Payload.isEmpty( ) ) { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToKickNoMatchesFound( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToKickNoMatchesFound( Payload ) ); else if( Matches == 1 ) { - LastMatch->SetDeleteMe( true ); - LastMatch->SetLeftReason( m_GHost->m_Language->WasKickedByPlayer( User ) ); + LastMatch->SetLeftReason( m_GHost->GetLanguage( )->WasKickedByPlayer( User ) ); if( !m_GameLoading && !m_GameLoaded ) LastMatch->SetLeftCode( PLAYERLEAVE_LOBBY ); else LastMatch->SetLeftCode( PLAYERLEAVE_LOST ); + LastMatch->deleteLater(); if( !m_GameLoading && !m_GameLoaded ) OpenSlot( GetSIDFromPID( LastMatch->GetPID( ) ), false ); } else - SendAllChat( m_GHost->m_Language->UnableToKickFoundMoreThanOneMatch( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToKickFoundMoreThanOneMatch( Payload ) ); } // @@ -1106,24 +1119,26 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "latency" ) { - if( Payload.empty( ) ) - SendAllChat( m_GHost->m_Language->LatencyIs( UTIL_ToString( m_Latency ) ) ); + if( Payload.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->LatencyIs( QString::number( m_Latency ) ) ); else { - m_Latency = UTIL_ToUInt32( Payload ); + m_RequestedLatency = Payload.toUInt(); + + quint32 min = 20, max = 2000; - if( m_Latency <= 20 ) + if( m_RequestedLatency <= min ) { - m_Latency = 20; - SendAllChat( m_GHost->m_Language->SettingLatencyToMinimum( "20" ) ); + m_RequestedLatency = min; + SendAllChat( m_GHost->GetLanguage( )->SettingLatencyToMinimum( QString::number(m_RequestedLatency) ) ); } - else if( m_Latency >= 500 ) + else if( m_RequestedLatency >= max ) { - m_Latency = 500; - SendAllChat( m_GHost->m_Language->SettingLatencyToMaximum( "500" ) ); + m_RequestedLatency = max; + SendAllChat( m_GHost->GetLanguage( )->SettingLatencyToMaximum( QString::number(m_RequestedLatency) ) ); } else - SendAllChat( m_GHost->m_Language->SettingLatencyTo( UTIL_ToString( m_Latency ) ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingLatencyTo( QString::number( m_RequestedLatency ) ) ); } } @@ -1133,7 +1148,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "lock" && ( RootAdminCheck || IsOwner( User ) ) ) { - SendAllChat( m_GHost->m_Language->GameLocked( ) ); + SendAllChat( m_GHost->GetLanguage( )->GameLocked( ) ); m_Locked = true; } @@ -1145,12 +1160,12 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { if( Payload == "on" ) { - SendAllChat( m_GHost->m_Language->LocalAdminMessagesEnabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->LocalAdminMessagesEnabled( ) ); m_LocalAdminMessages = true; } else if( Payload == "off" ) { - SendAllChat( m_GHost->m_Language->LocalAdminMessagesDisabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->LocalAdminMessagesDisabled( ) ); m_LocalAdminMessages = false; } } @@ -1162,17 +1177,17 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "mute" ) { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToMuteNoMatchesFound( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToMuteNoMatchesFound( Payload ) ); else if( Matches == 1 ) { - SendAllChat( m_GHost->m_Language->MutedPlayer( LastMatch->GetName( ), User ) ); + SendAllChat( m_GHost->GetLanguage( )->MutedPlayer( LastMatch->GetName( ), User ) ); LastMatch->SetMuted( true ); } else - SendAllChat( m_GHost->m_Language->UnableToMuteFoundMoreThanOneMatch( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToMuteFoundMoreThanOneMatch( Payload ) ); } // @@ -1181,7 +1196,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "muteall" && m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->GlobalChatMuted( ) ); + SendAllChat( m_GHost->GetLanguage( )->GlobalChatMuted( ) ); m_MuteAll = true; } @@ -1189,19 +1204,19 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !OPEN (open slot) // - if( Command == "open" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded ) + if( Command == "open" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded ) { // open as many slots as specified, e.g. "5 10" opens slots 5 and 10 - stringstream SS; - SS << Payload; + QTextStream SS(&Payload); - while( !SS.eof( ) ) + + while( !SS.atEnd( ) ) { - uint32_t SID; + quint32 SID; SS >> SID; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) { CONSOLE_Print( "[GAME: " + m_GameName + "] bad input to open command" ); break; @@ -1226,19 +1241,19 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { if( RootAdminCheck || IsOwner( User ) || !GetPlayerFromName( m_OwnerName, false ) ) { - if( !Payload.empty( ) ) + if( !Payload.isEmpty( ) ) { - SendAllChat( m_GHost->m_Language->SettingGameOwnerTo( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingGameOwnerTo( Payload ) ); m_OwnerName = Payload; } else { - SendAllChat( m_GHost->m_Language->SettingGameOwnerTo( User ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingGameOwnerTo( User ) ); m_OwnerName = User; } } else - SendAllChat( m_GHost->m_Language->UnableToSetGameOwner( m_OwnerName ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToSetGameOwner( m_OwnerName ) ); } // @@ -1250,32 +1265,32 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // kick players with ping higher than payload if payload isn't empty // we only do this if the game hasn't started since we don't want to kick players from a game in progress - uint32_t Kicked = 0; - uint32_t KickPing = 0; + quint32 Kicked = 0; + quint32 KickPing = 0; - if( !m_GameLoading && !m_GameLoaded && !Payload.empty( ) ) - KickPing = UTIL_ToUInt32( Payload ); + if( !m_GameLoading && !m_GameLoaded && !Payload.isEmpty( ) ) + KickPing = Payload.toUInt(); // copy the m_Players vector so we can sort by descending ping so it's easier to find players with high pings - vector SortedPlayers = m_Players; - sort( SortedPlayers.begin( ), SortedPlayers.end( ), CGamePlayerSortDescByPing( ) ); - string Pings; + QList SortedPlayers = m_Players; + qSort(SortedPlayers); + QString Pings; - for( vector :: iterator i = SortedPlayers.begin( ); i != SortedPlayers.end( ); i++ ) + for( QList :: const_iterator i = SortedPlayers.begin( ); i != SortedPlayers.end( ); i++ ) { Pings += (*i)->GetNameTerminated( ); Pings += ": "; if( (*i)->GetNumPings( ) > 0 ) { - Pings += UTIL_ToString( (*i)->GetPing( m_GHost->m_LCPings ) ); + Pings += QString::number( (*i)->GetPing( m_GHost->m_LCPings ) ); if( !m_GameLoading && !m_GameLoaded && !(*i)->GetReserved( ) && KickPing > 0 && (*i)->GetPing( m_GHost->m_LCPings ) > KickPing ) { - (*i)->SetDeleteMe( true ); - (*i)->SetLeftReason( "was kicked for excessive ping " + UTIL_ToString( (*i)->GetPing( m_GHost->m_LCPings ) ) + " > " + UTIL_ToString( KickPing ) ); + (*i)->SetLeftReason( "was kicked for excessive ping " + QString::number( (*i)->GetPing( m_GHost->m_LCPings ) ) + " > " + QString::number( KickPing ) ); (*i)->SetLeftCode( PLAYERLEAVE_LOBBY ); + (*i)->deleteLater(); OpenSlot( GetSIDFromPID( (*i)->GetPID( ) ), false ); Kicked++; } @@ -1297,29 +1312,29 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } } - if( !Pings.empty( ) ) + if( !Pings.isEmpty( ) ) SendAllChat( Pings ); if( Kicked > 0 ) - SendAllChat( m_GHost->m_Language->KickingPlayersWithPingsGreaterThan( UTIL_ToString( Kicked ), UTIL_ToString( KickPing ) ) ); + SendAllChat( m_GHost->GetLanguage( )->KickingPlayersWithPingsGreaterThan( QString::number( Kicked ), QString::number( KickPing ) ) ); } // // !PRIV (rehost as private game) // - if( Command == "priv" && !Payload.empty( ) && !m_CountDownStarted && !m_SaveGame ) + if( Command == "priv" && !Payload.isEmpty( ) && !m_CountDownStarted && !m_SaveGame ) { CONSOLE_Print( "[GAME: " + m_GameName + "] trying to rehost as private game [" + Payload + "]" ); - SendAllChat( m_GHost->m_Language->TryingToRehostAsPrivateGame( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->TryingToRehostAsPrivateGame( Payload ) ); m_GameState = GAME_PRIVATE; m_LastGameName = m_GameName; m_GameName = Payload; - m_HostCounter = m_GHost->m_HostCounter++; + m_HostCounter = GetNewHostCounter( ); m_RefreshError = false; m_RefreshRehosted = true; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { // unqueue any existing game refreshes because we're going to assume the next successful game refresh indicates that the rehost worked // this ignores the fact that it's possible a game refresh was just sent and no response has been received yet @@ -1331,32 +1346,31 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // we need to send the game creation message now because private games are not refreshed - (*i)->QueueGameCreate( m_GameState, m_GameName, string( ), m_Map, NULL, m_HostCounter ); + (*i)->QueueGameCreate( m_GameState, m_GameName, QString( ), m_Map, NULL, m_HostCounter ); if( (*i)->GetPasswordHashType( ) != "pvpgn" ) (*i)->QueueEnterChat( ); } m_CreationTime = GetTime( ); - m_LastRefreshTime = GetTime( ); } // // !PUB (rehost as public game) // - if( Command == "pub" && !Payload.empty( ) && !m_CountDownStarted && !m_SaveGame ) + if( Command == "pub" && !Payload.isEmpty( ) && !m_CountDownStarted && !m_SaveGame ) { CONSOLE_Print( "[GAME: " + m_GameName + "] trying to rehost as public game [" + Payload + "]" ); - SendAllChat( m_GHost->m_Language->TryingToRehostAsPublicGame( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->TryingToRehostAsPublicGame( Payload ) ); m_GameState = GAME_PUBLIC; m_LastGameName = m_GameName; m_GameName = Payload; - m_HostCounter = m_GHost->m_HostCounter++; + m_HostCounter = GetNewHostCounter( ); m_RefreshError = false; m_RefreshRehosted = true; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { // unqueue any existing game refreshes because we're going to assume the next successful game refresh indicates that the rehost worked // this ignores the fact that it's possible a game refresh was just sent and no response has been received yet @@ -1370,7 +1384,6 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string } m_CreationTime = GetTime( ); - m_LastRefreshTime = GetTime( ); } // @@ -1381,12 +1394,12 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { if( Payload == "on" ) { - SendAllChat( m_GHost->m_Language->RefreshMessagesEnabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->RefreshMessagesEnabled( ) ); m_RefreshMessages = true; } else if( Payload == "off" ) { - SendAllChat( m_GHost->m_Language->RefreshMessagesDisabled( ) ); + SendAllChat( m_GHost->GetLanguage( )->RefreshMessagesDisabled( ) ); m_RefreshMessages = false; } } @@ -1395,9 +1408,9 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !SAY // - if( Command == "say" && !Payload.empty( ) ) + if( Command == "say" && !Payload.isEmpty( ) ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) (*i)->QueueChatCommand( Payload ); HideCommand = true; @@ -1407,21 +1420,21 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !SENDLAN // - if( Command == "sendlan" && !Payload.empty( ) && !m_CountDownStarted ) + if( Command == "sendlan" && !Payload.isEmpty( ) && !m_CountDownStarted ) { // extract the ip and the port // e.g. "1.2.3.4 6112" -> ip: "1.2.3.4", port: "6112" - string IP; - uint32_t Port = 6112; - stringstream SS; - SS << Payload; + QString IP; + quint32 Port = 6112; + QTextStream SS(&Payload); + SS >> IP; - if( !SS.eof( ) ) + if( !SS.atEnd( ) ) SS >> Port; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad inputs to sendlan command" ); else { @@ -1438,22 +1451,24 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string { // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) - uint32_t MapGameType = MAPGAMETYPE_SAVEDGAME; - BYTEARRAY MapWidth; - MapWidth.push_back( 0 ); - MapWidth.push_back( 0 ); - BYTEARRAY MapHeight; - MapHeight.push_back( 0 ); - MapHeight.push_back( 0 ); - m_GHost->m_UDPSocket->SendTo( IP, Port, m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, UTIL_CreateByteArray( MapGameType, false ), m_Map->GetMapGameFlags( ), MapWidth, MapHeight, m_GameName, "Varlock", GetTime( ) - m_CreationTime, "Save\\Multiplayer\\" + m_SaveGame->GetFileNameNoPath( ), m_SaveGame->GetMagicNumber( ), 12, 12, m_HostPort, m_HostCounter ) ); + quint32 MapGameType = MAPGAMETYPE_SAVEDGAME; + QByteArray MapWidth; + MapWidth.push_back( (char)0 ); + MapWidth.push_back( (char)0 ); + QByteArray MapHeight; + MapHeight.push_back( (char)0 ); + MapHeight.push_back( (char)0 ); + m_GHost->SendUdpBroadcast( m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, Util::fromUInt32( MapGameType), m_Map->GetMapGameFlags( ), MapWidth, MapHeight, m_GameName, "Varlock", GetTime( ) - m_CreationTime, "Save\\Multiplayer\\" + m_SaveGame->GetFileNameNoPath( ), m_SaveGame->GetMagicNumber( ), 12, 12, m_HostPort, m_HostCounter ), + Port, QHostAddress(IP) ); } else { // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) - uint32_t MapGameType = MAPGAMETYPE_UNKNOWN0; - m_GHost->m_UDPSocket->SendTo( IP, Port, m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, UTIL_CreateByteArray( MapGameType, false ), m_Map->GetMapGameFlags( ), m_Map->GetMapWidth( ), m_Map->GetMapHeight( ), m_GameName, "Varlock", GetTime( ) - m_CreationTime, m_Map->GetMapPath( ), m_Map->GetMapCRC( ), 12, 12, m_HostPort, m_HostCounter ) ); + quint32 MapGameType = MAPGAMETYPE_UNKNOWN0; + m_GHost->SendUdpBroadcast( m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, Util::fromUInt32( MapGameType), m_Map->GetMapGameFlags( ), m_Map->GetMapWidth( ), m_Map->GetMapHeight( ), m_GameName, "Varlock", GetTime( ) - m_CreationTime, m_Map->GetMapPath( ), m_Map->GetMapCRC( ), 12, 12, m_HostPort, m_HostCounter ), + Port, QHostAddress(IP) ); } } } @@ -1464,7 +1479,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "sp" && !m_CountDownStarted ) { - SendAllChat( m_GHost->m_Language->ShufflingPlayers( ) ); + SendAllChat( m_GHost->GetLanguage( )->ShufflingPlayers( ) ); ShuffleSlots( ); } @@ -1484,7 +1499,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( GetTicks( ) - m_LastPlayerLeaveTicks >= 2000 ) StartCountDown( false ); else - SendAllChat( m_GHost->m_Language->CountDownAbortedSomeoneLeftRecently( ) ); + SendAllChat( m_GHost->GetLanguage( )->CountDownAbortedSomeoneLeftRecently( ) ); } } @@ -1492,25 +1507,25 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !SWAP (swap slots) // - if( Command == "swap" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded ) + if( Command == "swap" && !Payload.isEmpty( ) && !m_GameLoading && !m_GameLoaded ) { - uint32_t SID1; - uint32_t SID2; - stringstream SS; - SS << Payload; + quint32 SID1; + quint32 SID2; + QTextStream SS(&Payload); + SS >> SID1; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #1 to swap command" ); else { - if( SS.eof( ) ) + if( SS.atEnd( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] missing input #2 to swap command" ); else { SS >> SID2; - if( SS.fail( ) ) + if( SS.status() != QTextStream::Ok ) CONSOLE_Print( "[GAME: " + m_GameName + "] bad input #2 to swap command" ); else SwapSlots( (unsigned char)( SID1 - 1 ), (unsigned char)( SID2 - 1 ) ); @@ -1524,24 +1539,24 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "synclimit" ) { - if( Payload.empty( ) ) - SendAllChat( m_GHost->m_Language->SyncLimitIs( UTIL_ToString( m_SyncLimit ) ) ); + if( Payload.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->SyncLimitIs( QString::number( m_SyncLimit ) ) ); else { - m_SyncLimit = UTIL_ToUInt32( Payload ); + m_SyncLimit = Payload.toUInt(); if( m_SyncLimit <= 10 ) { m_SyncLimit = 10; - SendAllChat( m_GHost->m_Language->SettingSyncLimitToMinimum( "10" ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingSyncLimitToMinimum( "10" ) ); } else if( m_SyncLimit >= 10000 ) { m_SyncLimit = 10000; - SendAllChat( m_GHost->m_Language->SettingSyncLimitToMaximum( "10000" ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingSyncLimitToMaximum( "10000" ) ); } else - SendAllChat( m_GHost->m_Language->SettingSyncLimitTo( UTIL_ToString( m_SyncLimit ) ) ); + SendAllChat( m_GHost->GetLanguage( )->SettingSyncLimitTo( QString::number( m_SyncLimit ) ) ); } } @@ -1550,7 +1565,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // if( Command == "unhost" && !m_CountDownStarted ) - m_Exiting = true; + deleteLater(); // // !UNLOCK @@ -1558,7 +1573,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "unlock" && ( RootAdminCheck || IsOwner( User ) ) ) { - SendAllChat( m_GHost->m_Language->GameUnlocked( ) ); + SendAllChat( m_GHost->GetLanguage( )->GameUnlocked( ) ); m_Locked = false; } @@ -1569,17 +1584,17 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "unmute" ) { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendAllChat( m_GHost->m_Language->UnableToMuteNoMatchesFound( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToMuteNoMatchesFound( Payload ) ); else if( Matches == 1 ) { - SendAllChat( m_GHost->m_Language->UnmutedPlayer( LastMatch->GetName( ), User ) ); + SendAllChat( m_GHost->GetLanguage( )->UnmutedPlayer( LastMatch->GetName( ), User ) ); LastMatch->SetMuted( false ); } else - SendAllChat( m_GHost->m_Language->UnableToMuteFoundMoreThanOneMatch( Payload ) ); + SendAllChat( m_GHost->GetLanguage( )->UnableToMuteFoundMoreThanOneMatch( Payload ) ); } // @@ -1588,7 +1603,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "unmuteall" && m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->GlobalChatUnmuted( ) ); + SendAllChat( m_GHost->GetLanguage( )->GlobalChatUnmuted( ) ); m_MuteAll = false; } @@ -1596,42 +1611,43 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !VIRTUALHOST // - if( Command == "virtualhost" && !Payload.empty( ) && Payload.size( ) <= 15 && !m_CountDownStarted ) + if( Command == "virtualhost" && !Payload.isEmpty( ) && Payload.size( ) <= 15 && !m_CountDownStarted ) { DeleteVirtualHost( ); m_VirtualHostName = Payload; + CreateVirtualHost(); } // // !VOTECANCEL // - if( Command == "votecancel" && !m_KickVotePlayer.empty( ) ) + if( Command == "votecancel" && !m_KickVotePlayer.isEmpty( ) ) { - SendAllChat( m_GHost->m_Language->VoteKickCancelled( m_KickVotePlayer ) ); + SendAllChat( m_GHost->GetLanguage( )->VoteKickCancelled( m_KickVotePlayer ) ); m_KickVotePlayer.clear( ); - m_StartedKickVoteTime = 0; + m_VotekickTimer.stop(); } // // !W // - if( Command == "w" && !Payload.empty( ) ) + if( Command == "w" && !Payload.isEmpty( ) ) { // extract the name and the message // e.g. "Varlock hello there!" -> name: "Varlock", message: "hello there!" - string Name; - string Message; - string :: size_type MessageStart = Payload.find( " " ); + QString Name; + QString Message; + int MessageStart = Payload.indexOf( " " ); - if( MessageStart != string :: npos ) + if( MessageStart != -1 ) { - Name = Payload.substr( 0, MessageStart ); - Message = Payload.substr( MessageStart + 1 ); + Name = Payload.mid( 0, MessageStart ); + Message = Payload.mid( MessageStart + 1 ); - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) (*i)->QueueChatCommand( Message, Name, true ); } @@ -1641,7 +1657,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string else { CONSOLE_Print( "[GAME: " + m_GameName + "] admin command ignored, the game is locked" ); - SendChat( player, m_GHost->m_Language->TheGameIsLocked( ) ); + SendChat( player, m_GHost->GetLanguage( )->TheGameIsLocked( ) ); } } else @@ -1661,7 +1677,7 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // if( Command == "checkme" ) - SendChat( player, m_GHost->m_Language->CheckedPlayer( User, player->GetNumPings( ) > 0 ? UTIL_ToString( player->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( UTIL_ByteArrayToUInt32( player->GetExternalIP( ), true ) ), AdminCheck || RootAdminCheck ? "Yes" : "No", IsOwner( User ) ? "Yes" : "No", player->GetSpoofed( ) ? "Yes" : "No", player->GetSpoofedRealm( ).empty( ) ? "N/A" : player->GetSpoofedRealm( ), player->GetReserved( ) ? "Yes" : "No" ) ); + SendChat( player, m_GHost->GetLanguage( )->CheckedPlayer( User, player->GetNumPings( ) > 0 ? QString::number( player->GetPing( m_GHost->m_LCPings ) ) + "ms" : "N/A", m_GHost->m_DBLocal->FromCheck( Util::extractUInt32(Util::reverse(player->GetExternalIP( ))) ), AdminCheck || RootAdminCheck ? "Yes" : "No", IsOwner( User ) ? "Yes" : "No", player->GetSpoofed( ) ? "Yes" : "No", player->GetSpoofedRealm( ).isEmpty( ) ? "N/A" : player->GetSpoofedRealm( ), player->GetReserved( ) ? "Yes" : "No" ) ); // // !STATS @@ -1669,13 +1685,13 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "stats" && GetTime( ) - player->GetStatsSentTime( ) >= 5 ) { - string StatsUser = User; + QString StatsUser = User; - if( !Payload.empty( ) ) + if( !Payload.isEmpty( ) ) StatsUser = Payload; if( player->GetSpoofed( ) && ( AdminCheck || RootAdminCheck || IsOwner( User ) ) ) - m_PairedGPSChecks.push_back( PairedGPSCheck( string( ), m_GHost->m_DB->ThreadedGamePlayerSummaryCheck( StatsUser ) ) ); + m_PairedGPSChecks.push_back( PairedGPSCheck( QString( ), m_GHost->m_DB->ThreadedGamePlayerSummaryCheck( StatsUser ) ) ); else m_PairedGPSChecks.push_back( PairedGPSCheck( User, m_GHost->m_DB->ThreadedGamePlayerSummaryCheck( StatsUser ) ) ); @@ -1688,13 +1704,13 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "statsdota" && GetTime( ) - player->GetStatsDotASentTime( ) >= 5 ) { - string StatsUser = User; + QString StatsUser = User; - if( !Payload.empty( ) ) + if( !Payload.isEmpty( ) ) StatsUser = Payload; if( player->GetSpoofed( ) && ( AdminCheck || RootAdminCheck || IsOwner( User ) ) ) - m_PairedDPSChecks.push_back( PairedDPSCheck( string( ), m_GHost->m_DB->ThreadedDotAPlayerSummaryCheck( StatsUser ) ) ); + m_PairedDPSChecks.push_back( PairedDPSCheck( QString( ), m_GHost->m_DB->ThreadedDotAPlayerSummaryCheck( StatsUser ) ) ); else m_PairedDPSChecks.push_back( PairedDPSCheck( User, m_GHost->m_DB->ThreadedDotAPlayerSummaryCheck( StatsUser ) ) ); @@ -1708,48 +1724,48 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Command == "version" ) { if( player->GetSpoofed( ) && ( AdminCheck || RootAdminCheck || IsOwner( User ) ) ) - SendChat( player, m_GHost->m_Language->VersionAdmin( m_GHost->m_Version ) ); + SendChat( player, m_GHost->GetLanguage( )->VersionAdmin( m_GHost->GetVersion( ) ) ); else - SendChat( player, m_GHost->m_Language->VersionNotAdmin( m_GHost->m_Version ) ); + SendChat( player, m_GHost->GetLanguage( )->VersionNotAdmin( m_GHost->GetVersion( ) ) ); } // // !VOTEKICK // - if( Command == "votekick" && m_GHost->m_VoteKickAllowed && !Payload.empty( ) ) + if( Command == "votekick" && m_GHost->m_VoteKickAllowed && !Payload.isEmpty( ) ) { - if( !m_KickVotePlayer.empty( ) ) - SendChat( player, m_GHost->m_Language->UnableToVoteKickAlreadyInProgress( ) ); + if( !m_KickVotePlayer.isEmpty( ) ) + SendChat( player, m_GHost->GetLanguage( )->UnableToVoteKickAlreadyInProgress( ) ); else if( m_Players.size( ) == 2 ) - SendChat( player, m_GHost->m_Language->UnableToVoteKickNotEnoughPlayers( ) ); + SendChat( player, m_GHost->GetLanguage( )->UnableToVoteKickNotEnoughPlayers( ) ); else { CGamePlayer *LastMatch = NULL; - uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); + quint32 Matches = GetPlayerFromNamePartial( Payload, &LastMatch ); if( Matches == 0 ) - SendChat( player, m_GHost->m_Language->UnableToVoteKickNoMatchesFound( Payload ) ); + SendChat( player, m_GHost->GetLanguage( )->UnableToVoteKickNoMatchesFound( Payload ) ); else if( Matches == 1 ) { if( LastMatch->GetReserved( ) ) - SendChat( player, m_GHost->m_Language->UnableToVoteKickPlayerIsReserved( LastMatch->GetName( ) ) ); + SendChat( player, m_GHost->GetLanguage( )->UnableToVoteKickPlayerIsReserved( LastMatch->GetName( ) ) ); else { m_KickVotePlayer = LastMatch->GetName( ); - m_StartedKickVoteTime = GetTime( ); + m_VotekickTimer.start(); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) (*i)->SetKickVote( false ); player->SetKickVote( true ); CONSOLE_Print( "[GAME: " + m_GameName + "] votekick against player [" + m_KickVotePlayer + "] started by player [" + User + "]" ); - SendAllChat( m_GHost->m_Language->StartedVoteKick( LastMatch->GetName( ), User, UTIL_ToString( (uint32_t)ceil( ( GetNumHumanPlayers( ) - 1 ) * (float)m_GHost->m_VoteKickPercentage / 100 ) - 1 ) ) ); - SendAllChat( m_GHost->m_Language->TypeYesToVote( string( 1, m_GHost->m_CommandTrigger ) ) ); + SendAllChat( m_GHost->GetLanguage( )->StartedVoteKick( LastMatch->GetName( ), User, QString::number( (quint32)ceil( ( GetNumHumanPlayers( ) - 1 ) * (float)m_GHost->m_VoteKickPercentage / 100 ) - 1 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->TypeYesToVote( QString( 1, m_GHost->m_CommandTrigger ) ) ); } } else - SendChat( player, m_GHost->m_Language->UnableToVoteKickFoundMoreThanOneMatch( Payload ) ); + SendChat( player, m_GHost->GetLanguage( )->UnableToVoteKickFoundMoreThanOneMatch( Payload ) ); } } @@ -1757,13 +1773,13 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string // !YES // - if( Command == "yes" && !m_KickVotePlayer.empty( ) && player->GetName( ) != m_KickVotePlayer && !player->GetKickVote( ) ) + if( Command == "yes" && !m_KickVotePlayer.isEmpty( ) && player->GetName( ) != m_KickVotePlayer && !player->GetKickVote( ) ) { player->SetKickVote( true ); - uint32_t VotesNeeded = (uint32_t)ceil( ( GetNumHumanPlayers( ) - 1 ) * (float)m_GHost->m_VoteKickPercentage / 100 ); - uint32_t Votes = 0; + quint32 VotesNeeded = (quint32)ceil( ( GetNumHumanPlayers( ) - 1 ) * (float)m_GHost->m_VoteKickPercentage / 100 ); + quint32 Votes = 0; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetKickVote( ) ) Votes++; @@ -1775,28 +1791,29 @@ bool CGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string if( Victim ) { - Victim->SetDeleteMe( true ); - Victim->SetLeftReason( m_GHost->m_Language->WasKickedByVote( ) ); + Victim->SetLeftReason( m_GHost->GetLanguage( )->WasKickedByVote( ) ); if( !m_GameLoading && !m_GameLoaded ) Victim->SetLeftCode( PLAYERLEAVE_LOBBY ); else Victim->SetLeftCode( PLAYERLEAVE_LOST ); + Victim->deleteLater(); + if( !m_GameLoading && !m_GameLoaded ) OpenSlot( GetSIDFromPID( Victim->GetPID( ) ), false ); - CONSOLE_Print( "[GAME: " + m_GameName + "] votekick against player [" + m_KickVotePlayer + "] passed with " + UTIL_ToString( Votes ) + "/" + UTIL_ToString( GetNumHumanPlayers( ) ) + " votes" ); - SendAllChat( m_GHost->m_Language->VoteKickPassed( m_KickVotePlayer ) ); + CONSOLE_Print( "[GAME: " + m_GameName + "] votekick against player [" + m_KickVotePlayer + "] passed with " + QString::number( Votes ) + "/" + QString::number( GetNumHumanPlayers( ) ) + " votes" ); + SendAllChat( m_GHost->GetLanguage( )->VoteKickPassed( m_KickVotePlayer ) ); } else - SendAllChat( m_GHost->m_Language->ErrorVoteKickingPlayer( m_KickVotePlayer ) ); + SendAllChat( m_GHost->GetLanguage( )->ErrorVoteKickingPlayer( m_KickVotePlayer ) ); m_KickVotePlayer.clear( ); - m_StartedKickVoteTime = 0; + m_VotekickTimer.stop(); } else - SendAllChat( m_GHost->m_Language->VoteKickAcceptedNeedMoreVotes( m_KickVotePlayer, User, UTIL_ToString( VotesNeeded - Votes ) ) ); + SendAllChat( m_GHost->GetLanguage( )->VoteKickAcceptedNeedMoreVotes( m_KickVotePlayer, User, QString::number( VotesNeeded - Votes ) ) ); } return HideCommand; @@ -1811,8 +1828,8 @@ void CGame :: EventGameStarted( ) // but since the player has already left the game we don't have access to their information anymore // so we create a "potential ban" for each player and only store it in the database if requested to by an admin - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - m_DBBans.push_back( new CDBBan( (*i)->GetJoinedRealm( ), (*i)->GetName( ), (*i)->GetExternalIPString( ), string( ), string( ), string( ), string( ) ) ); + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + m_DBBans.push_back( new CDBBan( (*i)->GetJoinedRealm( ), (*i)->GetName( ), (*i)->GetExternalIPString( ), QString( ), QString( ), QString( ), QString( ) ) ); } bool CGame :: IsGameDataSaved( ) @@ -1823,5 +1840,11 @@ bool CGame :: IsGameDataSaved( ) void CGame :: SaveGameData( ) { CONSOLE_Print( "[GAME: " + m_GameName + "] saving game data to database" ); - m_CallableGameAdd = m_GHost->m_DB->ThreadedGameAdd( m_GHost->m_BNETs.size( ) == 1 ? m_GHost->m_BNETs[0]->GetServer( ) : string( ), m_DBGame->GetMap( ), m_GameName, m_OwnerName, m_GameTicks / 1000, m_GameState, m_CreatorName, m_CreatorServer ); + m_CallableGameAdd = m_GHost->m_DB->ThreadedGameAdd( m_GHost->m_BNETs.size( ) == 1 ? m_GHost->m_BNETs[0]->GetServer( ) : QString( ), m_DBGame->GetMap( ), m_GameName, m_OwnerName, m_GameTicks / 1000, m_GameState, m_CreatorName, m_CreatorServer ); + + if (!m_CallableGameAdd->GetReady()) + QObject::connect(m_CallableGameAdd, SIGNAL(finished()), this, SLOT(EventGameDataSaved())); + + else + EventGameDataSaved(); } diff --git a/src/libghost/game.h b/src/libghost/game.h new file mode 100644 index 0000000..a55336e --- /dev/null +++ b/src/libghost/game.h @@ -0,0 +1,80 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GAME_H +#define GAME_H + +// +// CGame +// + +#include "includes.h" + +class CDBBan; +class CDBGame; +class CDBGamePlayer; +class CStats; +class CCallableBanCheck; +class CCallableBanAdd; +class CCallableGameAdd; +class CCallableGamePlayerSummaryCheck; +class CCallableDotAPlayerSummaryCheck; + +typedef pair PairedBanCheck; +typedef pair PairedBanAdd; +typedef pair PairedGPSCheck; +typedef pair PairedDPSCheck; + +#include +#include "game_base.h" + +class CGame : public CBaseGame +{ + Q_OBJECT + +public slots: + virtual void EventPlayerDeleted(); + void EventCallableUpdateTimeout(); + void EventGameDataSaved(); + +protected: + CDBBan *m_DBBanLast; // last ban for the !banlast command - this is a pointer to one of the items in m_DBBans + QList m_DBBans; // vector of potential ban data for the database (see the Update function for more info, it's not as straightforward as you might think) + CDBGame *m_DBGame; // potential game data for the database + QList m_DBGamePlayers; // vector of potential gameplayer data for the database + CStats *m_Stats; // class to keep track of game stats such as kills/deaths/assists in dota + CCallableGameAdd *m_CallableGameAdd; // threaded database game addition in progress + QList m_PairedBanChecks; // vector of paired threaded database ban checks in progress + QList m_PairedBanAdds; // vector of paired threaded database ban adds in progress + QList m_PairedGPSChecks; // vector of paired threaded database game player summary checks in progress + QList m_PairedDPSChecks; // vector of paired threaded database DotA player summary checks in progress + +public: + CGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nOwnerName, QString nCreatorName, QString nCreatorServer ); + virtual ~CGame( ); + + virtual void EventPlayerAction( CGamePlayer *player, CIncomingAction *action ); + virtual bool EventPlayerBotCommand( CGamePlayer *player, QString command, QString payload ); + virtual void EventGameStarted( ); + virtual bool IsGameDataSaved( ); + virtual void SaveGameData( ); +}; + +#endif diff --git a/src/libghost/game_admin.cpp b/src/libghost/game_admin.cpp new file mode 100644 index 0000000..305c79f --- /dev/null +++ b/src/libghost/game_admin.cpp @@ -0,0 +1,1249 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "config.h" +#include "language.h" +#include "ghostdb.h" +#include "bnet.h" +#include "map.h" +#include "packed.h" +#include "savegame.h" +#include "replay.h" +#include "gameplayer.h" +#include "gameprotocol.h" +#include "game.h" +#include "game_admin.h" + +#include +#include +#include +#include + + +// +// CAdminGame +// + +CAdminGame :: CAdminGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nPassword ) : CBaseGame( nGHost, nMap, nSaveGame, nHostPort, nGameState, nGameName, QString( ), QString( ), QString( ) ) +{ + m_VirtualHostName = "|cFFC04040Admin"; + m_MuteLobby = true; + m_Password = nPassword; +} + +CAdminGame :: ~CAdminGame( ) +{ + for( QList :: const_iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + for( QList :: const_iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + /* + + for( QList :: const_iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); + + */ + + for( QList :: const_iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); i++ ) + m_GHost->m_Callables.push_back( i->second ); +} + +void CAdminGame::EventCallableUpdateTimeout() +{ + // + // update callables + // + + for( QList :: iterator i = m_PairedAdminCounts.begin( ); i != m_PairedAdminCounts.end( ); ) + { + if( i->second->GetReady( ) ) + { + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + quint32 Count = i->second->GetResult( ); + + if( Count == 0 ) + SendChat( Player, m_GHost->GetLanguage( )->ThereAreNoAdmins( i->second->GetServer( ) ) ); + else if( Count == 1 ) + SendChat( Player, m_GHost->GetLanguage( )->ThereIsAdmin( i->second->GetServer( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ThereAreAdmins( i->second->GetServer( ), QString::number( Count ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminCounts.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedAdminAdds.begin( ); i != m_PairedAdminAdds.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + for( QList :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) + { + if( (*j)->GetServer( ) == i->second->GetServer( ) ) + (*j)->AddAdmin( i->second->GetUser( ) ); + } + } + + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + if( i->second->GetResult( ) ) + SendChat( Player, m_GHost->GetLanguage( )->AddedUserToAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ErrorAddingUserToAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminAdds.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedAdminRemoves.begin( ); i != m_PairedAdminRemoves.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + for( QList :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) + { + if( (*j)->GetServer( ) == i->second->GetServer( ) ) + (*j)->RemoveAdmin( i->second->GetUser( ) ); + } + } + + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + if( i->second->GetResult( ) ) + SendChat( Player, m_GHost->GetLanguage( )->DeletedUserFromAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ErrorDeletingUserFromAdminDatabase( i->second->GetServer( ), i->second->GetUser( ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedAdminRemoves.erase( i ); + } + else + i++; + } + + for( QList :: iterator i = m_PairedBanCounts.begin( ); i != m_PairedBanCounts.end( ); ) + { + if( i->second->GetReady( ) ) + { + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + quint32 Count = i->second->GetResult( ); + + if( Count == 0 ) + SendChat( Player, m_GHost->GetLanguage( )->ThereAreNoBannedUsers( i->second->GetServer( ) ) ); + else if( Count == 1 ) + SendChat( Player, m_GHost->GetLanguage( )->ThereIsBannedUser( i->second->GetServer( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ThereAreBannedUsers( i->second->GetServer( ), QString::number( Count ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanCounts.erase( i ); + } + else + i++; + } + + /* + + for( QList :: const_iterator i = m_PairedBanAdds.begin( ); i != m_PairedBanAdds.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + for( QList :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) + { + if( (*j)->GetServer( ) == i->second->GetServer( ) ) + (*j)->AddBan( i->second->GetUser( ), i->second->GetIP( ), i->second->GetGameName( ), i->second->GetAdmin( ), i->second->GetReason( ) ); + } + } + + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + if( i->second->GetResult( ) ) + SendChat( Player, m_GHost->GetLanguage( )->BannedUser( i->second->GetServer( ), i->second->GetUser( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ErrorBanningUser( i->second->GetServer( ), i->second->GetUser( ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanAdds.erase( i ); + } + else + i++; + } + + */ + + for( QList :: iterator i = m_PairedBanRemoves.begin( ); i != m_PairedBanRemoves.end( ); ) + { + if( i->second->GetReady( ) ) + { + if( i->second->GetResult( ) ) + { + for( QList :: iterator j = m_GHost->m_BNETs.begin( ); j != m_GHost->m_BNETs.end( ); j++ ) + { + if( (*j)->GetServer( ) == i->second->GetServer( ) ) + (*j)->RemoveBan( i->second->GetUser( ) ); + } + } + + CGamePlayer *Player = GetPlayerFromName( i->first, true ); + + if( Player ) + { + if( i->second->GetResult( ) ) + SendChat( Player, m_GHost->GetLanguage( )->UnbannedUser( i->second->GetUser( ) ) ); + else + SendChat( Player, m_GHost->GetLanguage( )->ErrorUnbanningUser( i->second->GetUser( ) ) ); + } + + m_GHost->m_DB->RecoverCallable( i->second ); + delete i->second; + i = m_PairedBanRemoves.erase( i ); + } + else + i++; + } + + CBaseGame::EventCallableUpdateTimeout(); +} + +void CAdminGame :: SendAdminChat( QString message ) +{ + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( (*i)->GetLoggedIn( ) ) + SendChat( *i, message ); + } +} + +void CAdminGame :: SendWelcomeMessage( CGamePlayer *player ) +{ + SendChat( player, "GHost++ Admin Game http://www.codelain.com/" ); + SendChat( player, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" ); + SendChat( player, "Commands: addadmin, autohost, autohostmm, checkadmin" ); + SendChat( player, "Commands: checkban, countadmins, countbans, deladmin" ); + SendChat( player, "Commands: delban, disable, downloads, enable, end, enforcesg" ); + SendChat( player, "Commands: exit, getgame, getgames, hostsg, load, loadsg" ); + SendChat( player, "Commands: map, password, priv, privby, pub, pubby, quit" ); + SendChat( player, "Commands: reload, say, saygame, saygames, unban, unhost, w" ); +} + +void CAdminGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ) +{ + quint32 Time = GetTime( ); + + for( QList :: iterator i = m_TempBans.begin( ); i != m_TempBans.end( ); ) + { + // remove old tempbans (after 5 seconds) + + if( Time - (*i).second >= 5 ) + i = m_TempBans.erase( i ); + else + { + if( (*i).first == potential->GetExternalIPString( ) ) + { + // tempbanned, goodbye + + potential->GetSocket( )->write( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_WRONGPASSWORD ) ); + potential->deleteLater(); + CONSOLE_Print( "[ADMINGAME] player [" + joinPlayer->GetName( ) + "] at ip [" + (*i).first + "] is trying to join the game but is tempbanned" ); + return; + } + + i++; + } + } + + CBaseGame :: EventPlayerJoined( potential, joinPlayer ); +} + +bool CAdminGame :: EventPlayerBotCommand( CGamePlayer *player, QString command, QString payload ) +{ + CBaseGame :: EventPlayerBotCommand( player, command, payload ); + + // todotodo: don't be lazy + + QString User = player->GetName( ); + QString Command = command; + QString Payload = payload; + + if( player->GetLoggedIn( ) ) + { + CONSOLE_Print( "[ADMINGAME] admin [" + User + "] sent command [" + Command + "] with payload [" + Payload + "]" ); + + /***************** + * ADMIN COMMANDS * + ******************/ + + // + // !ADDADMIN + // + + if( Command == "addadmin" && !Payload.isEmpty( ) ) + { + // extract the name and the server + // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" + + QString Name; + QString Server; + QTextStream SS(&Payload); + + SS >> Name; + + if( SS.atEnd( ) ) + { + if( m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + else + CONSOLE_Print( "[ADMINGAME] missing input #2 to addadmin command" ); + } + else + SS >> Server; + + if( !Server.isEmpty( ) ) + { + QString Servers; + bool FoundServer = false; + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + if( Servers.isEmpty( ) ) + Servers = (*i)->GetServer( ); + else + Servers += ", " + (*i)->GetServer( ); + + if( (*i)->GetServer( ) == Server ) + { + FoundServer = true; + + if( (*i)->IsAdmin( Name ) ) + SendChat( player, m_GHost->GetLanguage( )->UserIsAlreadyAnAdmin( Server, Name ) ); + else + m_PairedAdminAdds.push_back( PairedAdminAdd( player->GetName( ), m_GHost->m_DB->ThreadedAdminAdd( Server, Name ) ) ); + + break; + } + } + + if( !FoundServer ) + SendChat( player, m_GHost->GetLanguage( )->ValidServers( Servers ) ); + } + } + + // + // !AUTOHOST + // + + if( Command == "autohost" ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + SendChat( player, m_GHost->GetLanguage( )->AutoHostDisabled( ) ); + m_GHost->m_AutoHostGameName.clear( ); + m_GHost->m_AutoHostOwner.clear( ); + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = 0; + m_GHost->m_AutoHostAutoStartPlayers = 0; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + else + { + // extract the maximum games, auto start players, and the game name + // e.g. "5 10 BattleShips Pro" -> maximum games: "5", auto start players: "10", game name: "BattleShips Pro" + + quint32 MaximumGames; + quint32 AutoStartPlayers; + QString GameName; + QTextStream SS(&Payload); + + SS >> MaximumGames; + + if( SS.status() != QTextStream::Ok || MaximumGames == 0 ) + CONSOLE_Print( "[ADMINGAME] bad input #1 to autohost command" ); + else + { + SS >> AutoStartPlayers; + + if( SS.status() != QTextStream::Ok || AutoStartPlayers == 0 ) + CONSOLE_Print( "[ADMINGAME] bad input #2 to autohost command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[ADMINGAME] missing input #3 to autohost command" ); + else + { + GameName = SS.readLine( ); + int Start = GameName.indexOf( QRegExp("[^ ]") ); + + if( Start != -1 ) + GameName = GameName.mid( Start ); + + SendChat( player, m_GHost->GetLanguage( )->AutoHostEnabled( ) ); + + m_GHost->SetAutoHostMap( new CMap( *m_GHost->GetCurrentMap( ) ) ); + m_GHost->m_AutoHostGameName = GameName; + m_GHost->m_AutoHostOwner = User; + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = MaximumGames; + m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + } + } + } + } + + // + // !AUTOHOSTMM + // + + if( Command == "autohostmm" ) + { + if( Payload.isEmpty( ) || Payload == "off" ) + { + SendChat( player, m_GHost->GetLanguage( )->AutoHostDisabled( ) ); + m_GHost->m_AutoHostGameName.clear( ); + m_GHost->m_AutoHostOwner.clear( ); + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = 0; + m_GHost->m_AutoHostAutoStartPlayers = 0; + m_GHost->m_AutoHostMatchMaking = false; + m_GHost->m_AutoHostMinimumScore = 0.0; + m_GHost->m_AutoHostMaximumScore = 0.0; + } + else + { + // extract the maximum games, auto start players, and the game name + // e.g. "5 10 800 1200 BattleShips Pro" -> maximum games: "5", auto start players: "10", minimum score: "800", maximum score: "1200", game name: "BattleShips Pro" + + quint32 MaximumGames; + quint32 AutoStartPlayers; + double MinimumScore; + double MaximumScore; + QString GameName; + QTextStream SS(&Payload); + + SS >> MaximumGames; + + if( SS.status() != QTextStream::Ok || MaximumGames == 0 ) + CONSOLE_Print( "[ADMINGAME] bad input #1 to autohostmm command" ); + else + { + SS >> AutoStartPlayers; + + if( SS.status() != QTextStream::Ok || AutoStartPlayers == 0 ) + CONSOLE_Print( "[ADMINGAME] bad input #2 to autohostmm command" ); + else + { + SS >> MinimumScore; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[ADMINGAME] bad input #3 to autohostmm command" ); + else + { + SS >> MaximumScore; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[ADMINGAME] bad input #4 to autohostmm command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[ADMINGAME] missing input #5 to autohostmm command" ); + else + { + GameName = SS.readLine(); + int Start = GameName.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + GameName = GameName.mid( Start ); + + SendChat( player, m_GHost->GetLanguage( )->AutoHostEnabled( ) ); + + m_GHost->SetAutoHostMap( new CMap( *m_GHost->GetCurrentMap( ) ) ); + m_GHost->m_AutoHostGameName = GameName; + m_GHost->m_AutoHostOwner = User; + m_GHost->m_AutoHostServer.clear( ); + m_GHost->m_AutoHostMaximumGames = MaximumGames; + m_GHost->m_AutoHostAutoStartPlayers = AutoStartPlayers; + m_GHost->m_AutoHostMatchMaking = true; + m_GHost->m_AutoHostMinimumScore = MinimumScore; + m_GHost->m_AutoHostMaximumScore = MaximumScore; + } + } + } + } + } + } + } + + // + // !CHECKADMIN + // + + if( Command == "checkadmin" && !Payload.isEmpty( ) ) + { + // extract the name and the server + // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" + + QString Name; + QString Server; + QTextStream SS(&Payload); + + SS >> Name; + + if( SS.atEnd( ) ) + { + if( m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + else + CONSOLE_Print( "[ADMINGAME] missing input #2 to checkadmin command" ); + } + else + SS >> Server; + + if( !Server.isEmpty( ) ) + { + QString Servers; + bool FoundServer = false; + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + if( Servers.isEmpty( ) ) + Servers = (*i)->GetServer( ); + else + Servers += ", " + (*i)->GetServer( ); + + if( (*i)->GetServer( ) == Server ) + { + FoundServer = true; + + if( (*i)->IsAdmin( Name ) ) + SendChat( player, m_GHost->GetLanguage( )->UserIsAnAdmin( Server, Name ) ); + else + SendChat( player, m_GHost->GetLanguage( )->UserIsNotAnAdmin( Server, Name ) ); + + break; + } + } + + if( !FoundServer ) + SendChat( player, m_GHost->GetLanguage( )->ValidServers( Servers ) ); + } + } + + // + // !CHECKBAN + // + + if( Command == "checkban" && !Payload.isEmpty( ) ) + { + // extract the name and the server + // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" + + QString Name; + QString Server; + QTextStream SS(&Payload); + + SS >> Name; + + if( SS.atEnd( ) ) + { + if( m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + else + CONSOLE_Print( "[ADMINGAME] missing input #2 to checkban command" ); + } + else + SS >> Server; + + if( !Server.isEmpty( ) ) + { + QString Servers; + bool FoundServer = false; + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + if( Servers.isEmpty( ) ) + Servers = (*i)->GetServer( ); + else + Servers += ", " + (*i)->GetServer( ); + + if( (*i)->GetServer( ) == Server ) + { + FoundServer = true; + CDBBan *Ban = (*i)->IsBannedName( Name ); + + if( Ban ) + SendChat( player, m_GHost->GetLanguage( )->UserWasBannedOnByBecause( Server, Name, Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + else + SendChat( player, m_GHost->GetLanguage( )->UserIsNotBanned( Server, Name ) ); + + break; + } + } + + if( !FoundServer ) + SendChat( player, m_GHost->GetLanguage( )->ValidServers( Servers ) ); + } + } + + // + // !COUNTADMINS + // + + if( Command == "countadmins" ) + { + QString Server = Payload; + + if( Server.isEmpty( ) && m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + + if( !Server.isEmpty( ) ) + m_PairedAdminCounts.push_back( PairedAdminCount( player->GetName( ), m_GHost->m_DB->ThreadedAdminCount( Server ) ) ); + } + + // + // !COUNTBANS + // + + if( Command == "countbans" ) + { + QString Server = Payload; + + if( Server.isEmpty( ) && m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + + if( !Server.isEmpty( ) ) + m_PairedBanCounts.push_back( PairedBanCount( player->GetName( ), m_GHost->m_DB->ThreadedBanCount( Server ) ) ); + } + + // + // !DELADMIN + // + + if( Command == "deladmin" && !Payload.isEmpty( ) ) + { + // extract the name and the server + // e.g. "Varlock useast.battle.net" -> name: "Varlock", server: "useast.battle.net" + + QString Name; + QString Server; + QTextStream SS(&Payload); + + SS >> Name; + + if( SS.atEnd( ) ) + { + if( m_GHost->m_BNETs.size( ) == 1 ) + Server = m_GHost->m_BNETs[0]->GetServer( ); + else + CONSOLE_Print( "[ADMINGAME] missing input #2 to deladmin command" ); + } + else + SS >> Server; + + if( !Server.isEmpty( ) ) + { + QString Servers; + bool FoundServer = false; + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + if( Servers.isEmpty( ) ) + Servers = (*i)->GetServer( ); + else + Servers += ", " + (*i)->GetServer( ); + + if( (*i)->GetServer( ) == Server ) + { + FoundServer = true; + + if( !(*i)->IsAdmin( Name ) ) + SendChat( player, m_GHost->GetLanguage( )->UserIsNotAnAdmin( Server, Name ) ); + else + m_PairedAdminRemoves.push_back( PairedAdminRemove( player->GetName( ), m_GHost->m_DB->ThreadedAdminRemove( Server, Name ) ) ); + + break; + } + } + + if( !FoundServer ) + SendChat( player, m_GHost->GetLanguage( )->ValidServers( Servers ) ); + } + } + + // + // !DELBAN + // !UNBAN + // + + if( ( Command == "delban" || Command == "unban" ) && !Payload.isEmpty( ) ) + m_PairedBanRemoves.push_back( PairedBanRemove( player->GetName( ), m_GHost->m_DB->ThreadedBanRemove( Payload ) ) ); + + // + // !DISABLE + // + + if( Command == "disable" ) + { + SendChat( player, m_GHost->GetLanguage( )->BotDisabled( ) ); + m_GHost->DisableGameCreation( ); + } + + // + // !DOWNLOADS + // + + if( Command == "downloads" && !Payload.isEmpty( ) ) + { + quint32 Downloads = Payload.toUInt(); + + if( Downloads == 0 ) + { + SendChat( player, m_GHost->GetLanguage( )->MapDownloadsDisabled( ) ); + m_GHost->m_AllowDownloads = 0; + } + else if( Downloads == 1 ) + { + SendChat( player, m_GHost->GetLanguage( )->MapDownloadsEnabled( ) ); + m_GHost->m_AllowDownloads = 1; + } + else if( Downloads == 2 ) + { + SendChat( player, m_GHost->GetLanguage( )->MapDownloadsConditional( ) ); + m_GHost->m_AllowDownloads = 2; + } + } + + // + // !ENABLE + // + + if( Command == "enable" ) + { + SendChat( player, m_GHost->GetLanguage( )->BotEnabled( ) ); + m_GHost->EnableGameCreation( ); + } + + // + // !END + // + + if( Command == "end" && !Payload.isEmpty( ) ) + { + // todotodo: what if a game ends just as you're typing this command and the numbering changes? + + int GameNumber = Payload.toUInt() - 1; + + if( GameNumber < m_GHost->m_Games.size( ) ) + { + SendChat( player, m_GHost->GetLanguage( )->EndingGame( m_GHost->m_Games[GameNumber]->GetDescription( ) ) ); + CONSOLE_Print( "[GAME: " + m_GHost->m_Games[GameNumber]->GetGameName( ) + "] is over (admin ended game)" ); + m_GHost->m_Games[GameNumber]->StopPlayers( "was disconnected (admin ended game)" ); + } + else + SendChat( player, m_GHost->GetLanguage( )->GameNumberDoesntExist( Payload ) ); + } + + // + // !ENFORCESG + // + + if( Command == "enforcesg" && !Payload.isEmpty( ) ) + { + // only load files in the current directory just to be safe + + if( Payload.indexOf( "/" ) != -1 || Payload.indexOf( "\\" ) != -1 ) + SendChat( player, m_GHost->GetLanguage( )->UnableToLoadReplaysOutside( ) ); + else + { + QString File = m_GHost->m_ReplayPath + Payload + ".w3g"; + + if( QFile::exists( File ) ) + { + SendChat( player, m_GHost->GetLanguage( )->LoadingReplay( File ) ); + CReplay *Replay = new CReplay( ); + Replay->Load( File, false ); + Replay->ParseReplay( false ); + m_GHost->m_EnforcePlayers = Replay->GetPlayers( ); + delete Replay; + } + else + SendChat( player, m_GHost->GetLanguage( )->UnableToLoadReplayDoesntExist( File ) ); + } + } + + // + // !EXIT + // !QUIT + // + + if( Command == "exit" || Command == "quit" ) + { + if( Payload == "nice" ) + m_GHost->ExitNice( ); + else if( Payload == "force" ) + deleteLater(); + else + { + if( m_GHost->GetCurrentGame( ) || !m_GHost->m_Games.isEmpty( ) ) + SendChat( player, m_GHost->GetLanguage( )->AtLeastOneGameActiveUseForceToShutdown( ) ); + else + deleteLater(); + } + } + + // + // !GETGAME + // + + if( Command == "getgame" && !Payload.isEmpty( ) ) + { + int GameNumber = Payload.toUInt() - 1; + + if( GameNumber < m_GHost->m_Games.size( ) ) + SendChat( player, m_GHost->GetLanguage( )->GameNumberIs( Payload, m_GHost->m_Games[GameNumber]->GetDescription( ) ) ); + else + SendChat( player, m_GHost->GetLanguage( )->GameNumberDoesntExist( Payload ) ); + } + + // + // !GETGAMES + // + + if( Command == "getgames" ) + { + if( m_GHost->GetCurrentGame( ) ) + SendChat( player, m_GHost->GetLanguage( )->GameIsInTheLobby( m_GHost->GetCurrentGame( )->GetDescription( ), QString::number( m_GHost->m_Games.size( ) ), QString::number( m_GHost->m_MaxGames ) ) ); + else + SendChat( player, m_GHost->GetLanguage( )->ThereIsNoGameInTheLobby( QString::number( m_GHost->m_Games.size( ) ), QString::number( m_GHost->m_MaxGames ) ) ); + } + + // + // !HOSTSG + // + + if( Command == "hostsg" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, true, Payload, User, User, QString( ), false ); + + // + // !LOAD (load config file) + // + + if( Command == "load" ) + { + if( Payload.isEmpty( ) ) + SendChat( player, m_GHost->GetLanguage( )->CurrentlyLoadedMapCFGIs( m_GHost->GetCurrentMap( )->GetCFGFile( ) ) ); + else + { + try + { + QDir MapCFGPath( m_GHost->m_MapCFGPath ); + QString Pattern = Payload.toLower(); + + if( !MapCFGPath.exists() ) + { + CONSOLE_Print( "[ADMINGAME] error listing map configs - map config path doesn't exist" ); + SendChat( player, m_GHost->GetLanguage( )->ErrorListingMapConfigs( ) ); + } + else + { + QStringList files = MapCFGPath.entryList(QStringList("*" + Pattern + "*"), QDir::Files, QDir::Name); + quint32 Matches = files.size(); + + if( Matches == 0 ) + SendChat( player, m_GHost->GetLanguage( )->NoMapConfigsFound( ) ); + else if (files.contains(Pattern)) + { + SendChat( player, m_GHost->GetLanguage( )->LoadingConfigFile( m_GHost->m_MapCFGPath + Pattern ) ); + CConfig MapCFG; + MapCFG.Read( Pattern ); + m_GHost->GetCurrentMap( )->Load( MapCFG, m_GHost->m_MapCFGPath + Pattern ); + } + else if (Matches == 1) + { + QString File = files.at(0); + SendChat( player, m_GHost->GetLanguage( )->LoadingConfigFile( m_GHost->m_MapCFGPath + File ) ); + CConfig MapCFG; + MapCFG.Read( m_GHost->m_MapCFGPath + File ); + m_GHost->GetCurrentMap( )->Load( MapCFG, m_GHost->m_MapCFGPath + File ); + } + else + SendChat( player, m_GHost->GetLanguage( )->FoundMapConfigs( files.join(", ") ) ); + } + } + catch( const exception &ex ) + { + CONSOLE_Print( QString( "[ADMINGAME] error listing map configs - caught exception [" ) + ex.what( ) + "]" ); + SendChat( player, m_GHost->GetLanguage( )->ErrorListingMapConfigs( ) ); + } + } + } + + // + // !LOADSG + // + + if( Command == "loadsg" && !Payload.isEmpty( ) ) + { + // only load files in the current directory just to be safe + + if( Payload.indexOf( "/" ) != -1 || Payload.indexOf( "\\" ) != -1 ) + SendChat( player, m_GHost->GetLanguage( )->UnableToLoadSaveGamesOutside( ) ); + else + { + QString File = m_GHost->m_SaveGamePath + Payload + ".w3z"; + + if( QFile::exists( File ) ) + { + if( m_GHost->GetCurrentGame( ) ) + SendChat( player, m_GHost->GetLanguage( )->UnableToLoadSaveGameGameInLobby( ) ); + else + { + SendChat( player, m_GHost->GetLanguage( )->LoadingSaveGame( File ) ); + m_GHost->LoadSavegame( File ); + } + } + else + SendChat( player, m_GHost->GetLanguage( )->UnableToLoadSaveGameDoesntExist( File ) ); + } + } + + // + // !MAP (load map file) + // + + if( Command == "map" ) + { + if( Payload.isEmpty( ) ) + SendChat( player, m_GHost->GetLanguage( )->CurrentlyLoadedMapCFGIs( m_GHost->GetCurrentMap( )->GetCFGFile( ) ) ); + else + { + try + { + QDir MapPath( m_GHost->m_MapPath ); + QString Pattern = Payload.toLower(); + + if( !MapPath.exists() ) + { + CONSOLE_Print( "[ADMINGAME] error listing maps - map path doesn't exist" ); + SendChat( player, m_GHost->GetLanguage( )->ErrorListingMaps( ) ); + } + else + { + QStringList files = MapPath.entryList(QStringList("*"+Pattern+"*"), QDir::Files, QDir::Name); + quint32 Matches = files.size(); + + if( Matches == 0 ) + SendChat( player, m_GHost->GetLanguage( )->NoMapsFound( ) ); + else if (files.contains(Pattern)) + { + SendChat( player, m_GHost->GetLanguage( )->LoadingConfigFile( Pattern ) ); + + // hackhack: create a config file in memory with the required information to load the map + + CConfig MapCFG; + MapCFG.Set( "map_path", "Maps\\Download\\" + Pattern ); + MapCFG.Set( "map_localpath", Pattern ); + m_GHost->GetCurrentMap( )->Load( MapCFG, Pattern ); + } + else if( Matches == 1 ) + { + QString File = files.at(0); + SendChat( player, m_GHost->GetLanguage( )->LoadingConfigFile( File ) ); + + // hackhack: create a config file in memory with the required information to load the map + + CConfig MapCFG; + MapCFG.Set( "map_path", "Maps\\Download\\" + File ); + MapCFG.Set( "map_localpath", File ); + m_GHost->GetCurrentMap( )->Load( MapCFG, File ); + } + else + SendChat( player, m_GHost->GetLanguage( )->FoundMaps( files.join(", ") ) ); + } + } + catch( const exception &ex ) + { + CONSOLE_Print( QString( "[ADMINGAME] error listing maps - caught exception [" ) + ex.what( ) + "]" ); + SendChat( player, m_GHost->GetLanguage( )->ErrorListingMaps( ) ); + } + } + } + + // + // !PRIV (host private game) + // + + if( Command == "priv" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, false, Payload, User, User, QString( ), false ); + + // + // !PRIVBY (host private game by other player) + // + + if( Command == "privby" && !Payload.isEmpty( ) ) + { + // extract the owner and the game name + // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" + + QString Owner; + QString GameName; + int GameNameStart = Payload.indexOf( " " ); + + if( GameNameStart != -1 ) + { + Owner = Payload.mid( 0, GameNameStart ); + GameName = Payload.mid( GameNameStart + 1 ); + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PRIVATE, false, GameName, Owner, User, QString( ), false ); + } + } + + // + // !PUB (host public game) + // + + if( Command == "pub" && !Payload.isEmpty( ) ) + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PUBLIC, false, Payload, User, User, QString( ), false ); + + // + // !PUBBY (host public game by other player) + // + + if( Command == "pubby" && !Payload.isEmpty( ) ) + { + // extract the owner and the game name + // e.g. "Varlock dota 6.54b arem ~~~" -> owner: "Varlock", game name: "dota 6.54b arem ~~~" + + QString Owner; + QString GameName; + int GameNameStart = Payload.indexOf( " " ); + + if( GameNameStart != -1 ) + { + Owner = Payload.mid( 0, GameNameStart ); + GameName = Payload.mid( GameNameStart + 1 ); + m_GHost->CreateGame( m_GHost->GetCurrentMap( ), GAME_PUBLIC, false, GameName, Owner, User, QString( ), false ); + } + } + + // + // !RELOAD + // + + if( Command == "reload" ) + { + SendChat( player, m_GHost->GetLanguage( )->ReloadingConfigurationFiles( ) ); + m_GHost->ReloadConfigs( ); + } + + // + // !SAY + // + + if( Command == "say" && !Payload.isEmpty( ) ) + { + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + (*i)->QueueChatCommand( Payload ); + } + + // + // !SAYGAME + // + + if( Command == "saygame" && !Payload.isEmpty( ) ) + { + // extract the game number and the message + // e.g. "3 hello everyone" -> game number: "3", message: "hello everyone" + + int GameNumber; + QString Message; + QTextStream SS(&Payload); + + SS >> GameNumber; + + if( SS.status() != QTextStream::Ok ) + CONSOLE_Print( "[ADMINGAME] bad input #1 to saygame command" ); + else + { + if( SS.atEnd( ) ) + CONSOLE_Print( "[ADMINGAME] missing input #2 to saygame command" ); + else + { + Message = SS.readLine(); + int Start = Message.indexOf( QRegExp( "[^ ]" )); + + if( Start != -1 ) + Message = Message.mid( Start ); + + if( GameNumber - 1 < m_GHost->m_Games.size( ) ) + m_GHost->m_Games[GameNumber - 1]->SendAllChat( "ADMIN: " + Message ); + else + SendChat( player, m_GHost->GetLanguage( )->GameNumberDoesntExist( QString::number( GameNumber ) ) ); + } + } + } + + // + // !SAYGAMES + // + + if( Command == "saygames" && !Payload.isEmpty( ) ) + { + if( m_GHost->GetCurrentGame( ) ) + m_GHost->GetCurrentGame( )->SendAllChat( Payload ); + + for( QList :: const_iterator i = m_GHost->m_Games.begin( ); i != m_GHost->m_Games.end( ); i++ ) + (*i)->SendAllChat( "ADMIN: " + Payload ); + } + + // + // !UNHOST + // + + if( Command == "unhost" ) + { + if( m_GHost->GetCurrentGame( ) ) + { + if( m_GHost->GetCurrentGame( )->GetCountDownStarted( ) ) + SendChat( player, m_GHost->GetLanguage( )->UnableToUnhostGameCountdownStarted( m_GHost->GetCurrentGame( )->GetDescription( ) ) ); + else + { + SendChat( player, m_GHost->GetLanguage( )->UnhostingGame( m_GHost->GetCurrentGame( )->GetDescription( ) ) ); + m_GHost->GetCurrentGame( )->deleteLater(); + } + } + else + SendChat( player, m_GHost->GetLanguage( )->UnableToUnhostGameNoGameInLobby( ) ); + } + + // + // !W + // + + if( Command == "w" && !Payload.isEmpty( ) ) + { + // extract the name and the message + // e.g. "Varlock hello there!" -> name: "Varlock", message: "hello there!" + + QString Name; + QString Message; + int MessageStart = Payload.indexOf( " " ); + + if( MessageStart != -1 ) + { + Name = Payload.mid( 0, MessageStart ); + Message = Payload.mid( MessageStart + 1 ); + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + (*i)->QueueChatCommand( Message, Name, true ); + } + } + } + else + CONSOLE_Print( "[ADMINGAME] user [" + User + "] sent command [" + Command + "] with payload [" + Payload + "]" ); + + /********************* + * NON ADMIN COMMANDS * + *********************/ + + // + // !PASSWORD + // + + if( Command == "password" && !player->GetLoggedIn( ) ) + { + if( !m_Password.isEmpty( ) && Payload == m_Password ) + { + CONSOLE_Print( "[ADMINGAME] user [" + User + "] logged in" ); + SendChat( player, m_GHost->GetLanguage( )->AdminLoggedIn( ) ); + player->SetLoggedIn( true ); + } + else + { + quint32 LoginAttempts = player->GetLoginAttempts( ) + 1; + player->SetLoginAttempts( LoginAttempts ); + CONSOLE_Print( "[ADMINGAME] user [" + User + "] login attempt failed" ); + SendChat( player, m_GHost->GetLanguage( )->AdminInvalidPassword( QString::number( LoginAttempts ) ) ); + + if( LoginAttempts >= 1 ) + { + player->SetLeftReason( "was kicked for too many failed login attempts" ); + player->SetLeftCode( PLAYERLEAVE_LOBBY ); + player->deleteLater(); + OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); + + // tempban for 5 seconds to prevent bruteforcing + + m_TempBans.push_back( TempBan( player->GetExternalIPString( ), GetTime( ) ) ); + } + } + } + + // always hide chat commands from other players in the admin game + // note: this is actually redundant because we've already set m_MuteLobby = true so this has no effect + // if you actually wanted to relay chat commands you would have to set m_MuteLobby = false AND return false here + + return true; +} diff --git a/src/libghost/game_admin.h b/src/libghost/game_admin.h new file mode 100644 index 0000000..ade601d --- /dev/null +++ b/src/libghost/game_admin.h @@ -0,0 +1,75 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GAME_ADMIN_H +#define GAME_ADMIN_H + +// +// CAdminGame +// + +class CCallableAdminCount; +class CCallableAdminAdd; +class CCallableAdminRemove; +class CCallableBanCount; +// class CCallableBanAdd; +class CCallableBanRemove; + +#include "includes.h" +#include "game_base.h" +#include + +typedef pair PairedAdminCount; +typedef pair PairedAdminAdd; +typedef pair PairedAdminRemove; +typedef pair PairedBanCount; +// typedef pair PairedBanAdd; +typedef pair PairedBanRemove; + +typedef pair TempBan; + +class CAdminGame : public CBaseGame +{ + Q_OBJECT + +public slots: + void EventCallableUpdateTimeout(); + +protected: + QString m_Password; + QList m_TempBans; + QList m_PairedAdminCounts; // vector of paired threaded database admin counts in progress + QList m_PairedAdminAdds; // vector of paired threaded database admin adds in progress + QList m_PairedAdminRemoves; // vector of paired threaded database admin removes in progress + QList m_PairedBanCounts; // vector of paired threaded database ban counts in progress + // QList m_PairedBanAdds; // vector of paired threaded database ban adds in progress + QList m_PairedBanRemoves; // vector of paired threaded database ban removes in progress + +public: + CAdminGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nPassword ); + virtual ~CAdminGame( ); + + virtual void SendAdminChat( QString message ); + virtual void SendWelcomeMessage( CGamePlayer *player ); + virtual void EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ); + virtual bool EventPlayerBotCommand( CGamePlayer *player, QString command, QString payload ); +}; + +#endif diff --git a/ghost/game_base.cpp b/src/libghost/game_base.cpp similarity index 57% rename from ghost/game_base.cpp rename to src/libghost/game_base.cpp index 7e09da6..6c8677f 100644 --- a/ghost/game_base.cpp +++ b/src/libghost/game_base.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,6 @@ #include "util.h" #include "config.h" #include "language.h" -#include "socket.h" #include "ghostdb.h" #include "bnet.h" #include "map.h" @@ -34,8 +33,15 @@ #include "game_base.h" #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include "next_combination.h" @@ -43,10 +49,72 @@ // CBaseGame // -CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16_t nHostPort, unsigned char nGameState, string nGameName, string nOwnerName, string nCreatorName, string nCreatorServer ) +quint32 CBaseGame::m_GlobalHostCounter = 1; + +CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nOwnerName, QString nCreatorName, QString nCreatorServer ) { m_GHost = nGHost; - m_Socket = new CTCPServer( ); + m_Socket = new QTcpServer(this); + QObject::connect(m_Socket, SIGNAL(newConnection()), this, SLOT(EventNewConnection())); + + m_BroadcastTimer.start(3000); + QObject::connect(&m_BroadcastTimer, SIGNAL(timeout()), this, SLOT(EventBroadcastTimeout())); + + m_RefreshTimer.start(3000); + QObject::connect(&m_RefreshTimer, SIGNAL(timeout()), this, SLOT(EventRefreshTimeout())); + + m_MapDataTimer.start(100); + QObject::connect(&m_MapDataTimer, SIGNAL(timeout()), this, SLOT(EventMapDataTimeout())); + + m_CountdownTimer.setInterval(500); + QObject::connect(&m_CountdownTimer, SIGNAL(timeout()), this, SLOT(EventCountdownTimeout())); + + m_AutostartTimer.start(10000); + QObject::connect(&m_AutostartTimer, SIGNAL(timeout()), this, SLOT(EventAutostartTimeout())); + + m_GameOverTimer.setInterval(60000); + QObject::connect(&m_GameOverTimer, SIGNAL(timeout()), this, SLOT(EventGameOverTimeout())); + + m_VotekickTimer.setInterval(60000); + QObject::connect(&m_VotekickTimer, SIGNAL(timeout()), this, SLOT(EventVotekickTimeout())); + + m_SlotInfoTimer.setInterval(500); + m_SlotInfoTimer.setSingleShot(true); + QObject::connect(&m_SlotInfoTimer, SIGNAL(timeout()), this, SLOT(SendAllSlotInfo())); + + m_CallableUpdateTimer.setInterval(200); + QObject::connect(&m_CallableUpdateTimer, SIGNAL(timeout()), this, SLOT(EventCallableUpdateTimeout())); + + m_DownloadCounterTimer.start(1000); + QObject::connect(&m_DownloadCounterTimer, SIGNAL(timeout()), this, SLOT(EventResetDownloadCounter())); + + QObject::connect(&m_AnnounceTimer, SIGNAL(timeout()), this, SLOT(EventAnnounceTimeout())); + + m_DropLaggerTimer.setInterval(60000); + m_DropLaggerTimer.setSingleShot(true); + QObject::connect(&m_DropLaggerTimer, SIGNAL(timeout()), this, SLOT(EventDropLaggerTimeout())); + + m_ResetLagscreenTimer.setInterval(60000); + QObject::connect(&m_ResetLagscreenTimer, SIGNAL(timeout()), this, SLOT(EventResetLagscreenTimeout())); + + m_LoadInGameTimer.setInterval(30000); + QObject::connect(&m_LoadInGameTimer, SIGNAL(timeout()), this, SLOT(EventLoadInGameTimeout())); + + m_LobbyTimeoutTimer.setInterval(m_GHost->m_LobbyTimeLimit * 60000); + m_LobbyTimeoutTimer.setSingleShot(true); + QObject::connect(&m_LobbyTimeoutTimer, SIGNAL(timeout()), this, SLOT(EventLobbyTimeout())); + + m_Latency = m_GHost->m_Latency; + m_SendActionTimer.setInterval(m_Latency); + QObject::connect(&m_SendActionTimer, SIGNAL(timeout()), this, SLOT(EventSendActions())); + + QObject::connect(this, SIGNAL(finishedLoading()), &m_SendActionTimer, SLOT(start())); + QObject::connect(this, SIGNAL(startedLoading()), this, SLOT(EventGameStarted())); + QObject::connect(this, SIGNAL(finishedLoading()), this, SLOT(EventGameLoaded())); + + + + m_RequestedLatency = 0; m_Protocol = new CGameProtocol( m_GHost ); m_Map = new CMap( *nMap ); m_SaveGame = nSaveGame; @@ -56,7 +124,6 @@ CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16 else m_Replay = NULL; - m_Exiting = false; m_Saving = false; m_HostPort = nHostPort; m_GameState = nGameState; @@ -87,37 +154,22 @@ CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16 m_CreatorServer = nCreatorServer; m_HCLCommandString = m_Map->GetMapDefaultHCL( ); m_RandomSeed = GetTicks( ); - m_HostCounter = m_GHost->m_HostCounter++; - m_Latency = m_GHost->m_Latency; + m_HostCounter = GetNewHostCounter( ); m_SyncLimit = m_GHost->m_SyncLimit; m_SyncCounter = 0; m_GameTicks = 0; m_CreationTime = GetTime( ); - m_LastPingTime = GetTime( ); - m_LastRefreshTime = GetTime( ); m_LastDownloadTicks = GetTime( ); m_DownloadCounter = 0; - m_LastDownloadCounterResetTicks = GetTicks( ); - m_LastAnnounceTime = 0; - m_AnnounceInterval = 0; - m_LastAutoStartTime = GetTime( ); m_AutoStartPlayers = 0; - m_LastCountDownTicks = 0; m_CountDownCounter = 0; m_StartedLoadingTicks = 0; m_StartPlayers = 0; - m_LastLagScreenResetTime = 0; m_LastActionSentTicks = 0; - m_LastActionLateBy = 0; m_StartedLaggingTime = 0; - m_LastLagScreenTime = 0; - m_LastReservedSeen = GetTime( ); - m_StartedKickVoteTime = 0; - m_GameOverTime = 0; m_LastPlayerLeaveTicks = 0; m_MinimumScore = 0.0; m_MaximumScore = 0.0; - m_SlotInfoChanged = false; m_Locked = false; m_RefreshMessages = m_GHost->m_RefreshMessages; m_RefreshError = false; @@ -142,7 +194,7 @@ CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16 // we really just want the open/closed/computer entries // so open all the player slots - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 ) { @@ -155,65 +207,74 @@ CBaseGame :: CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, uint16 else m_Slots = m_Map->GetSlots( ); - if( !m_GHost->m_IPBlackListFile.empty( ) ) + if( !m_GHost->m_IPBlackListFile.isEmpty( ) ) { - ifstream in; - in.open( m_GHost->m_IPBlackListFile.c_str( ) ); + QFile f(m_GHost->m_IPBlackListFile); - if( in.fail( ) ) + if( !f.open(QFile::ReadOnly) ) CONSOLE_Print( "[GAME: " + m_GameName + "] error loading IP blacklist file [" + m_GHost->m_IPBlackListFile + "]" ); else { + QTextStream in(&f); CONSOLE_Print( "[GAME: " + m_GameName + "] loading IP blacklist file [" + m_GHost->m_IPBlackListFile + "]" ); - string Line; + QString Line; - while( !in.eof( ) ) + while( !in.atEnd( ) ) { - getline( in, Line ); + Line = in.readLine(); // ignore blank lines and comments - if( Line.empty( ) || Line[0] == '#' ) + if( Line.isEmpty( ) || Line[0] == '#' ) continue; // remove newlines and partial newlines to help fix issues with Windows formatted files on Linux systems - Line.erase( remove( Line.begin( ), Line.end( ), ' ' ), Line.end( ) ); - Line.erase( remove( Line.begin( ), Line.end( ), '\r' ), Line.end( ) ); - Line.erase( remove( Line.begin( ), Line.end( ), '\n' ), Line.end( ) ); + Line.replace(QRegExp("[ \r\n]"), ""); // ignore lines that don't look like IP addresses - if( Line.find_first_not_of( "1234567890." ) != string :: npos ) + if( Line.indexOf( QRegExp("[^0-9\\.]") ) != -1 ) continue; m_IPBlackList.insert( Line ); } - in.close( ); + f.close( ); - CONSOLE_Print( "[GAME: " + m_GameName + "] loaded " + UTIL_ToString( m_IPBlackList.size( ) ) + " lines from IP blacklist file" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] loaded " + QString::number( m_IPBlackList.size( ) ) + " lines from IP blacklist file" ); } } + CreateVirtualHost( ); + // start listening for connections - if( !m_GHost->m_BindAddress.empty( ) ) + if( !m_GHost->m_BindAddress.isEmpty( ) ) CONSOLE_Print( "[GAME: " + m_GameName + "] attempting to bind to address [" + m_GHost->m_BindAddress + "]" ); else CONSOLE_Print( "[GAME: " + m_GameName + "] attempting to bind to all available addresses" ); - if( m_Socket->Listen( m_GHost->m_BindAddress, m_HostPort ) ) - CONSOLE_Print( "[GAME: " + m_GameName + "] listening on port " + UTIL_ToString( m_HostPort ) ); + QHostAddress hostAddr = m_GHost->m_BindAddress == "" ? QHostAddress::Any : QHostAddress(m_GHost->m_BindAddress); + if( m_Socket->listen( hostAddr, m_HostPort ) ) + CONSOLE_Print( "[GAME: " + m_GameName + "] listening on " + hostAddr.toString() + ":" + QString::number( m_Socket->serverPort() ) ); else { - CONSOLE_Print( "[GAME: " + m_GameName + "] error listening on port " + UTIL_ToString( m_HostPort ) ); - m_Exiting = true; + CONSOLE_Print( "[GAME: " + m_GameName + "] error listening on " + hostAddr.toString() + ":" + QString::number( m_HostPort ) ); + deleteLater(); } } CBaseGame :: ~CBaseGame( ) { + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + (*i)->QueueChatCommand( m_GHost->GetLanguage( )->GameIsOver( GetDescription( ) ) ); + + if( (*i)->GetServer( ) == GetCreatorServer( ) ) + (*i)->QueueChatCommand( m_GHost->GetLanguage( )->GameIsOver( GetDescription( ) ), GetCreatorName( ), true ); + } + // save replay // todotodo: put this in a thread @@ -223,8 +284,8 @@ CBaseGame :: ~CBaseGame( ) char Time[17]; memset( Time, 0, sizeof( char ) * 17 ); strftime( Time, sizeof( char ) * 17, "%Y-%m-%d %H-%M", localtime( &Now ) ); - string MinString = UTIL_ToString( ( m_GameTicks / 1000 ) / 60 ); - string SecString = UTIL_ToString( ( m_GameTicks / 1000 ) % 60 ); + QString MinString = QString::number( ( m_GameTicks / 1000 ) / 60 ); + QString SecString = QString::number( ( m_GameTicks / 1000 ) % 60 ); if( MinString.size( ) == 1 ) MinString.insert( 0, "0" ); @@ -233,7 +294,7 @@ CBaseGame :: ~CBaseGame( ) SecString.insert( 0, "0" ); m_Replay->BuildReplay( m_GameName, m_StatString, m_GHost->m_ReplayWar3Version, m_GHost->m_ReplayBuildNumber ); - m_Replay->Save( m_GHost->m_TFT, m_GHost->m_ReplayPath + UTIL_FileSafeName( "GHost++ " + string( Time ) + " " + m_GameName + " (" + MinString + "m" + SecString + "s).w3g" ) ); + m_Replay->Save( m_GHost->m_TFT, m_GHost->m_ReplayPath + UTIL_FileSafeName( "GHost++ " + QString( Time ) + " " + m_GameName + " (" + MinString + "m" + SecString + "s).w3g" ) ); } delete m_Socket; @@ -241,45 +302,27 @@ CBaseGame :: ~CBaseGame( ) delete m_Map; delete m_Replay; - for( vector :: iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) + for( QList :: const_iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) delete *i; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) delete *i; - for( vector :: iterator i = m_ScoreChecks.begin( ); i != m_ScoreChecks.end( ); i++ ) + for( QList :: const_iterator i = m_ScoreChecks.begin( ); i != m_ScoreChecks.end( ); i++ ) m_GHost->m_Callables.push_back( *i ); - while( !m_Actions.empty( ) ) + while( !m_Actions.isEmpty( ) ) { delete m_Actions.front( ); - m_Actions.pop( ); + m_Actions.dequeue( ); } } -uint32_t CBaseGame :: GetNextTimedActionTicks( ) +quint32 CBaseGame :: GetSlotsOccupied( ) const { - // return the number of ticks (ms) until the next "timed action", which for our purposes is the next game update - // the main GHost++ loop will make sure the next loop update happens at or before this value - // note: there's no reason this function couldn't take into account the game's other timers too but they're far less critical - // warning: this function must take into account when actions are not being sent (e.g. during loading or lagging) - - if( !m_GameLoaded || m_Lagging ) - return 50; + quint32 NumSlotsOccupied = 0; - uint32_t TicksSinceLastUpdate = GetTicks( ) - m_LastActionSentTicks; - - if( TicksSinceLastUpdate > m_Latency - m_LastActionLateBy ) - return 0; - else - return m_Latency - m_LastActionLateBy - TicksSinceLastUpdate; -} - -uint32_t CBaseGame :: GetSlotsOccupied( ) -{ - uint32_t NumSlotsOccupied = 0; - - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: const_iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED ) NumSlotsOccupied++; @@ -288,11 +331,11 @@ uint32_t CBaseGame :: GetSlotsOccupied( ) return NumSlotsOccupied; } -uint32_t CBaseGame :: GetSlotsOpen( ) +quint32 CBaseGame :: GetSlotsOpen( ) const { - uint32_t NumSlotsOpen = 0; + quint32 NumSlotsOpen = 0; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: const_iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OPEN ) NumSlotsOpen++; @@ -301,9 +344,9 @@ uint32_t CBaseGame :: GetSlotsOpen( ) return NumSlotsOpen; } -uint32_t CBaseGame :: GetNumPlayers( ) +quint32 CBaseGame :: GetNumPlayers( ) const { - uint32_t NumPlayers = GetNumHumanPlayers( ); + quint32 NumPlayers = GetNumHumanPlayers( ); if( m_FakePlayerPID != 255 ) NumPlayers++; @@ -311,11 +354,11 @@ uint32_t CBaseGame :: GetNumPlayers( ) return NumPlayers; } -uint32_t CBaseGame :: GetNumHumanPlayers( ) +quint32 CBaseGame :: GetNumHumanPlayers( ) const { - uint32_t NumHumanPlayers = 0; + quint32 NumHumanPlayers = 0; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) NumHumanPlayers++; @@ -324,219 +367,295 @@ uint32_t CBaseGame :: GetNumHumanPlayers( ) return NumHumanPlayers; } -string CBaseGame :: GetDescription( ) +QString CBaseGame :: GetDescription( ) const { - string Description = m_GameName + " : " + m_OwnerName + " : " + UTIL_ToString( GetNumHumanPlayers( ) ) + "/" + UTIL_ToString( m_GameLoading || m_GameLoaded ? m_StartPlayers : m_Slots.size( ) ); + QString Description = m_GameName + " : " + m_OwnerName + " : " + QString::number( GetNumHumanPlayers( ) ) + "/" + QString::number( m_GameLoading || m_GameLoaded ? m_StartPlayers : m_Slots.size( ) ); if( m_GameLoading || m_GameLoaded ) - Description += " : " + UTIL_ToString( ( m_GameTicks / 1000 ) / 60 ) + "m"; + Description += " : " + QString::number( ( m_GameTicks / 1000 ) / 60 ) + "m"; else - Description += " : " + UTIL_ToString( ( GetTime( ) - m_CreationTime ) / 60 ) + "m"; + Description += " : " + QString::number( ( GetTime( ) - m_CreationTime ) / 60 ) + "m"; return Description; } -void CBaseGame :: SetAnnounce( uint32_t interval, string message ) +void CBaseGame :: SetAnnounce( quint32 interval, const QString &message ) { - m_AnnounceInterval = interval; + m_AnnounceTimer.start(1000 * interval); m_AnnounceMessage = message; - m_LastAnnounceTime = GetTime( ); } -unsigned int CBaseGame :: SetFD( void *fd, void *send_fd, int *nfds ) +void CBaseGame::CheckGameLoaded() { - unsigned int NumFDs = 0; + bool FinishedLoading = true; - if( m_Socket ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - m_Socket->SetFD( (fd_set *)fd, (fd_set *)send_fd, nfds ); - NumFDs++; - } + FinishedLoading = (*i)->GetFinishedLoading( ); - for( vector :: iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) - { - if( (*i)->GetSocket( ) ) - { - (*i)->GetSocket( )->SetFD( (fd_set *)fd, (fd_set *)send_fd, nfds ); - NumFDs++; - } + if( !FinishedLoading ) + break; } - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + if( FinishedLoading ) { - if( (*i)->GetSocket( ) ) - { - (*i)->GetSocket( )->SetFD( (fd_set *)fd, (fd_set *)send_fd, nfds ); - NumFDs++; - } + m_LastActionSentTicks = GetTicks( ); + m_GameLoading = false; + m_GameLoaded = true; + emit finishedLoading(); + return; } - - return NumFDs; } -bool CBaseGame :: Update( void *fd, void *send_fd ) +void CBaseGame::EventLoadInGameTimeout() { - // update callables + // reset the "lag" screen (the load-in-game screen) every 30 seconds + + bool UsingGProxy = false; - for( vector :: iterator i = m_ScoreChecks.begin( ); i != m_ScoreChecks.end( ); ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - if( (*i)->GetReady( ) ) + if( (*i)->GetGProxy( ) ) + UsingGProxy = true; + } + + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( (*i)->GetFinishedLoading( ) ) { - double Score = (*i)->GetResult( ); + // stop the lag screen - for( vector :: iterator j = m_Potentials.begin( ); j != m_Potentials.end( ); j++ ) + for( QList :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) { - if( (*j)->GetJoinPlayer( ) && (*j)->GetJoinPlayer( )->GetName( ) == (*i)->GetName( ) ) - EventPlayerJoinedWithScore( *j, (*j)->GetJoinPlayer( ), Score ); + if( !(*j)->GetFinishedLoading( ) ) + Send( *i, m_Protocol->SEND_W3GS_STOP_LAG( *j, true ) ); } - m_GHost->m_DB->RecoverCallable( *i ); - delete *i; - i = m_ScoreChecks.erase( i ); + // send an empty update + // this resets the lag screen timer but creates a rather annoying problem + // in order to prevent a desync we must make sure every player receives the exact same "desyncable game data" (updates and player leaves) in the exact same order + // unfortunately we cannot send updates to players who are still loading the map, so we buffer the updates to those players (see the else clause a few lines down for the code) + // in addition to this we must ensure any player leave messages are sent in the exact same position relative to these updates so those must be buffered too + + if( UsingGProxy && !(*i)->GetGProxy( ) ) + { + // we must send empty actions to non-GProxy++ players + // GProxy++ will insert these itself so we don't need to send them to GProxy++ players + // empty actions are used to extend the time a player can use when reconnecting + + for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) + Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); + } + + Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); + + // start the lag screen + + Send( *i, m_Protocol->SEND_W3GS_START_LAG( m_Players, true ) ); } else - i++; - } + { + // buffer the empty update since the player is still loading the map - // update players + if( UsingGProxy && !(*i)->GetGProxy( ) ) + { + // we must send empty actions to non-GProxy++ players + // GProxy++ will insert these itself so we don't need to send them to GProxy++ players + // empty actions are used to extend the time a player can use when reconnecting - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); ) - { - if( (*i)->Update( fd ) ) - { - EventPlayerDeleted( *i ); - delete *i; - i = m_Players.erase( i ); + for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) + (*i)->AddLoadInGameData( m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); + } + + (*i)->AddLoadInGameData( m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); } - else - i++; } - for( vector :: iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); ) + // add actions to replay + + if( m_Replay ) { - if( (*i)->Update( fd ) ) + if( UsingGProxy ) { - // flush the socket (e.g. in case a rejection message is queued) - - if( (*i)->GetSocket( ) ) - (*i)->GetSocket( )->DoSend( (fd_set *)send_fd ); - - delete *i; - i = m_Potentials.erase( i ); + for( unsigned char i = 0; i < m_GProxyEmptyActions; i++ ) + m_Replay->AddTimeSlot( 0, QQueue( ) ); } - else - i++; + + m_Replay->AddTimeSlot( 0, QQueue( ) ); } - // create the virtual host player + // Warcraft III doesn't seem to respond to empty actions - if( !m_GameLoading && !m_GameLoaded && GetNumPlayers( ) < 12 ) - CreateVirtualHost( ); + /* if( UsingGProxy ) + m_SyncCounter += m_GProxyEmptyActions; - // unlock the game + m_SyncCounter++; */ +} - if( m_Locked && !GetPlayerFromName( m_OwnerName, false ) ) +void CBaseGame::EventSendActions() +{ + if (m_Lagging) { - SendAllChat( m_GHost->m_Language->GameUnlocked( ) ); - m_Locked = false; + m_SendActionTimer.stop(); + return; } - // ping every 5 seconds - // changed this to ping during game loading as well to hopefully fix some problems with people disconnecting during loading - // changed this to ping during the game as well + // send actions every m_Latency milliseconds + // actions are at the heart of every Warcraft 3 game but luckily we don't need to know their contents to relay them + // we queue player actions in EventPlayerAction then just resend them in batches to all players here + + SendAllActions( ); +} - if( GetTime( ) - m_LastPingTime >= 5 ) +void CBaseGame::EventBroadcastTimeout() +{ + // we broadcast the game to the local network every 3 seconds so we hijack this timer for our nefarious purposes + // however we only want to broadcast if the countdown hasn't started + // see the !sendlan code later in this file for some more information about how this works + // todotodo: should we send a game cancel message somewhere? we'll need to implement a host counter for it to work + + if (m_GameLoading || m_GameLoaded) { - // note: we must send pings to players who are downloading the map because Warcraft III disconnects from the lobby if it doesn't receive a ping every ~90 seconds - // so if the player takes longer than 90 seconds to download the map they would be disconnected unless we keep sending pings - // todotodo: ignore pings received from players who have recently finished downloading the map + m_BroadcastTimer.stop(); + return; + } - SendAll( m_Protocol->SEND_W3GS_PING_FROM_HOST( ) ); + // construct a fixed host counter which will be used to identify players from this "realm" (i.e. LAN) + // the fixed host counter's 4 most significant bits will contain a 4 bit ID (0-15) + // the rest of the fixed host counter will contain the 28 least significant bits of the actual host counter + // since we're destroying 4 bits of information here the actual host counter should not be greater than 2^28 which is a reasonable assumption + // when a player joins a game we can obtain the ID from the received host counter + // note: LAN broadcasts use an ID of 0, battle.net refreshes use an ID of 1-10, the rest are unused - // we also broadcast the game to the local network every 5 seconds so we hijack this timer for our nefarious purposes - // however we only want to broadcast if the countdown hasn't started - // see the !sendlan code later in this file for some more information about how this works - // todotodo: should we send a game cancel message somewhere? we'll need to implement a host counter for it to work + quint32 FixedHostCounter = m_HostCounter & 0x0FFFFFFF; - if( !m_CountDownStarted ) - { - // construct a fixed host counter which will be used to identify players from this "realm" (i.e. LAN) - // the fixed host counter's 4 most significant bits will contain a 4 bit ID (0-15) - // the rest of the fixed host counter will contain the 28 least significant bits of the actual host counter - // since we're destroying 4 bits of information here the actual host counter should not be greater than 2^28 which is a reasonable assumption - // when a player joins a game we can obtain the ID from the received host counter - // note: LAN broadcasts use an ID of 0, battle.net refreshes use an ID of 1-10, the rest are unused + if( m_SaveGame ) + { + // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) + + quint32 MapGameType = MAPGAMETYPE_SAVEDGAME; + QByteArray MapWidth; + MapWidth.push_back( (char)0 ); + MapWidth.push_back( (char)0 ); + QByteArray MapHeight; + MapHeight.push_back( (char)0 ); + MapHeight.push_back( (char)0 ); + m_GHost->SendUdpBroadcast( + m_Protocol->SEND_W3GS_GAMEINFO( + m_GHost->m_TFT, + m_GHost->m_LANWar3Version, + Util::fromUInt32( MapGameType), + m_Map->GetMapGameFlags( ), + MapWidth, + MapHeight, + m_GameName, + "Varlock", + GetTime( ) - m_CreationTime, + "Save\\Multiplayer\\" + m_SaveGame->GetFileNameNoPath( ), + m_SaveGame->GetMagicNumber( ), + 12, + 12, + m_HostPort, + FixedHostCounter ), + 6112); + } + else + { + // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) + // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) + + quint32 MapGameType = MAPGAMETYPE_UNKNOWN0; + m_GHost->SendUdpBroadcast( + m_Protocol->SEND_W3GS_GAMEINFO( + m_GHost->m_TFT, + m_GHost->m_LANWar3Version, + Util::fromUInt32( MapGameType), + m_Map->GetMapGameFlags( ), + m_Map->GetMapWidth( ), + m_Map->GetMapHeight( ), + m_GameName, + "Varlock", + GetTime( ) - m_CreationTime, + m_Map->GetMapPath( ), + m_Map->GetMapCRC( ), + 12, + 12, + m_HostPort, + FixedHostCounter ), + 6112 ); + } +} - uint32_t FixedHostCounter = m_HostCounter & 0x0FFFFFFF; +void CBaseGame::EventTryAutoRehost() +{ + // there's a slim chance that this isn't actually an autohosted game since there is no explicit autohost flag + // however, if autohosting is enabled and this game is public and this game is set to autostart, it's probably autohosted + // so rehost it using the current autohost game name - if( m_SaveGame ) - { - // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) - - uint32_t MapGameType = MAPGAMETYPE_SAVEDGAME; - BYTEARRAY MapWidth; - MapWidth.push_back( 0 ); - MapWidth.push_back( 0 ); - BYTEARRAY MapHeight; - MapHeight.push_back( 0 ); - MapHeight.push_back( 0 ); - m_GHost->m_UDPSocket->Broadcast( 6112, m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, UTIL_CreateByteArray( MapGameType, false ), m_Map->GetMapGameFlags( ), MapWidth, MapHeight, m_GameName, "Varlock", GetTime( ) - m_CreationTime, "Save\\Multiplayer\\" + m_SaveGame->GetFileNameNoPath( ), m_SaveGame->GetMagicNumber( ), 12, 12, m_HostPort, FixedHostCounter ) ); - } - else - { - // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) - // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) + m_HostCounter = GetNewHostCounter( ); + QString GameName = m_GHost->m_AutoHostGameName + " #" + QString::number( m_HostCounter ); + CONSOLE_Print( "[GAME: " + m_GameName + "] automatically trying to rehost as public game [" + GameName + "] due to refresh failure" ); + m_LastGameName = m_GameName; + m_GameName = GameName; - uint32_t MapGameType = MAPGAMETYPE_UNKNOWN0; - m_GHost->m_UDPSocket->Broadcast( 6112, m_Protocol->SEND_W3GS_GAMEINFO( m_GHost->m_TFT, m_GHost->m_LANWar3Version, UTIL_CreateByteArray( MapGameType, false ), m_Map->GetMapGameFlags( ), m_Map->GetMapWidth( ), m_Map->GetMapHeight( ), m_GameName, "Varlock", GetTime( ) - m_CreationTime, m_Map->GetMapPath( ), m_Map->GetMapCRC( ), 12, 12, m_HostPort, FixedHostCounter ) ); - } - } + m_RefreshError = false; + + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + (*i)->QueueGameUncreate( ); + (*i)->QueueEnterChat( ); - m_LastPingTime = GetTime( ); + // the game creation message will be sent on the next refresh } - // auto rehost if there was a refresh error in autohosted games + m_CreationTime = GetTime( ); +} - if( m_RefreshError && !m_CountDownStarted && m_GameState == GAME_PUBLIC && !m_GHost->m_AutoHostGameName.empty( ) && m_GHost->m_AutoHostMaximumGames != 0 && m_GHost->m_AutoHostAutoStartPlayers != 0 && m_AutoStartPlayers != 0 ) +void CBaseGame::EventRefreshError() +{ + if (m_GameLoading || m_GameLoaded) { - // there's a slim chance that this isn't actually an autohosted game since there is no explicit autohost flag - // however, if autohosting is enabled and this game is public and this game is set to autostart, it's probably autohosted - // so rehost it using the current autohost game name - - string GameName = m_GHost->m_AutoHostGameName + " #" + UTIL_ToString( m_GHost->m_HostCounter ); - CONSOLE_Print( "[GAME: " + m_GameName + "] automatically trying to rehost as public game [" + GameName + "] due to refresh failure" ); - m_LastGameName = m_GameName; - m_GameName = GameName; - m_HostCounter = m_GHost->m_HostCounter++; - m_RefreshError = false; + m_RefreshTimer.stop(); + return; + } - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - (*i)->QueueGameUncreate( ); - (*i)->QueueEnterChat( ); + if (m_CountDownStarted) + return; + DEBUG_Print("EventRefreshError"); - // the game creation message will be sent on the next refresh - } + // auto rehost if there was a refresh error in autohosted games + m_RefreshError = true; + + if(m_GameState == GAME_PUBLIC && + !m_GHost->m_AutoHostGameName.isEmpty( ) && + m_GHost->m_AutoHostMaximumGames != 0 && + m_GHost->m_AutoHostAutoStartPlayers != 0 && + m_AutoStartPlayers != 0 ) + QTimer::singleShot(5000, this, SLOT(EventTryAutoRehost())); +} - m_CreationTime = GetTime( ); - m_LastRefreshTime = GetTime( ); +void CBaseGame::EventRefreshTimeout() +{ + if (m_GameLoading || m_GameLoaded) + { + m_RefreshTimer.stop(); + return; } // refresh every 3 seconds - - if( !m_RefreshError && !m_CountDownStarted && m_GameState == GAME_PUBLIC && GetSlotsOpen( ) > 0 && GetTime( ) - m_LastRefreshTime >= 3 ) + if( !m_RefreshError && m_GameState == GAME_PUBLIC && GetSlotsOpen( ) > 0) { // send a game refresh packet to each battle.net connection bool Refreshed = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { // don't queue a game refresh message if the queue contains more than 1 packet because they're very low priority if( (*i)->GetOutPacketsQueued( ) <= 1 ) { - (*i)->QueueGameRefresh( m_GameState, m_GameName, string( ), m_Map, m_SaveGame, GetTime( ) - m_CreationTime, m_HostCounter ); + (*i)->QueueGameRefresh( m_GameState, m_GameName, QString( ), m_Map, m_SaveGame, GetTime( ) - m_CreationTime, m_HostCounter ); Refreshed = true; } } @@ -544,557 +663,206 @@ bool CBaseGame :: Update( void *fd, void *send_fd ) // only print the "game refreshed" message if we actually refreshed on at least one battle.net server if( m_RefreshMessages && Refreshed ) - SendAllChat( m_GHost->m_Language->GameRefreshed( ) ); - - m_LastRefreshTime = GetTime( ); + SendAllChat( m_GHost->GetLanguage( )->GameRefreshed( ) ); } +} - // send more map data - - if( !m_GameLoading && !m_GameLoaded && GetTicks( ) - m_LastDownloadCounterResetTicks >= 1000 ) +void CBaseGame::EventResetDownloadCounter() +{ + // 1 Hz + if (m_GameLoading || m_GameLoaded ) { - // hackhack: another timer hijack is in progress here - // since the download counter is reset once per second it's a great place to update the slot info if necessary - - if( m_SlotInfoChanged ) - SendAllSlotInfo( ); - - m_DownloadCounter = 0; - m_LastDownloadCounterResetTicks = GetTicks( ); + m_DownloadCounterTimer.stop(); + return; } - if( !m_GameLoading && !m_GameLoaded && GetTicks( ) - m_LastDownloadTicks >= 100 ) - { - uint32_t Downloaders = 0; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetDownloadStarted( ) && !(*i)->GetDownloadFinished( ) ) - { - Downloaders++; - - if( m_GHost->m_MaxDownloaders > 0 && Downloaders > m_GHost->m_MaxDownloaders ) - break; - - // send up to 100 pieces of the map at once so that the download goes faster - // if we wait for each MAPPART packet to be acknowledged by the client it'll take a long time to download - // this is because we would have to wait the round trip time (the ping time) between sending every 1442 bytes of map data - // doing it this way allows us to send at least 140 KB in each round trip interval which is much more reasonable - // the theoretical throughput is [140 KB * 1000 / ping] in KB/sec so someone with 100 ping (round trip ping, not LC ping) could download at 1400 KB/sec - // note: this creates a queue of map data which clogs up the connection when the client is on a slower connection (e.g. dialup) - // in this case any changes to the lobby are delayed by the amount of time it takes to send the queued data (i.e. 140 KB, which could be 30 seconds or more) - // for example, players joining and leaving, slot changes, chat messages would all appear to happen much later for the low bandwidth player - // note: the throughput is also limited by the number of times this code is executed each second - // e.g. if we send the maximum amount (140 KB) 10 times per second the theoretical throughput is 1400 KB/sec - // therefore the maximum throughput is 1400 KB/sec regardless of ping and this value slowly diminishes as the player's ping increases - // in addition to this, the throughput is limited by the configuration value bot_maxdownloadspeed - // in summary: the actual throughput is MIN( 140 * 1000 / ping, 1400, bot_maxdownloadspeed ) in KB/sec assuming only one player is downloading the map - - uint32_t MapSize = UTIL_ByteArrayToUInt32( m_Map->GetMapSize( ), false ); - - while( (*i)->GetLastMapPartSent( ) < (*i)->GetLastMapPartAcked( ) + 1442 * 100 && (*i)->GetLastMapPartSent( ) < MapSize ) - { - if( (*i)->GetLastMapPartSent( ) == 0 ) - { - // overwrite the "started download ticks" since this is the first time we've sent any map data to the player - // prior to this we've only determined if the player needs to download the map but it's possible we could have delayed sending any data due to download limits - - (*i)->SetStartedDownloadingTicks( GetTicks( ) ); - } - - // limit the download speed if we're sending too much data - // the download counter is the # of map bytes downloaded in the last second (it's reset once per second) - - if( m_GHost->m_MaxDownloadSpeed > 0 && m_DownloadCounter > m_GHost->m_MaxDownloadSpeed * 1024 ) - break; - - Send( *i, m_Protocol->SEND_W3GS_MAPPART( GetHostPID( ), (*i)->GetPID( ), (*i)->GetLastMapPartSent( ), m_Map->GetMapData( ) ) ); - (*i)->SetLastMapPartSent( (*i)->GetLastMapPartSent( ) + 1442 ); - m_DownloadCounter += 1442; - } - } - } - - m_LastDownloadTicks = GetTicks( ); - } + m_DownloadCounter = 0; +} +void CBaseGame::EventAnnounceTimeout() +{ // announce every m_AnnounceInterval seconds - if( !m_AnnounceMessage.empty( ) && !m_CountDownStarted && GetTime( ) - m_LastAnnounceTime >= m_AnnounceInterval ) - { - SendAllChat( m_AnnounceMessage ); - m_LastAnnounceTime = GetTime( ); - } - - // kick players who don't spoof check within 20 seconds when spoof checks are required and the game is autohosted - - if( !m_CountDownStarted && m_GHost->m_RequireSpoofChecks && m_GameState == GAME_PUBLIC && !m_GHost->m_AutoHostGameName.empty( ) && m_GHost->m_AutoHostMaximumGames != 0 && m_GHost->m_AutoHostAutoStartPlayers != 0 && m_AutoStartPlayers != 0 ) + if( m_AnnounceMessage.isEmpty( ) ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( !(*i)->GetSpoofed( ) && GetTime( ) - (*i)->GetJoinTime( ) >= 20 ) - { - (*i)->SetDeleteMe( true ); - (*i)->SetLeftReason( m_GHost->m_Language->WasKickedForNotSpoofChecking( ) ); - (*i)->SetLeftCode( PLAYERLEAVE_LOBBY ); - OpenSlot( GetSIDFromPID( (*i)->GetPID( ) ), false ); - } - } - } - - // try to auto start every 10 seconds - - if( !m_CountDownStarted && m_AutoStartPlayers != 0 && GetTime( ) - m_LastAutoStartTime >= 10 ) - { - StartCountDownAuto( m_GHost->m_RequireSpoofChecks ); - m_LastAutoStartTime = GetTime( ); + m_AnnounceTimer.stop(); + return; } - // countdown every 500 ms - - if( m_CountDownStarted && GetTicks( ) - m_LastCountDownTicks >= 500 ) - { - if( m_CountDownCounter > 0 ) - { - // we use a countdown counter rather than a "finish countdown time" here because it might alternately round up or down the count - // this sometimes resulted in a countdown of e.g. "6 5 3 2 1" during my testing which looks pretty dumb - // doing it this way ensures it's always "5 4 3 2 1" but each interval might not be *exactly* the same length - - SendAllChat( UTIL_ToString( m_CountDownCounter ) + ". . ." ); - m_CountDownCounter--; - } - else if( !m_GameLoading && !m_GameLoaded ) - EventGameStarted( ); - - m_LastCountDownTicks = GetTicks( ); - } + if (m_CountDownStarted) + return; - // check if the lobby is "abandoned" and needs to be closed since it will never start + SendAllChat( m_AnnounceMessage ); +} - if( !m_GameLoading && !m_GameLoaded && m_AutoStartPlayers == 0 && m_GHost->m_LobbyTimeLimit > 0 ) +void CBaseGame::EventMapDataTimeout() +{ + if (m_GameLoading || m_GameLoaded ) { - // check if there's a player with reserved status in the game - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetReserved( ) ) - m_LastReservedSeen = GetTime( ); - } - - // check if we've hit the time limit - - if( GetTime( ) - m_LastReservedSeen >= m_GHost->m_LobbyTimeLimit * 60 ) - { - CONSOLE_Print( "[GAME: " + m_GameName + "] is over (lobby time limit hit)" ); - return true; - } + m_MapDataTimer.stop(); + return; } - // check if the game is loaded + quint32 Downloaders = 0; - if( m_GameLoading ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - bool FinishedLoading = true; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + if( (*i)->GetDownloadStarted( ) && !(*i)->GetDownloadFinished( ) ) { - FinishedLoading = (*i)->GetFinishedLoading( ); + Downloaders++; - if( !FinishedLoading ) + if( m_GHost->m_MaxDownloaders > 0 && Downloaders > m_GHost->m_MaxDownloaders ) break; - } - - if( FinishedLoading ) - { - m_LastActionSentTicks = GetTicks( ); - m_GameLoading = false; - m_GameLoaded = true; - EventGameLoaded( ); - } - else - { - // reset the "lag" screen (the load-in-game screen) every 30 seconds - - if( m_LoadInGame && GetTime( ) - m_LastLagScreenResetTime >= 30 ) - { - bool UsingGProxy = false; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetGProxy( ) ) - UsingGProxy = true; - } - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetFinishedLoading( ) ) - { - // stop the lag screen - - for( vector :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) - { - if( !(*j)->GetFinishedLoading( ) ) - Send( *i, m_Protocol->SEND_W3GS_STOP_LAG( *j, true ) ); - } - - // send an empty update - // this resets the lag screen timer but creates a rather annoying problem - // in order to prevent a desync we must make sure every player receives the exact same "desyncable game data" (updates and player leaves) in the exact same order - // unfortunately we cannot send updates to players who are still loading the map, so we buffer the updates to those players (see the else clause a few lines down for the code) - // in addition to this we must ensure any player leave messages are sent in the exact same position relative to these updates so those must be buffered too - - if( UsingGProxy && !(*i)->GetGProxy( ) ) - { - // we must send empty actions to non-GProxy++ players - // GProxy++ will insert these itself so we don't need to send them to GProxy++ players - // empty actions are used to extend the time a player can use when reconnecting - - for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) - Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - } - - Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - - // start the lag screen - - Send( *i, m_Protocol->SEND_W3GS_START_LAG( m_Players, true ) ); - } - else - { - // buffer the empty update since the player is still loading the map - - if( UsingGProxy && !(*i)->GetGProxy( ) ) - { - // we must send empty actions to non-GProxy++ players - // GProxy++ will insert these itself so we don't need to send them to GProxy++ players - // empty actions are used to extend the time a player can use when reconnecting - - for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) - (*i)->AddLoadInGameData( m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - } - - (*i)->AddLoadInGameData( m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - } - } - - // add actions to replay - - if( m_Replay ) - { - if( UsingGProxy ) - { - for( unsigned char i = 0; i < m_GProxyEmptyActions; i++ ) - m_Replay->AddTimeSlot( 0, queue( ) ); - } - - m_Replay->AddTimeSlot( 0, queue( ) ); - } - - // Warcraft III doesn't seem to respond to empty actions - - /* if( UsingGProxy ) - m_SyncCounter += m_GProxyEmptyActions; - - m_SyncCounter++; */ - m_LastLagScreenResetTime = GetTime( ); - } - } - } - - // keep track of the largest sync counter (the number of keepalive packets received by each player) - // if anyone falls behind by more than m_SyncLimit keepalives we start the lag screen - - if( m_GameLoaded ) - { - // check if anyone has started lagging - // we consider a player to have started lagging if they're more than m_SyncLimit keepalives behind - - if( !m_Lagging ) - { - string LaggingString; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( m_SyncCounter - (*i)->GetSyncCounter( ) > m_SyncLimit ) - { - (*i)->SetLagging( true ); - (*i)->SetStartedLaggingTicks( GetTicks( ) ); - m_Lagging = true; - m_StartedLaggingTime = GetTime( ); - - if( LaggingString.empty( ) ) - LaggingString = (*i)->GetName( ); - else - LaggingString += ", " + (*i)->GetName( ); - } - } - - if( m_Lagging ) - { - // start the lag screen - - CONSOLE_Print( "[GAME: " + m_GameName + "] started lagging on [" + LaggingString + "]" ); - SendAll( m_Protocol->SEND_W3GS_START_LAG( m_Players ) ); - - // reset everyone's drop vote - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - (*i)->SetDropVote( false ); - - m_LastLagScreenResetTime = GetTime( ); - } - } - - if( m_Lagging ) - { - bool UsingGProxy = false; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetGProxy( ) ) - UsingGProxy = true; - } - - uint32_t WaitTime = 60; - - if( UsingGProxy ) - WaitTime = ( m_GProxyEmptyActions + 1 ) * 60; - - if( GetTime( ) - m_StartedLaggingTime >= WaitTime ) - StopLaggers( m_GHost->m_Language->WasAutomaticallyDroppedAfterSeconds( UTIL_ToString( WaitTime ) ) ); - - // we cannot allow the lag screen to stay up for more than ~65 seconds because Warcraft III disconnects if it doesn't receive an action packet at least this often - // one (easy) solution is to simply drop all the laggers if they lag for more than 60 seconds - // another solution is to reset the lag screen the same way we reset it when using load-in-game - // this is required in order to give GProxy++ clients more time to reconnect - - if( GetTime( ) - m_LastLagScreenResetTime >= 60 ) - { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - // stop the lag screen - - for( vector :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) - { - if( (*j)->GetLagging( ) ) - Send( *i, m_Protocol->SEND_W3GS_STOP_LAG( *j ) ); - } - - // send an empty update - // this resets the lag screen timer - - if( UsingGProxy && !(*i)->GetGProxy( ) ) - { - // we must send additional empty actions to non-GProxy++ players - // GProxy++ will insert these itself so we don't need to send them to GProxy++ players - // empty actions are used to extend the time a player can use when reconnecting - for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) - Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - } - - Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); - - // start the lag screen - - Send( *i, m_Protocol->SEND_W3GS_START_LAG( m_Players ) ); - } - - // add actions to replay - - if( m_Replay ) - { - if( UsingGProxy ) - { - for( unsigned char i = 0; i < m_GProxyEmptyActions; i++ ) - m_Replay->AddTimeSlot( 0, queue( ) ); - } - - m_Replay->AddTimeSlot( 0, queue( ) ); - } - - // Warcraft III doesn't seem to respond to empty actions - - /* if( UsingGProxy ) - m_SyncCounter += m_GProxyEmptyActions; - - m_SyncCounter++; */ - m_LastLagScreenResetTime = GetTime( ); - } - - // check if anyone has stopped lagging normally - // we consider a player to have stopped lagging if they're less than half m_SyncLimit keepalives behind - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + // send up to 100 pieces of the map at once so that the download goes faster + // if we wait for each MAPPART packet to be acknowledged by the client it'll take a long time to download + // this is because we would have to wait the round trip time (the ping time) between sending every 1442 bytes of map data + // doing it this way allows us to send at least 140 KB in each round trip interval which is much more reasonable + // the theoretical throughput is [140 KB * 1000 / ping] in KB/sec so someone with 100 ping (round trip ping, not LC ping) could download at 1400 KB/sec + // note: this creates a queue of map data which clogs up the connection when the client is on a slower connection (e.g. dialup) + // in this case any changes to the lobby are delayed by the amount of time it takes to send the queued data (i.e. 140 KB, which could be 30 seconds or more) + // for example, players joining and leaving, slot changes, chat messages would all appear to happen much later for the low bandwidth player + // note: the throughput is also limited by the number of times this code is executed each second + // e.g. if we send the maximum amount (140 KB) 10 times per second the theoretical throughput is 1400 KB/sec + // therefore the maximum throughput is 1400 KB/sec regardless of ping and this value slowly diminishes as the player's ping increases + // in addition to this, the throughput is limited by the configuration value bot_maxdownloadspeed + // in summary: the actual throughput is MIN( 140 * 1000 / ping, 1400, bot_maxdownloadspeed ) in KB/sec assuming only one player is downloading the map + + quint32 MapSize = Util::extractUInt32(m_Map->GetMapSize( )); + + while( (*i)->GetLastMapPartSent( ) < (*i)->GetLastMapPartAcked( ) + 1442 * 100 && (*i)->GetLastMapPartSent( ) < MapSize ) { - if( (*i)->GetLagging( ) && m_SyncCounter - (*i)->GetSyncCounter( ) < m_SyncLimit / 2 ) + if( (*i)->GetLastMapPartSent( ) == 0 ) { - // stop the lag screen for this player + // overwrite the "started download ticks" since this is the first time we've sent any map data to the player + // prior to this we've only determined if the player needs to download the map but it's possible we could have delayed sending any data due to download limits - CONSOLE_Print( "[GAME: " + m_GameName + "] stopped lagging on [" + (*i)->GetName( ) + "]" ); - SendAll( m_Protocol->SEND_W3GS_STOP_LAG( *i ) ); - (*i)->SetLagging( false ); - (*i)->SetStartedLaggingTicks( 0 ); + (*i)->SetStartedDownloadingTicks( GetTicks( ) ); } - } - // check if everyone has stopped lagging + // limit the download speed if we're sending too much data + // the download counter is the # of map bytes downloaded in the last second (it's reset once per second) - bool Lagging = false; + if( m_GHost->m_MaxDownloadSpeed > 0 && m_DownloadCounter > m_GHost->m_MaxDownloadSpeed * 1024 ) + break; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetLagging( ) ) - Lagging = true; + Send( *i, m_Protocol->SEND_W3GS_MAPPART( GetHostPID( ), (*i)->GetPID( ), (*i)->GetLastMapPartSent( ), m_Map->GetMapData( ) ) ); + (*i)->SetLastMapPartSent( (*i)->GetLastMapPartSent( ) + 1442 ); + m_DownloadCounter += 1442; } - - m_Lagging = Lagging; - - // reset m_LastActionSentTicks because we want the game to stop running while the lag screen is up - - m_LastActionSentTicks = GetTicks( ); - - // keep track of the last lag screen time so we can avoid timing out players - - m_LastLagScreenTime = GetTime( ); } } +} - // send actions every m_Latency milliseconds - // actions are at the heart of every Warcraft 3 game but luckily we don't need to know their contents to relay them - // we queue player actions in EventPlayerAction then just resend them in batches to all players here - - if( m_GameLoaded && !m_Lagging && GetTicks( ) - m_LastActionSentTicks >= m_Latency - m_LastActionLateBy ) - SendAllActions( ); - - // expire the votekick - - if( !m_KickVotePlayer.empty( ) && GetTime( ) - m_StartedKickVoteTime >= 60 ) +void CBaseGame::EventCountdownTimeout() +{ + if( m_CountDownCounter <= 0 ) { - CONSOLE_Print( "[GAME: " + m_GameName + "] votekick against player [" + m_KickVotePlayer + "] expired" ); - SendAllChat( m_GHost->m_Language->VoteKickExpired( m_KickVotePlayer ) ); - m_KickVotePlayer.clear( ); - m_StartedKickVoteTime = 0; + emit startedLoading(); + m_CountdownTimer.stop(); + return; } - // start the gameover timer if there's only one player left + SendAllChat( QString::number( m_CountDownCounter ) + ". . ." ); + m_CountDownCounter--; +} - if( m_Players.size( ) == 1 && m_FakePlayerPID == 255 && m_GameOverTime == 0 && ( m_GameLoading || m_GameLoaded ) ) +void CBaseGame::EventAutostartTimeout() +{ + if (m_GameLoading || m_GameLoaded) { - CONSOLE_Print( "[GAME: " + m_GameName + "] gameover timer started (one player left)" ); - m_GameOverTime = GetTime( ); + m_AutostartTimer.stop(); + return; } - // finish the gameover timer - - if( m_GameOverTime != 0 && GetTime( ) - m_GameOverTime >= 60 ) - { - bool AlreadyStopped = true; - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( !(*i)->GetDeleteMe( ) ) - { - AlreadyStopped = false; - break; - } - } + // try to auto start every 10 seconds - if( !AlreadyStopped ) - { - CONSOLE_Print( "[GAME: " + m_GameName + "] is over (gameover timer finished)" ); - StopPlayers( "was disconnected (gameover timer finished)" ); - } - } + if( m_CountDownStarted || m_AutoStartPlayers == 0 ) + return; - // end the game if there aren't any players left + StartCountDownAuto( m_GHost->m_RequireSpoofChecks ); +} - if( m_Players.empty( ) && ( m_GameLoading || m_GameLoaded ) ) - { - if( !m_Saving ) - { - CONSOLE_Print( "[GAME: " + m_GameName + "] is over (no players left)" ); - SaveGameData( ); - m_Saving = true; - } - else if( IsGameDataSaved( ) ) - return true; - } +void CBaseGame::EventGameOverTimeout() +{ + if( m_Players.size() == 0 ) + return; - // accept new connections + CONSOLE_Print( "[GAME: " + m_GameName + "] is over (gameover timer finished)" ); + StopPlayers( "was disconnected (gameover timer finished)" ); + deleteLater(); +} - if( m_Socket ) - { - CTCPSocket *NewSocket = m_Socket->Accept( (fd_set *)fd ); +void CBaseGame::EventVotekickTimeout() +{ + // expire the votekick - if( NewSocket ) - { - // check the IP blacklist + if( m_KickVotePlayer.isEmpty( ) ) + return; - if( m_IPBlackList.find( NewSocket->GetIPString( ) ) == m_IPBlackList.end( ) ) - { - if( m_GHost->m_TCPNoDelay ) - NewSocket->SetNoDelay( true ); + CONSOLE_Print( "[GAME: " + m_GameName + "] votekick against player [" + m_KickVotePlayer + "] expired" ); + SendAllChat( m_GHost->GetLanguage( )->VoteKickExpired( m_KickVotePlayer ) ); + m_KickVotePlayer.clear( ); +} - m_Potentials.push_back( new CPotentialPlayer( m_Protocol, this, NewSocket ) ); - } - else - { - CONSOLE_Print( "[GAME: " + m_GameName + "] rejected connection from [" + NewSocket->GetIPString( ) + "] due to blacklist" ); - delete NewSocket; - } - } +void CBaseGame::EventLobbyTimeout() +{ + if( m_GameLoading || m_GameLoaded || m_AutoStartPlayers != 0) + return; - if( m_Socket->HasError( ) ) - return true; - } + // check if we've hit the time limit - return m_Exiting; + CONSOLE_Print( "[GAME: " + m_GameName + "] is over (lobby time limit hit)" ); + deleteLater(); } -void CBaseGame :: UpdatePost( void *send_fd ) +void CBaseGame::EventNewConnection() { - // we need to manually call DoSend on each player now because CGamePlayer :: Update doesn't do it - // this is in case player 2 generates a packet for player 1 during the update but it doesn't get sent because player 1 already finished updating - // in reality since we're queueing actions it might not make a big difference but oh well + QTcpSocket *NewSocket = m_Socket->nextPendingConnection(); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( (*i)->GetSocket( ) ) - (*i)->GetSocket( )->DoSend( (fd_set *)send_fd ); - } + if( !NewSocket ) + return; + + DEBUG_Print("New connection incomming"); - for( vector :: iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) + // check the IP blacklist + if( m_IPBlackList.find( NewSocket->localAddress().toString() ) != m_IPBlackList.end( ) ) { - if( (*i)->GetSocket( ) ) - (*i)->GetSocket( )->DoSend( (fd_set *)send_fd ); + CONSOLE_Print( "[GAME: " + m_GameName + "] rejected connection from [" + NewSocket->localAddress().toString() + "] due to blacklist" ); + NewSocket->deleteLater(); + return; } + + if( m_GHost->m_TCPNoDelay ) + NewSocket->setSocketOption(QAbstractSocket::LowDelayOption, true); + + new CPotentialPlayer( m_Protocol, this, NewSocket ); } -void CBaseGame :: Send( CGamePlayer *player, BYTEARRAY data ) +void CBaseGame :: Send( CGamePlayer *player, const QByteArray &data ) { if( player ) player->Send( data ); } -void CBaseGame :: Send( unsigned char PID, BYTEARRAY data ) +void CBaseGame :: Send( unsigned char PID, const QByteArray &data ) { Send( GetPlayerFromPID( PID ), data ); } -void CBaseGame :: Send( BYTEARRAY PIDs, BYTEARRAY data ) +void CBaseGame :: Send( const QByteArray &PIDs, const QByteArray &data ) { - for( unsigned int i = 0; i < PIDs.size( ); i++ ) + for( int i = 0; i < PIDs.size( ); i++ ) Send( PIDs[i], data ); } -void CBaseGame :: SendAll( BYTEARRAY data ) +void CBaseGame :: SendAll( const QByteArray &data ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) (*i)->Send( data ); } -void CBaseGame :: SendChat( unsigned char fromPID, CGamePlayer *player, string message ) +void CBaseGame :: SendChat( unsigned char fromPID, CGamePlayer *player, const QString &message ) { // send a private message to one player - it'll be marked [Private] in Warcraft 3 @@ -1102,10 +870,8 @@ void CBaseGame :: SendChat( unsigned char fromPID, CGamePlayer *player, string m { if( !m_GameLoading && !m_GameLoaded ) { - if( message.size( ) > 254 ) - message = message.substr( 0, 254 ); - - Send( player, m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, UTIL_CreateByteArray( player->GetPID( ) ), 16, BYTEARRAY( ), message ) ); + // limit text length to 254 + Send( player, m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, QByteArray(1, player->GetPID( ) ), 16, QByteArray( ), message.mid( 0, 254 ) ) ); } else { @@ -1117,31 +883,29 @@ void CBaseGame :: SendChat( unsigned char fromPID, CGamePlayer *player, string m if( SID < m_Slots.size( ) ) ExtraFlags[0] = 3 + m_Slots[SID].GetColour( ); - - if( message.size( ) > 127 ) - message = message.substr( 0, 127 ); - - Send( player, m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, UTIL_CreateByteArray( player->GetPID( ) ), 32, UTIL_CreateByteArray( ExtraFlags, 4 ), message ) ); + + // limit text length to 127 + Send( player, m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, QByteArray( 1, player->GetPID( ) ), 32, QByteArray( (char*)ExtraFlags, 4 ), message.mid( 0, 127 ) ) ); } } } -void CBaseGame :: SendChat( unsigned char fromPID, unsigned char toPID, string message ) +void CBaseGame :: SendChat( unsigned char fromPID, unsigned char toPID, const QString &message ) { SendChat( fromPID, GetPlayerFromPID( toPID ), message ); } -void CBaseGame :: SendChat( CGamePlayer *player, string message ) +void CBaseGame :: SendChat( CGamePlayer *player, const QString &message ) { SendChat( GetHostPID( ), player, message ); } -void CBaseGame :: SendChat( unsigned char toPID, string message ) +void CBaseGame :: SendChat( unsigned char toPID, const QString &message ) { SendChat( GetHostPID( ), toPID, message ); } -void CBaseGame :: SendAllChat( unsigned char fromPID, string message ) +void CBaseGame :: SendAllChat( unsigned char fromPID, const QString &message ) { // send a public message to all players - it'll be marked [All] in Warcraft 3 @@ -1151,17 +915,13 @@ void CBaseGame :: SendAllChat( unsigned char fromPID, string message ) if( !m_GameLoading && !m_GameLoaded ) { - if( message.size( ) > 254 ) - message = message.substr( 0, 254 ); - - SendAll( m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, GetPIDs( ), 16, BYTEARRAY( ), message ) ); + // limit text length to 254 + SendAll( m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, GetPIDs( ), 16, QByteArray( ), message.mid( 0, 254 ) ) ); } else { - if( message.size( ) > 127 ) - message = message.substr( 0, 127 ); - - SendAll( m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, GetPIDs( ), 32, UTIL_CreateByteArray( (uint32_t)0, false ), message ) ); + // limit text length to 127 + SendAll( m_Protocol->SEND_W3GS_CHAT_FROM_HOST( fromPID, GetPIDs( ), 32, Util::fromUInt32( 0), message.mid( 0, 127 ) ) ); if( m_Replay ) m_Replay->AddChatMessage( fromPID, 32, 0, message ); @@ -1169,12 +929,12 @@ void CBaseGame :: SendAllChat( unsigned char fromPID, string message ) } } -void CBaseGame :: SendAllChat( string message ) +void CBaseGame :: SendAllChat( const QString &message ) { SendAllChat( GetHostPID( ), message ); } -void CBaseGame :: SendLocalAdminChat( string message ) +void CBaseGame :: SendLocalAdminChat( const QString &message ) { if( !m_LocalAdminMessages ) return; @@ -1183,7 +943,7 @@ void CBaseGame :: SendLocalAdminChat( string message ) // at the time of this writing it is only possible for the game owner to meet this criteria because being an admin requires spoof checking // this is mainly used for relaying battle.net whispers, chat messages, and emotes to these players - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetSpoofed( ) && IsOwner( (*i)->GetName( ) ) && ( UTIL_IsLanIP( (*i)->GetExternalIP( ) ) || UTIL_IsLocalIP( (*i)->GetExternalIP( ), m_GHost->m_LocalAddresses ) ) ) { @@ -1202,10 +962,7 @@ void CBaseGame :: SendLocalAdminChat( string message ) void CBaseGame :: SendAllSlotInfo( ) { if( !m_GameLoading && !m_GameLoaded ) - { SendAll( m_Protocol->SEND_W3GS_SLOTINFO( m_Slots, m_RandomSeed, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); - m_SlotInfoChanged = false; - } } void CBaseGame :: SendVirtualHostPlayerInfo( CGamePlayer *player ) @@ -1213,11 +970,11 @@ void CBaseGame :: SendVirtualHostPlayerInfo( CGamePlayer *player ) if( m_VirtualHostPID == 255 ) return; - BYTEARRAY IP; - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); + QByteArray IP; + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); Send( player, m_Protocol->SEND_W3GS_PLAYERINFO( m_VirtualHostPID, m_VirtualHostName, IP, IP ) ); } @@ -1226,11 +983,11 @@ void CBaseGame :: SendFakePlayerInfo( CGamePlayer *player ) if( m_FakePlayerPID == 255 ) return; - BYTEARRAY IP; - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); + QByteArray IP; + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); Send( player, m_Protocol->SEND_W3GS_PLAYERINFO( m_FakePlayerPID, "FakePlayer", IP, IP ) ); } @@ -1238,12 +995,20 @@ void CBaseGame :: SendAllActions( ) { bool UsingGProxy = false; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetGProxy( ) ) UsingGProxy = true; } + if (m_RequestedLatency != 0) + { + m_Latency = m_RequestedLatency; + m_SendActionTimer.setInterval(m_RequestedLatency); + m_SendActionTimer.start(); + m_RequestedLatency = 0; + } + m_GameTicks += m_Latency; if( UsingGProxy ) @@ -1252,19 +1017,19 @@ void CBaseGame :: SendAllActions( ) // GProxy++ will insert these itself so we don't need to send them to GProxy++ players // empty actions are used to extend the time a player can use when reconnecting - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetGProxy( ) ) { for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) - Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( queue( ), 0 ) ); + Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); } } if( m_Replay ) { for( unsigned char i = 0; i < m_GProxyEmptyActions; i++ ) - m_Replay->AddTimeSlot( 0, queue( ) ); + m_Replay->AddTimeSlot( 0, QQueue( ) ); } } @@ -1274,24 +1039,25 @@ void CBaseGame :: SendAllActions( ) m_SyncCounter += m_GProxyEmptyActions; */ m_SyncCounter++; + CheckPlayersStartedLaggging(); // we aren't allowed to send more than 1460 bytes in a single packet but it's possible we might have more than that many bytes waiting in the queue - if( !m_Actions.empty( ) ) + if( !m_Actions.isEmpty( ) ) { // we use a "sub actions queue" which we keep adding actions to until we reach the size limit // start by adding one action to the sub actions queue - queue SubActions; + QQueue SubActions; CIncomingAction *Action = m_Actions.front( ); - m_Actions.pop( ); - SubActions.push( Action ); - uint32_t SubActionsLength = Action->GetLength( ); + m_Actions.dequeue( ); + SubActions.enqueue( Action ); + quint32 SubActionsLength = Action->GetLength( ); - while( !m_Actions.empty( ) ) + while( !m_Actions.isEmpty( ) ) { Action = m_Actions.front( ); - m_Actions.pop( ); + m_Actions.dequeue( ); // check if adding the next action to the sub actions queue would put us over the limit (1452 because the INCOMING_ACTION and INCOMING_ACTION2 packets use an extra 8 bytes) @@ -1306,16 +1072,16 @@ void CBaseGame :: SendAllActions( ) if( m_Replay ) m_Replay->AddTimeSlot2( SubActions ); - while( !SubActions.empty( ) ) + while( !SubActions.isEmpty( ) ) { delete SubActions.front( ); - SubActions.pop( ); + SubActions.dequeue( ); } SubActionsLength = 0; } - SubActions.push( Action ); + SubActions.enqueue( Action ); SubActionsLength += Action->GetLength( ); } @@ -1324,10 +1090,10 @@ void CBaseGame :: SendAllActions( ) if( m_Replay ) m_Replay->AddTimeSlot( m_Latency, SubActions ); - while( !SubActions.empty( ) ) + while( !SubActions.isEmpty( ) ) { delete SubActions.front( ); - SubActions.pop( ); + SubActions.dequeue( ); } } else @@ -1338,18 +1104,13 @@ void CBaseGame :: SendAllActions( ) m_Replay->AddTimeSlot( m_Latency, m_Actions ); } - uint32_t ActualSendInterval = GetTicks( ) - m_LastActionSentTicks; - uint32_t ExpectedSendInterval = m_Latency - m_LastActionLateBy; - m_LastActionLateBy = ActualSendInterval - ExpectedSendInterval; - - if( m_LastActionLateBy > m_Latency ) + if( GetTicks() - m_LastActionSentTicks > 1.5 * m_Latency ) { // something is going terribly wrong - GHost++ is probably starved of resources // print a message because even though this will take more resources it should provide some information to the administrator for future reference // other solutions - dynamically modify the latency, request higher priority, terminate other games, ??? - CONSOLE_Print( "[GAME: " + m_GameName + "] warning - the latency is " + UTIL_ToString( m_Latency ) + "ms but the last update was late by " + UTIL_ToString( m_LastActionLateBy ) + "ms" ); - m_LastActionLateBy = m_Latency; + CONSOLE_Print( "[GAME: " + m_GameName + "] warning - the latency is " + QString::number( m_Latency ) + "ms but GHost needed " + QString::number(GetTicks() - m_LastActionSentTicks) + "ms , your machine is probably overloaded" ); } m_LastActionSentTicks = GetTicks( ); @@ -1359,14 +1120,13 @@ void CBaseGame :: SendWelcomeMessage( CGamePlayer *player ) { // read from motd.txt if available (thanks to zeeg for this addition) - ifstream in; - in.open( m_GHost->m_MOTDFile.c_str( ) ); + QFile f(m_GHost->m_MOTDFile); - if( in.fail( ) ) + if( !f.open(QFile::ReadOnly) ) { // default welcome message - if( m_HCLCommandString.empty( ) ) + if( m_HCLCommandString.isEmpty( ) ) SendChat( player, " " ); SendChat( player, " " ); @@ -1376,78 +1136,256 @@ void CBaseGame :: SendWelcomeMessage( CGamePlayer *player ) SendChat( player, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" ); SendChat( player, " Game Name: " + m_GameName ); - if( !m_HCLCommandString.empty( ) ) + if( !m_HCLCommandString.isEmpty( ) ) SendChat( player, " HCL Command String: " + m_HCLCommandString ); } else { // custom welcome message // don't print more than 8 lines + QStringList data = QString::fromUtf8(f.readAll()).replace('\r', "").split('\n'); + + for (int i = 0; i < data.size() && i < 8; i++) + SendChat( player, data.at(i) ); + } +} + +void CBaseGame :: SendEndMessage( ) +{ + // read from gameover.txt if available + + QFile f(m_GHost->m_GameOverFile); + + if( f.open(QFile::ReadOnly) ) + { + // don't print more than 8 lines + QStringList data = QString::fromUtf8(f.readAll()).replace('\r', "").split('\n'); + + for (int i = 0; i < data.size() && i < 8; i++) + SendAllChat( data.at(i) ); + } +} + +void CBaseGame::CheckPlayersStartedLaggging() +{ + // check if anyone has started lagging + // we consider a player to have started lagging if they're more than m_SyncLimit keepalives behind + + if( m_Lagging ) + return; - uint32_t Count = 0; - string Line; - while( !in.eof( ) && Count < 8 ) + bool UsingGProxy = false; + + m_WaitTime = 60; + + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( (*i)->GetGProxy( ) ) { - getline( in, Line ); + if( UsingGProxy ) + m_WaitTime = ( m_GProxyEmptyActions + 1 ) * 60; - if( Line.empty( ) ) - { - if( !in.eof( ) ) - SendChat( player, " " ); - } - else - SendChat( player, Line ); + break; + } + } - Count++; + QString LaggingString; + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( m_SyncCounter - (*i)->GetSyncCounter( ) > m_SyncLimit ) + { + (*i)->SetLagging( true ); + (*i)->SetStartedLaggingTicks( GetTicks( ) ); + m_Lagging = true; + m_StartedLaggingTime = GetTime( ); + + m_DropLaggerTimer.start(m_WaitTime*1000); + + if( LaggingString.isEmpty( ) ) + LaggingString = (*i)->GetName( ); + else + LaggingString += ", " + (*i)->GetName( ); } + } + + if( m_Lagging ) + { + // start the lag screen + + CONSOLE_Print( "[GAME: " + m_GameName + "] started lagging on [" + LaggingString + "]" ); + SendAll( m_Protocol->SEND_W3GS_START_LAG( m_Players ) ); + + // reset everyone's drop vote + + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + (*i)->SetDropVote( false ); - in.close( ); + m_ResetLagscreenTimer.start(); + m_SendActionTimer.stop(); } } -void CBaseGame :: SendEndMessage( ) +void CBaseGame::EventDropLaggerTimeout() { - // read from gameover.txt if available + StopLaggers( m_GHost->GetLanguage( )->WasAutomaticallyDroppedAfterSeconds( QString::number(m_WaitTime) ) ); +} + +void CBaseGame::EventResetLagscreenTimeout() +{ + if (!m_Lagging) + { + m_ResetLagscreenTimer.stop(); + return; + } - ifstream in; - in.open( m_GHost->m_GameOverFile.c_str( ) ); + bool UsingGProxy = false; - if( !in.fail( ) ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - // don't print more than 8 lines + if( (*i)->GetGProxy( ) ) + UsingGProxy = true; + } + + // we cannot allow the lag screen to stay up for more than ~65 seconds because Warcraft III disconnects if it doesn't receive an action packet at least this often + // one (easy) solution is to simply drop all the laggers if they lag for more than 60 seconds + // another solution is to reset the lag screen the same way we reset it when using load-in-game + // this is required in order to give GProxy++ clients more time to reconnect - uint32_t Count = 0; - string Line; + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + // stop the lag screen - while( !in.eof( ) && Count < 8 ) + for( QList :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) { - getline( in, Line ); + if( (*j)->GetLagging( ) ) + Send( *i, m_Protocol->SEND_W3GS_STOP_LAG( *j ) ); + } - if( Line.empty( ) ) - { - if( !in.eof( ) ) - SendAllChat( " " ); - } - else - SendAllChat( Line ); + // send an empty update + // this resets the lag screen timer + + if( UsingGProxy && !(*i)->GetGProxy( ) ) + { + // we must send additional empty actions to non-GProxy++ players + // GProxy++ will insert these itself so we don't need to send them to GProxy++ players + // empty actions are used to extend the time a player can use when reconnecting + + for( unsigned char j = 0; j < m_GProxyEmptyActions; j++ ) + Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); + } + + Send( *i, m_Protocol->SEND_W3GS_INCOMING_ACTION( QQueue( ), 0 ) ); + + // start the lag screen + + Send( *i, m_Protocol->SEND_W3GS_START_LAG( m_Players ) ); + } + + // add actions to replay - Count++; + if( m_Replay ) + { + if( UsingGProxy ) + { + for( unsigned char i = 0; i < m_GProxyEmptyActions; i++ ) + m_Replay->AddTimeSlot( 0, QQueue( ) ); } - in.close( ); + m_Replay->AddTimeSlot( 0, QQueue( ) ); + } + + // Warcraft III doesn't seem to respond to empty actions + + /* if( UsingGProxy ) + m_SyncCounter += m_GProxyEmptyActions; + + m_SyncCounter++; */ +} + +void CBaseGame::EventPlayerStoppedLagging() +{ + if( !m_Lagging ) + return; + + CGamePlayer *player = (CGamePlayer*)QObject::sender(); + if (player == NULL) + return; + + // we consider a player to have stopped lagging if they're less than half m_SyncLimit keepalives behind + + CONSOLE_Print( "[GAME: " + m_GameName + "] stopped lagging on [" + player->GetName( ) + "]" ); + SendAll( m_Protocol->SEND_W3GS_STOP_LAG( player ) ); + player->SetStartedLaggingTicks( 0 ); + + // check if everyone has stopped lagging + + bool Lagging = false; + + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( (*i)->GetLagging( ) ) + Lagging = true; + } + + m_Lagging = Lagging; + + if (!m_Lagging) + { + m_DropLaggerTimer.stop(); + + // we continue to send actions + m_SendActionTimer.start(); } } -void CBaseGame :: EventPlayerDeleted( CGamePlayer *player ) +void CBaseGame :: EventPlayerDeleted() { + CGamePlayer *player = (CGamePlayer*)QObject::sender(); CONSOLE_Print( "[GAME: " + m_GameName + "] deleting player [" + player->GetName( ) + "]: " + player->GetLeftReason( ) ); + if( !m_Players.removeOne(player) ) + return; + + // create the virtual host player if there is room + if( !m_GameLoading && !m_GameLoaded && GetNumPlayers( ) < 12 ) + CreateVirtualHost( ); + + bool res = false; + // check if there's another player with reserved status in the game + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + if( (*i)->GetReserved( ) ) + res = true; + + if (res) + m_LobbyTimeoutTimer.start(); + + // unlock the game if the owner leaves + if( m_Locked && player->GetName() == m_OwnerName ) + { + SendAllChat( m_GHost->GetLanguage( )->GameUnlocked( ) ); + m_Locked = false; + } + + // start the gameover timer if there's only one player left + if( ( m_GameLoading || m_GameLoaded ) && m_Players.size( ) == 1 && m_FakePlayerPID == 255 && !m_GameOverTimer.isActive() ) + { + CONSOLE_Print( "[GAME: " + m_GameName + "] gameover timer started (one player left)" ); + m_GameOverTimer.start(); + } + + // end the game if there aren't any players left + if( m_Players.isEmpty( ) && (m_GameLoading || m_GameLoaded) ) + { + CONSOLE_Print( "[GAME: " + m_GameName + "] is over (no players left)" ); + SaveGameData( ); + } + // remove any queued spoofcheck messages for this player - if( player->GetWhoisSent( ) && !player->GetJoinedRealm( ).empty( ) && player->GetSpoofedRealm( ).empty( ) ) + if( player->GetWhoisSent( ) && !player->GetJoinedRealm( ).isEmpty( ) && player->GetSpoofedRealm( ).isEmpty( ) ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == player->GetJoinedRealm( ) ) { @@ -1458,7 +1396,7 @@ void CBaseGame :: EventPlayerDeleted( CGamePlayer *player ) else (*i)->UnqueueChatCommand( "/whois " + player->GetName( ) ); - (*i)->UnqueueChatCommand( "/w " + player->GetName( ) + " " + m_GHost->m_Language->SpoofCheckByReplying( ) ); + (*i)->UnqueueChatCommand( "/w " + player->GetName( ) + " " + m_GHost->GetLanguage( )->SpoofCheckByReplying( ) ); } } } @@ -1480,13 +1418,13 @@ void CBaseGame :: EventPlayerDeleted( CGamePlayer *player ) if( m_GameLoaded && player->GetLeftCode( ) == PLAYERLEAVE_DISCONNECT && m_AutoSave ) { - string SaveGameName = UTIL_FileSafeName( "GHost++ AutoSave " + m_GameName + " (" + player->GetName( ) + ").w3z" ); - CONSOLE_Print( "[GAME: " + m_GameName + "] auto saving [" + SaveGameName + "] before player drop, shortened send interval = " + UTIL_ToString( GetTicks( ) - m_LastActionSentTicks ) ); - BYTEARRAY CRC; - BYTEARRAY Action; + QString SaveGameName = UTIL_FileSafeName( "GHost++ AutoSave " + m_GameName + " (" + player->GetName( ) + ").w3z" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] auto saving [" + SaveGameName + "] before player drop, shortened send interval = " + QString::number( GetTicks( ) - m_LastActionSentTicks ) ); + QByteArray CRC; + QByteArray Action; Action.push_back( 6 ); - UTIL_AppendByteArray( Action, SaveGameName ); - m_Actions.push( new CIncomingAction( player->GetPID( ), CRC, Action ) ); + Action.append(SaveGameName.toUtf8()); + m_Actions.enqueue( new CIncomingAction( player->GetPID( ), CRC, Action ) ); // todotodo: with the new latency system there needs to be a way to send a 0-time action @@ -1498,7 +1436,7 @@ void CBaseGame :: EventPlayerDeleted( CGamePlayer *player ) // we must buffer player leave messages when using "load in game" to prevent desyncs // this ensures the player leave messages are correctly interleaved with the empty updates sent to each player - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetFinishedLoading( ) ) { @@ -1538,17 +1476,17 @@ void CBaseGame :: EventPlayerDeleted( CGamePlayer *player ) if( m_CountDownStarted && !m_GameLoading && !m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->CountDownAborted( ) ); + SendAllChat( m_GHost->GetLanguage( )->CountDownAborted( ) ); m_CountDownStarted = false; } // abort the votekick - if( !m_KickVotePlayer.empty( ) ) - SendAllChat( m_GHost->m_Language->VoteKickCancelled( m_KickVotePlayer ) ); + if( !m_KickVotePlayer.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->VoteKickCancelled( m_KickVotePlayer ) ); m_KickVotePlayer.clear( ); - m_StartedKickVoteTime = 0; + m_VotekickTimer.stop(); } void CBaseGame :: EventPlayerDisconnectTimedOut( CGamePlayer *player ) @@ -1557,37 +1495,28 @@ void CBaseGame :: EventPlayerDisconnectTimedOut( CGamePlayer *player ) { if( !player->GetGProxyDisconnectNoticeSent( ) ) { - SendAllChat( player->GetName( ) + " " + m_GHost->m_Language->HasLostConnectionTimedOutGProxy( ) + "." ); + SendAllChat( player->GetName( ) + " " + m_GHost->GetLanguage( )->HasLostConnectionTimedOutGProxy( ) + "." ); player->SetGProxyDisconnectNoticeSent( true ); } - if( GetTime( ) - player->GetLastGProxyWaitNoticeSentTime( ) >= 20 ) - { - uint32_t TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60 - ( GetTime( ) - m_StartedLaggingTime ); - - if( TimeRemaining > ( (uint32_t)m_GProxyEmptyActions + 1 ) * 60 ) - TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60; - - SendAllChat( player->GetPID( ), m_GHost->m_Language->WaitForReconnectSecondsRemain( UTIL_ToString( TimeRemaining ) ) ); - player->SetLastGProxyWaitNoticeSentTime( GetTime( ) ); - } - + player->m_SendGProxyMessageTimer.start(); return; } - // not only do we not do any timeouts if the game is lagging, we allow for an additional grace period of 10 seconds + // not only do we not do any timeouts if the game is lagging, we allow for an additional grace period of 5 seconds // this is because Warcraft 3 stops sending packets during the lag screen // so when the lag screen finishes we would immediately disconnect everyone if we didn't give them some extra time - if( GetTime( ) - m_LastLagScreenTime >= 10 ) - { - player->SetDeleteMe( true ); - player->SetLeftReason( m_GHost->m_Language->HasLostConnectionTimedOut( ) ); - player->SetLeftCode( PLAYERLEAVE_DISCONNECT ); + QTimer::singleShot(5000, this, SLOT(EventPlayerLaggedOut(player))); +} - if( !m_GameLoading && !m_GameLoaded ) - OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); - } +void CBaseGame::EventPlayerLaggedOut(CGamePlayer *player) +{ + player->SetLeftReason( m_GHost->GetLanguage( )->HasLostConnectionTimedOut( ) ); + player->SetLeftCode( PLAYERLEAVE_DISCONNECT ); + + if( !m_GameLoading && !m_GameLoaded ) + OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); } void CBaseGame :: EventPlayerDisconnectPlayerError( CGamePlayer *player ) @@ -1595,8 +1524,7 @@ void CBaseGame :: EventPlayerDisconnectPlayerError( CGamePlayer *player ) // at the time of this comment there's only one player error and that's when we receive a bad packet from the player // since TCP has checks and balances for data corruption the chances of this are pretty slim - player->SetDeleteMe( true ); - player->SetLeftReason( m_GHost->m_Language->HasLostConnectionPlayerError( player->GetErrorString( ) ) ); + player->SetLeftReason( m_GHost->GetLanguage( )->HasLostConnectionPlayerError( player->GetErrorString( ) ) ); player->SetLeftCode( PLAYERLEAVE_DISCONNECT ); if( !m_GameLoading && !m_GameLoaded ) @@ -1609,26 +1537,25 @@ void CBaseGame :: EventPlayerDisconnectSocketError( CGamePlayer *player ) { if( !player->GetGProxyDisconnectNoticeSent( ) ) { - SendAllChat( player->GetName( ) + " " + m_GHost->m_Language->HasLostConnectionSocketErrorGProxy( player->GetSocket( )->GetErrorString( ) ) + "." ); + SendAllChat( player->GetName( ) + " " + m_GHost->GetLanguage( )->HasLostConnectionSocketErrorGProxy( player->GetSocket( )->errorString() ) + "." ); player->SetGProxyDisconnectNoticeSent( true ); } if( GetTime( ) - player->GetLastGProxyWaitNoticeSentTime( ) >= 20 ) { - uint32_t TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60 - ( GetTime( ) - m_StartedLaggingTime ); + quint32 TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60 - ( GetTime( ) - m_StartedLaggingTime ); - if( TimeRemaining > ( (uint32_t)m_GProxyEmptyActions + 1 ) * 60 ) + if( TimeRemaining > ( (quint32)m_GProxyEmptyActions + 1 ) * 60 ) TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60; - SendAllChat( player->GetPID( ), m_GHost->m_Language->WaitForReconnectSecondsRemain( UTIL_ToString( TimeRemaining ) ) ); + SendAllChat( player->GetPID( ), m_GHost->GetLanguage( )->WaitForReconnectSecondsRemain( QString::number( TimeRemaining ) ) ); player->SetLastGProxyWaitNoticeSentTime( GetTime( ) ); } return; } - player->SetDeleteMe( true ); - player->SetLeftReason( m_GHost->m_Language->HasLostConnectionSocketError( player->GetSocket( )->GetErrorString( ) ) ); + player->SetLeftReason( m_GHost->GetLanguage( )->HasLostConnectionSocketError( player->GetSocket( )->errorString( ) ) ); player->SetLeftCode( PLAYERLEAVE_DISCONNECT ); if( !m_GameLoading && !m_GameLoaded ) @@ -1641,26 +1568,25 @@ void CBaseGame :: EventPlayerDisconnectConnectionClosed( CGamePlayer *player ) { if( !player->GetGProxyDisconnectNoticeSent( ) ) { - SendAllChat( player->GetName( ) + " " + m_GHost->m_Language->HasLostConnectionClosedByRemoteHostGProxy( ) + "." ); + SendAllChat( player->GetName( ) + " " + m_GHost->GetLanguage( )->HasLostConnectionClosedByRemoteHostGProxy( ) + "." ); player->SetGProxyDisconnectNoticeSent( true ); } if( GetTime( ) - player->GetLastGProxyWaitNoticeSentTime( ) >= 20 ) { - uint32_t TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60 - ( GetTime( ) - m_StartedLaggingTime ); + quint32 TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60 - ( GetTime( ) - m_StartedLaggingTime ); - if( TimeRemaining > ( (uint32_t)m_GProxyEmptyActions + 1 ) * 60 ) + if( TimeRemaining > ( (quint32)m_GProxyEmptyActions + 1 ) * 60 ) TimeRemaining = ( m_GProxyEmptyActions + 1 ) * 60; - SendAllChat( player->GetPID( ), m_GHost->m_Language->WaitForReconnectSecondsRemain( UTIL_ToString( TimeRemaining ) ) ); + SendAllChat( player->GetPID( ), m_GHost->GetLanguage( )->WaitForReconnectSecondsRemain( QString::number( TimeRemaining ) ) ); player->SetLastGProxyWaitNoticeSentTime( GetTime( ) ); } return; } - player->SetDeleteMe( true ); - player->SetLeftReason( m_GHost->m_Language->HasLostConnectionClosedByRemoteHost( ) ); + player->SetLeftReason( m_GHost->GetLanguage( )->HasLostConnectionClosedByRemoteHost( ) ); player->SetLeftCode( PLAYERLEAVE_DISCONNECT ); if( !m_GameLoading && !m_GameLoaded ) @@ -1671,11 +1597,11 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP { // check if the new player's name is empty or too long - if( joinPlayer->GetName( ).empty( ) || joinPlayer->GetName( ).size( ) > 15 ) + if( joinPlayer->GetName( ).isEmpty( ) || joinPlayer->GetName( ).size( ) > 15 ) { - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game with an invalid name of length " + UTIL_ToString( joinPlayer->GetName( ).size( ) ) ); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game with an invalid name of length " + QString::number( joinPlayer->GetName( ).size( ) ) ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -1685,7 +1611,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game with the virtual host name" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -1694,9 +1620,9 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( GetPlayerFromName( joinPlayer->GetName( ), false ) ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but that name is already taken" ); - // SendAllChat( m_GHost->m_Language->TryingToJoinTheGameButTaken( joinPlayer->GetName( ) ) ); + // SendAllChat( m_GHost->GetLanguage( )->TryingToJoinTheGameButTaken( joinPlayer->GetName( ) ) ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -1705,14 +1631,14 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP // the client sends the host counter when it joins so we can extract the ID value here // note: this is not a replacement for spoof checking since it doesn't verify the player's name and it can be spoofed anyway - uint32_t HostCounterID = joinPlayer->GetHostCounter( ) >> 28; - string JoinedRealm; + quint32 HostCounterID = joinPlayer->GetHostCounter( ) >> 28; + QString JoinedRealm; // we use an ID value of 0 to denote joining via LAN if( HostCounterID != 0 ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetHostCounterID( ) == HostCounterID ) JoinedRealm = (*i)->GetServer( ); @@ -1725,7 +1651,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_GHost->m_BanMethod != 0 ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == JoinedRealm ) { @@ -1739,17 +1665,17 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_IgnoredNames.find( joinPlayer->GetName( ) ) == m_IgnoredNames.end( ) ) { - SendAllChat( m_GHost->m_Language->TryingToJoinTheGameButBannedByName( joinPlayer->GetName( ) ) ); - SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->TryingToJoinTheGameButBannedByName( joinPlayer->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); m_IgnoredNames.insert( joinPlayer->GetName( ) ); } // let banned players "join" the game with an arbitrary PID then immediately close the connection // this causes them to be kicked back to the chat channel on battle.net - vector Slots = m_Map->GetSlots( ); - potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, potential->GetSocket( )->GetPort( ), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); - potential->SetDeleteMe( true ); + QList Slots = m_Map->GetSlots( ); + potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, Util::fromUInt16(potential->GetSocket( )->localPort()), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); + potential->deleteLater(); return; } @@ -1767,17 +1693,17 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_IgnoredNames.find( joinPlayer->GetName( ) ) == m_IgnoredNames.end( ) ) { - SendAllChat( m_GHost->m_Language->TryingToJoinTheGameButBannedByIP( joinPlayer->GetName( ), potential->GetExternalIPString( ), Ban->GetName( ) ) ); - SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->TryingToJoinTheGameButBannedByIP( joinPlayer->GetName( ), potential->GetExternalIPString( ), Ban->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); m_IgnoredNames.insert( joinPlayer->GetName( ) ); } // let banned players "join" the game with an arbitrary PID then immediately close the connection // this causes them to be kicked back to the chat channel on battle.net - vector Slots = m_Map->GetSlots( ); - potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, potential->GetSocket( )->GetPort( ), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); - potential->SetDeleteMe( true ); + QList Slots = m_Map->GetSlots( ); + potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, Util::fromUInt16((quint16)potential->GetSocket( )->localPort()), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); + potential->deleteLater(); return; } @@ -1786,7 +1712,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP } } - if( m_MatchMaking && m_AutoStartPlayers != 0 && !m_Map->GetMapMatchMakingCategory( ).empty( ) && m_Map->GetMapOptions( ) & MAPOPT_FIXEDPLAYERSETTINGS ) + if( m_MatchMaking && m_AutoStartPlayers != 0 && !m_Map->GetMapMatchMakingCategory( ).isEmpty( ) && m_Map->GetMapOptions( ) & MAPOPT_FIXEDPLAYERSETTINGS ) { // matchmaking is enabled // start a database query to determine the player's score @@ -1801,7 +1727,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP bool AnyAdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) ) { @@ -1812,6 +1738,10 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP bool Reserved = IsReserved( joinPlayer->GetName( ) ) || ( m_GHost->m_ReserveAdmins && AnyAdminCheck ) || IsOwner( joinPlayer->GetName( ) ); + // stop some timers + if (Reserved) + m_LobbyTimeoutTimer.stop(); + // try to find a slot unsigned char SID = 255; @@ -1825,13 +1755,13 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP // unfortunately we don't know how to extract the player layout from the saved game so we use the data from a replay instead // the !enforcesg command defines the player layout by parsing a replay - for( vector :: iterator i = m_EnforcePlayers.begin( ); i != m_EnforcePlayers.end( ); i++ ) + for( QList :: const_iterator i = m_EnforcePlayers.begin( ); i != m_EnforcePlayers.end( ); i++ ) { if( (*i).second == joinPlayer->GetName( ) ) EnforcePID = (*i).first; } - for( vector :: iterator i = m_EnforceSlots.begin( ); i != m_EnforceSlots.end( ); i++ ) + for( QList :: iterator i = m_EnforceSlots.begin( ); i != m_EnforceSlots.end( ); i++ ) { if( (*i).GetPID( ) == EnforcePID ) { @@ -1846,7 +1776,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but isn't in the enforced list" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -1870,8 +1800,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( KickedPlayer ) { - KickedPlayer->SetDeleteMe( true ); - KickedPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForReservedPlayer( joinPlayer->GetName( ) ) ); + KickedPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForReservedPlayer( joinPlayer->GetName( ) ) ); KickedPlayer->SetLeftCode( PLAYERLEAVE_LOBBY ); // send a playerleave message immediately since it won't normally get sent until the player is deleted which is after we send a playerjoin message @@ -1879,6 +1808,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP SendAll( m_Protocol->SEND_W3GS_PLAYERLEAVE_OTHERS( KickedPlayer->GetPID( ), KickedPlayer->GetLeftCode( ) ) ); KickedPlayer->SetLeftMessageSent( true ); + KickedPlayer->deleteLater(); } } } @@ -1903,8 +1833,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( KickedPlayer ) { - KickedPlayer->SetDeleteMe( true ); - KickedPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForOwnerPlayer( joinPlayer->GetName( ) ) ); + KickedPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForOwnerPlayer( joinPlayer->GetName( ) ) ); KickedPlayer->SetLeftCode( PLAYERLEAVE_LOBBY ); // send a playerleave message immediately since it won't normally get sent until the player is deleted which is after we send a playerjoin message @@ -1912,6 +1841,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP SendAll( m_Protocol->SEND_W3GS_PLAYERLEAVE_OTHERS( KickedPlayer->GetPID( ), KickedPlayer->GetLeftCode( ) ) ); KickedPlayer->SetLeftMessageSent( true ); + KickedPlayer->deleteLater(); } } } @@ -1919,7 +1849,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( SID >= m_Slots.size( ) ) { potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -1929,7 +1859,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_GHost->m_BanMethod == 0 ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == JoinedRealm ) { @@ -1938,8 +1868,8 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( Ban ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is using a banned name" ); - SendAllChat( m_GHost->m_Language->HasBannedName( joinPlayer->GetName( ) ) ); - SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->HasBannedName( joinPlayer->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); break; } } @@ -1949,8 +1879,8 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( Ban ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is using a banned IP address" ); - SendAllChat( m_GHost->m_Language->HasBannedIP( joinPlayer->GetName( ), potential->GetExternalIPString( ), Ban->GetName( ) ) ); - SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->HasBannedIP( joinPlayer->GetName( ), potential->GetExternalIPString( ), Ban->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) ); break; } } @@ -1972,13 +1902,13 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP // consider LAN players to have already spoof checked since they can't // since so many people have trouble with this feature we now use the JoinedRealm to determine LAN status - if( JoinedRealm.empty( ) ) + if( JoinedRealm.isEmpty( ) ) Player->SetSpoofed( true ); Player->SetWhoisShouldBeSent( m_GHost->m_SpoofChecks == 1 || ( m_GHost->m_SpoofChecks == 2 && AnyAdminCheck ) ); m_Players.push_back( Player ); potential->SetSocket( NULL ); - potential->SetDeleteMe( true ); + potential->deleteLater(); if( m_SaveGame ) m_Slots[SID] = EnforceSlot; @@ -2019,20 +1949,20 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP // send slot info to the new player // the SLOTINFOJOIN packet also tells the client their assigned PID and that the join was successful - Player->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( Player->GetPID( ), Player->GetSocket( )->GetPort( ), Player->GetExternalIP( ), m_Slots, m_RandomSeed, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); + Player->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( Player->GetPID( ), Util::fromUInt16(Player->GetSocket( )->localPort()), Player->GetExternalIP( ), m_Slots, m_RandomSeed, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); // send virtual host info and fake player info (if present) to the new player SendVirtualHostPlayerInfo( Player ); SendFakePlayerInfo( Player ); - BYTEARRAY BlankIP; - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); + QByteArray BlankIP; + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && *i != Player ) { @@ -2072,17 +2002,17 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_GHost->m_RequireSpoofChecks && !Player->GetWhoisShouldBeSent( ) ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { // note: the following (commented out) line of code will crash because calling GetUniqueName( ) twice will result in two different return values // and unfortunately iterators are not valid if compared against different containers // this comment shall serve as warning to not make this mistake again since it has now been made twice before in GHost++ - // string( (*i)->GetUniqueName( ).begin( ), (*i)->GetUniqueName( ).end( ) ) + // QString( (*i)->GetUniqueName( ).begin( ), (*i)->GetUniqueName( ).end( ) ) - BYTEARRAY UniqueName = (*i)->GetUniqueName( ); + QByteArray UniqueName = (*i)->GetUniqueName( ); if( (*i)->GetServer( ) == JoinedRealm ) - SendChat( Player, m_GHost->m_Language->SpoofCheckByWhispering( string( UniqueName.begin( ), UniqueName.end( ) ) ) ); + SendChat( Player, m_GHost->GetLanguage( )->SpoofCheckByWhispering( UniqueName ) ); } } @@ -2090,28 +2020,28 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_GHost->m_CheckMultipleIPUsage ) { - string Others; + QString Others; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( Player != *i && Player->GetExternalIPString( ) == (*i)->GetExternalIPString( ) ) { - if( Others.empty( ) ) + if( Others.isEmpty( ) ) Others = (*i)->GetName( ); else Others += ", " + (*i)->GetName( ); } } - if( !Others.empty( ) ) - SendAllChat( m_GHost->m_Language->MultipleIPAddressUsageDetected( joinPlayer->GetName( ), Others ) ); + if( !Others.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->MultipleIPAddressUsageDetected( joinPlayer->GetName( ), Others ) ); } // abort the countdown if there was one in progress if( m_CountDownStarted && !m_GameLoading && !m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->CountDownAborted( ) ); + SendAllChat( m_GHost->GetLanguage( )->CountDownAborted( ) ); m_CountDownStarted = false; } @@ -2119,7 +2049,7 @@ void CBaseGame :: EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinP if( m_GHost->m_AutoLock && !m_Locked && IsOwner( joinPlayer->GetName( ) ) ) { - SendAllChat( m_GHost->m_Language->GameLocked( ) ); + SendAllChat( m_GHost->GetLanguage( )->GameLocked( ) ); m_Locked = true; } } @@ -2137,7 +2067,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game with the virtual host name" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2146,9 +2076,9 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( GetPlayerFromName( joinPlayer->GetName( ), false ) ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but that name is already taken" ); - // SendAllChat( m_GHost->m_Language->TryingToJoinTheGameButTaken( joinPlayer->GetName( ) ) ); + // SendAllChat( m_GHost->GetLanguage( )->TryingToJoinTheGameButTaken( joinPlayer->GetName( ) ) ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2156,9 +2086,9 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( score > -99999.0 && ( score < m_MinimumScore || score > m_MaximumScore ) ) { - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has a rating [" + UTIL_ToString( score, 2 ) + "] outside the limits [" + UTIL_ToString( m_MinimumScore, 2 ) + "] to [" + UTIL_ToString( m_MaximumScore, 2 ) + "]" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has a rating [" + QString::number( score, 'g', 2 ) + "] outside the limits [" + QString::number( m_MinimumScore, 'g', 2 ) + "] to [" + QString::number( m_MaximumScore, 'g', 2 ) + "]" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2171,7 +2101,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco bool AnyAdminCheck = false; - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) ) { @@ -2180,6 +2110,12 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco } } + bool Reserved = IsReserved( joinPlayer->GetName( ) ) || ( m_GHost->m_ReserveAdmins && AnyAdminCheck ) || IsOwner( joinPlayer->GetName( ) ); + + // stop some timers + if (Reserved) + m_LobbyTimeoutTimer.stop(); + if( SID == 255 ) { // no empty slot found, time to do some matchmaking! @@ -2198,7 +2134,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco // this ensures that the players' scores will tend to converge as players join the game double AverageScore = 0.0; - uint32_t PlayersScored = 0; + quint32 PlayersScored = 0; if( score > -99999.0 ) { @@ -2206,7 +2142,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco PlayersScored = 1; } - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetScore( ) > -99999.0 ) { @@ -2222,7 +2158,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco CGamePlayer *FurthestPlayer = NULL; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !FurthestPlayer || (*i)->GetScore( ) < -99999.0 || abs( (*i)->GetScore( ) - AverageScore ) > abs( FurthestPlayer->GetScore( ) - AverageScore ) ) FurthestPlayer = *i; @@ -2234,7 +2170,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but no furthest player was found (this should be impossible)" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2243,24 +2179,23 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( score < -99999.0 || abs( score - AverageScore ) > abs( FurthestPlayer->GetScore( ) - AverageScore ) ) { if( score < -99999.0 ) - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the furthest rating [N/A] from the average [" + UTIL_ToString( AverageScore, 2 ) + "]" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the furthest rating [N/A] from the average [" + QString::number( AverageScore, 'g', 2 ) + "]" ); else - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the furthest rating [" + UTIL_ToString( score, 2 ) + "] from the average [" + UTIL_ToString( AverageScore, 2 ) + "]" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the furthest rating [" + QString::number( score, 'g', 2 ) + "] from the average [" + QString::number( AverageScore, 'g', 2 ) + "]" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } // kick the furthest player SID = GetSIDFromPID( FurthestPlayer->GetPID( ) ); - FurthestPlayer->SetDeleteMe( true ); if( FurthestPlayer->GetScore( ) < -99999.0 ) - FurthestPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForHavingFurthestScore( "N/A", UTIL_ToString( AverageScore, 2 ) ) ); + FurthestPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForHavingFurthestScore( "N/A", QString::number( AverageScore, 'g', 2 ) ) ); else - FurthestPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForHavingFurthestScore( UTIL_ToString( FurthestPlayer->GetScore( ), 2 ), UTIL_ToString( AverageScore, 2 ) ) ); + FurthestPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForHavingFurthestScore( QString::number( FurthestPlayer->GetScore( ), 'g', 2 ), QString::number( AverageScore, 'g', 2 ) ) ); FurthestPlayer->SetLeftCode( PLAYERLEAVE_LOBBY ); @@ -2269,11 +2204,12 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco SendAll( m_Protocol->SEND_W3GS_PLAYERLEAVE_OTHERS( FurthestPlayer->GetPID( ), FurthestPlayer->GetLeftCode( ) ) ); FurthestPlayer->SetLeftMessageSent( true ); + FurthestPlayer->deleteLater(); if( FurthestPlayer->GetScore( ) < -99999.0 ) - SendAllChat( m_GHost->m_Language->PlayerWasKickedForFurthestScore( FurthestPlayer->GetName( ), "N/A", UTIL_ToString( AverageScore, 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerWasKickedForFurthestScore( FurthestPlayer->GetName( ), "N/A", QString::number( AverageScore, 'g', 2 ) ) ); else - SendAllChat( m_GHost->m_Language->PlayerWasKickedForFurthestScore( FurthestPlayer->GetName( ), UTIL_ToString( FurthestPlayer->GetScore( ), 2 ), UTIL_ToString( AverageScore, 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerWasKickedForFurthestScore( FurthestPlayer->GetName( ), QString::number( FurthestPlayer->GetScore( ), 'g', 2 ), QString::number( AverageScore, 'g', 2 ) ) ); } else if( m_GHost->m_MatchMakingMethod == 2 ) { @@ -2282,7 +2218,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco CGamePlayer *LowestPlayer = NULL; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !LowestPlayer || (*i)->GetScore( ) < -99999.0 || (*i)->GetScore( ) < LowestPlayer->GetScore( ) ) LowestPlayer = *i; @@ -2294,7 +2230,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but no lowest player was found (this should be impossible)" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2305,22 +2241,21 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( score < -99999.0 ) CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the lowest rating [N/A]" ); else - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the lowest rating [" + UTIL_ToString( score, 2 ) + "]" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] is trying to join the game but has the lowest rating [" + QString::number( score, 'g', 2 ) + "]" ); potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } // kick the lowest player SID = GetSIDFromPID( LowestPlayer->GetPID( ) ); - LowestPlayer->SetDeleteMe( true ); if( LowestPlayer->GetScore( ) < -99999.0 ) - LowestPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForHavingLowestScore( "N/A" ) ); + LowestPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForHavingLowestScore( "N/A" ) ); else - LowestPlayer->SetLeftReason( m_GHost->m_Language->WasKickedForHavingLowestScore( UTIL_ToString( LowestPlayer->GetScore( ), 2 ) ) ); + LowestPlayer->SetLeftReason( m_GHost->GetLanguage( )->WasKickedForHavingLowestScore( QString::number( LowestPlayer->GetScore( ), 'g', 2 ) ) ); LowestPlayer->SetLeftCode( PLAYERLEAVE_LOBBY ); @@ -2329,18 +2264,19 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco SendAll( m_Protocol->SEND_W3GS_PLAYERLEAVE_OTHERS( LowestPlayer->GetPID( ), LowestPlayer->GetLeftCode( ) ) ); LowestPlayer->SetLeftMessageSent( true ); + LowestPlayer->deleteLater(); if( LowestPlayer->GetScore( ) < -99999.0 ) - SendAllChat( m_GHost->m_Language->PlayerWasKickedForLowestScore( LowestPlayer->GetName( ), "N/A" ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerWasKickedForLowestScore( LowestPlayer->GetName( ), "N/A" ) ); else - SendAllChat( m_GHost->m_Language->PlayerWasKickedForLowestScore( LowestPlayer->GetName( ), UTIL_ToString( LowestPlayer->GetScore( ), 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerWasKickedForLowestScore( LowestPlayer->GetName( ), QString::number( LowestPlayer->GetScore( ), 'g', 2 ) ) ); } } if( SID >= m_Slots.size( ) ) { potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) ); - potential->SetDeleteMe( true ); + potential->deleteLater(); return; } @@ -2355,14 +2291,14 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco // the client sends the host counter when it joins so we can extract the ID value here // note: this is not a replacement for spoof checking since it doesn't verify the player's name and it can be spoofed anyway - uint32_t HostCounterID = joinPlayer->GetHostCounter( ) >> 28; - string JoinedRealm; + quint32 HostCounterID = joinPlayer->GetHostCounter( ) >> 28; + QString JoinedRealm; // we use an ID value of 0 to denote joining via LAN if( HostCounterID != 0 ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetHostCounterID( ) == HostCounterID ) JoinedRealm = (*i)->GetServer( ); @@ -2379,33 +2315,33 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco // consider LAN players to have already spoof checked since they can't // since so many people have trouble with this feature we now use the JoinedRealm to determine LAN status - if( JoinedRealm.empty( ) ) + if( JoinedRealm.isEmpty( ) ) Player->SetSpoofed( true ); Player->SetWhoisShouldBeSent( m_GHost->m_SpoofChecks == 1 || ( m_GHost->m_SpoofChecks == 2 && AnyAdminCheck ) ); Player->SetScore( score ); m_Players.push_back( Player ); potential->SetSocket( NULL ); - potential->SetDeleteMe( true ); + potential->deleteLater(); m_Slots[SID] = CGameSlot( Player->GetPID( ), 255, SLOTSTATUS_OCCUPIED, 0, m_Slots[SID].GetTeam( ), m_Slots[SID].GetColour( ), m_Slots[SID].GetRace( ) ); // send slot info to the new player // the SLOTINFOJOIN packet also tells the client their assigned PID and that the join was successful - Player->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( Player->GetPID( ), Player->GetSocket( )->GetPort( ), Player->GetExternalIP( ), m_Slots, m_RandomSeed, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); + Player->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( Player->GetPID( ), Util::fromUInt16((quint16)Player->GetSocket( )->localPort()), Player->GetExternalIP( ), m_Slots, m_RandomSeed, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) ); // send virtual host info and fake player info (if present) to the new player SendVirtualHostPlayerInfo( Player ); SendFakePlayerInfo( Player ); - BYTEARRAY BlankIP; - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); - BlankIP.push_back( 0 ); + QByteArray BlankIP; + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); + BlankIP.push_back( (char)0 ); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && *i != Player ) { @@ -2445,33 +2381,33 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( m_GHost->m_RequireSpoofChecks && !Player->GetWhoisShouldBeSent( ) ) { - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + for( QList :: const_iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) { // note: the following (commented out) line of code will crash because calling GetUniqueName( ) twice will result in two different return values // and unfortunately iterators are not valid if compared against different containers // this comment shall serve as warning to not make this mistake again since it has now been made twice before in GHost++ - // string( (*i)->GetUniqueName( ).begin( ), (*i)->GetUniqueName( ).end( ) ) + // QString( (*i)->GetUniqueName( ).begin( ), (*i)->GetUniqueName( ).end( ) ) - BYTEARRAY UniqueName = (*i)->GetUniqueName( ); + QByteArray UniqueName = (*i)->GetUniqueName( ); if( (*i)->GetServer( ) == JoinedRealm ) - SendChat( Player, m_GHost->m_Language->SpoofCheckByWhispering( string( UniqueName.begin( ), UniqueName.end( ) ) ) ); + SendChat( Player, m_GHost->GetLanguage( )->SpoofCheckByWhispering( UniqueName.end( )) ); } } if( score < -99999.0 ) - SendAllChat( m_GHost->m_Language->PlayerHasScore( joinPlayer->GetName( ), "N/A" ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerHasScore( joinPlayer->GetName( ), "N/A" ) ); else - SendAllChat( m_GHost->m_Language->PlayerHasScore( joinPlayer->GetName( ), UTIL_ToString( score, 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerHasScore( joinPlayer->GetName( ), QString::number( score, 'g', 2 ) ) ); - uint32_t PlayersScored = 0; - uint32_t PlayersNotScored = 0; + quint32 PlayersScored = 0; + quint32 PlayersNotScored = 0; double AverageScore = 0.0; double MinScore = 0.0; double MaxScore = 0.0; bool Found = false; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) { @@ -2494,34 +2430,34 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco } double Spread = MaxScore - MinScore; - SendAllChat( m_GHost->m_Language->RatedPlayersSpread( UTIL_ToString( PlayersScored ), UTIL_ToString( PlayersScored + PlayersNotScored ), UTIL_ToString( (uint32_t)Spread ) ) ); + SendAllChat( m_GHost->GetLanguage( )->RatedPlayersSpread( QString::number( PlayersScored ), QString::number( PlayersScored + PlayersNotScored ), QString::number( (quint32)Spread ) ) ); // check for multiple IP usage if( m_GHost->m_CheckMultipleIPUsage ) { - string Others; + QString Others; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( Player != *i && Player->GetExternalIPString( ) == (*i)->GetExternalIPString( ) ) { - if( Others.empty( ) ) + if( Others.isEmpty( ) ) Others = (*i)->GetName( ); else Others += ", " + (*i)->GetName( ); } } - if( !Others.empty( ) ) - SendAllChat( m_GHost->m_Language->MultipleIPAddressUsageDetected( joinPlayer->GetName( ), Others ) ); + if( !Others.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->MultipleIPAddressUsageDetected( joinPlayer->GetName( ), Others ) ); } // abort the countdown if there was one in progress if( m_CountDownStarted && !m_GameLoading && !m_GameLoaded ) { - SendAllChat( m_GHost->m_Language->CountDownAborted( ) ); + SendAllChat( m_GHost->GetLanguage( )->CountDownAborted( ) ); m_CountDownStarted = false; } @@ -2529,7 +2465,7 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco if( m_GHost->m_AutoLock && !m_Locked && IsOwner( joinPlayer->GetName( ) ) ) { - SendAllChat( m_GHost->m_Language->GameLocked( ) ); + SendAllChat( m_GHost->GetLanguage( )->GameLocked( ) ); m_Locked = true; } @@ -2539,26 +2475,28 @@ void CBaseGame :: EventPlayerJoinedWithScore( CPotentialPlayer *potential, CInco BalanceSlots( ); } -void CBaseGame :: EventPlayerLeft( CGamePlayer *player, uint32_t reason ) +void CBaseGame :: EventPlayerLeft( CGamePlayer *player, quint32 reason ) { // this function is only called when a player leave packet is received, not when there's a socket error, kick, etc... + DEBUG_Print("EventPlayerLeft"); - player->SetDeleteMe( true ); if( reason == PLAYERLEAVE_GPROXY ) - player->SetLeftReason( m_GHost->m_Language->WasUnrecoverablyDroppedFromGProxy( ) ); + player->SetLeftReason( m_GHost->GetLanguage( )->WasUnrecoverablyDroppedFromGProxy( ) ); else - player->SetLeftReason( m_GHost->m_Language->HasLeftVoluntarily( ) ); + player->SetLeftReason( m_GHost->GetLanguage( )->HasLeftVoluntarily( ) ); player->SetLeftCode( PLAYERLEAVE_LOST ); + player->deleteLater(); if( !m_GameLoading && !m_GameLoaded ) OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); } -void CBaseGame :: EventPlayerLoaded( CGamePlayer *player ) +void CBaseGame :: EventPlayerLoaded() { - CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + player->GetName( ) + "] finished loading in " + UTIL_ToString( (float)( player->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 2 ) + " seconds" ); + CGamePlayer *player = (CGamePlayer*)QObject::sender(); + CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + player->GetName( ) + "] finished loading in " + QString::number( (float)( player->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 'g' ) + " seconds" ); if( m_LoadInGame ) { @@ -2566,19 +2504,16 @@ void CBaseGame :: EventPlayerLoaded( CGamePlayer *player ) // see the Update function for more information about why we do this // this includes player loaded messages, game updates, and player leave messages - queue *LoadInGameData = player->GetLoadInGameData( ); + QQueue *LoadInGameData = player->GetLoadInGameData( ); while( !LoadInGameData->empty( ) ) - { - Send( player, LoadInGameData->front( ) ); - LoadInGameData->pop( ); - } + Send( player, LoadInGameData->dequeue( ) ); // start the lag screen for the new player bool FinishedLoading = true; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { FinishedLoading = (*i)->GetFinishedLoading( ); @@ -2591,7 +2526,7 @@ void CBaseGame :: EventPlayerLoaded( CGamePlayer *player ) // remove the new player from previously loaded players' lag screens - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( *i != player && (*i)->GetFinishedLoading( ) ) Send( *i, m_Protocol->SEND_W3GS_STOP_LAG( player ) ); @@ -2599,57 +2534,56 @@ void CBaseGame :: EventPlayerLoaded( CGamePlayer *player ) // send a chat message to previously loaded players - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( *i != player && (*i)->GetFinishedLoading( ) ) - SendChat( *i, m_GHost->m_Language->PlayerFinishedLoading( player->GetName( ) ) ); + SendChat( *i, m_GHost->GetLanguage( )->PlayerFinishedLoading( player->GetName( ) ) ); } if( !FinishedLoading ) - SendChat( player, m_GHost->m_Language->PleaseWaitPlayersStillLoading( ) ); + SendChat( player, m_GHost->GetLanguage( )->PleaseWaitPlayersStillLoading( ) ); } else SendAll( m_Protocol->SEND_W3GS_GAMELOADED_OTHERS( player->GetPID( ) ) ); + + CheckGameLoaded(); } void CBaseGame :: EventPlayerAction( CGamePlayer *player, CIncomingAction *action ) { - m_Actions.push( action ); + m_Actions.enqueue( action ); // check for players saving the game and notify everyone - if( !action->GetAction( )->empty( ) && (*action->GetAction( ))[0] == 6 ) + if( !action->GetAction( ).isEmpty( ) && action->GetAction( ).at(0) == 6 ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + player->GetName( ) + "] is saving the game" ); - SendAllChat( m_GHost->m_Language->PlayerIsSavingTheGame( player->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerIsSavingTheGame( player->GetName( ) ) ); } } -void CBaseGame :: EventPlayerKeepAlive( CGamePlayer *player, uint32_t checkSum ) +void CBaseGame :: EventPlayerKeepAlive( CGamePlayer */*player*/, quint32 /*checkSum*/ ) { // check for desyncs // however, it's possible that not every player has sent a checksum for this frame yet // first we verify that we have enough checksums to work with otherwise we won't know exactly who desynced - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - if( !(*i)->GetDeleteMe( ) && (*i)->GetCheckSums( )->empty( ) ) + if( (*i)->GetCheckSums( )->empty( ) ) return; } // now we check for desyncs since we know that every player has at least one checksum waiting bool FoundPlayer = false; - uint32_t FirstCheckSum = 0; + quint32 FirstCheckSum = 0; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - if( !(*i)->GetDeleteMe( ) ) - { - FoundPlayer = true; - FirstCheckSum = (*i)->GetCheckSums( )->front( ); - break; - } + FoundPlayer = true; + FirstCheckSum = (*i)->GetCheckSums( )->front( ); + break; } if( !FoundPlayer ) @@ -2657,59 +2591,56 @@ void CBaseGame :: EventPlayerKeepAlive( CGamePlayer *player, uint32_t checkSum ) bool AddToReplay = true; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - if( !(*i)->GetDeleteMe( ) && (*i)->GetCheckSums( )->front( ) != FirstCheckSum ) + if( (*i)->GetCheckSums( )->front( ) != FirstCheckSum ) { CONSOLE_Print( "[GAME: " + m_GameName + "] desync detected" ); - SendAllChat( m_GHost->m_Language->DesyncDetected( ) ); + SendAllChat( m_GHost->GetLanguage( )->DesyncDetected( ) ); // try to figure out who desynced // this is complicated by the fact that we don't know what the correct game state is so we let the players vote // put the players into bins based on their game state - map > Bins; + QMap > Bins; - for( vector :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) - { - if( !(*j)->GetDeleteMe( ) ) - Bins[(*j)->GetCheckSums( )->front( )].push_back( (*j)->GetPID( ) ); - } + for( QList :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) + Bins[(*j)->GetCheckSums( )->front( )].push_back( (*j)->GetPID( ) ); - uint32_t StateNumber = 1; - map > :: iterator LargestBin = Bins.begin( ); + quint32 StateNumber = 1; + QMap > :: iterator LargestBin = Bins.begin( ); bool Tied = false; - for( map > :: iterator j = Bins.begin( ); j != Bins.end( ); j++ ) + for( QMap > :: iterator j = Bins.begin( ); j != Bins.end( ); j++ ) { - if( (*j).second.size( ) > (*LargestBin).second.size( ) ) + if( j.value().size( ) > LargestBin.value().size( ) ) { LargestBin = j; Tied = false; } - else if( j != LargestBin && (*j).second.size( ) == (*LargestBin).second.size( ) ) + else if( j != LargestBin && j.value().size( ) == LargestBin.value().size( ) ) Tied = true; - string Players; + QString Players; - for( vector :: iterator k = (*j).second.begin( ); k != (*j).second.end( ); k++ ) + for( QList :: iterator k = j.value().begin( ); k != j.value().end( ); k++ ) { CGamePlayer *Player = GetPlayerFromPID( *k ); if( Player ) { - if( Players.empty( ) ) + if( Players.isEmpty( ) ) Players = Player->GetName( ); else Players += ", " + Player->GetName( ); } } - SendAllChat( m_GHost->m_Language->PlayersInGameState( UTIL_ToString( StateNumber ), Players ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayersInGameState( QString::number( StateNumber ), Players ) ); StateNumber++; } - FirstCheckSum = (*LargestBin).first; + FirstCheckSum = LargestBin.key(); if( Tied ) { @@ -2721,31 +2652,31 @@ void CBaseGame :: EventPlayerKeepAlive( CGamePlayer *player, uint32_t checkSum ) // todotodo: it would be possible to split the game at this point and create a "new" game for each game state CONSOLE_Print( "[GAME: " + m_GameName + "] can't kick desynced players because there is a tie, kicking all players instead" ); - StopPlayers( m_GHost->m_Language->WasDroppedDesync( ) ); + StopPlayers( m_GHost->GetLanguage( )->WasDroppedDesync( ) ); AddToReplay = false; } else { CONSOLE_Print( "[GAME: " + m_GameName + "] kicking desynced players" ); - for( map > :: iterator j = Bins.begin( ); j != Bins.end( ); j++ ) + for( QMap > :: iterator j = Bins.begin( ); j != Bins.end( ); j++ ) { // kick players who are NOT in the largest bin // examples: suppose there are 10 players // the most common case will be 9v1 (e.g. one player desynced and the others were unaffected) and this will kick the single outlier // another (very unlikely) possibility is 8v1v1 or 8v2 and this will kick both of the outliers, regardless of whether their game states match - if( (*j).first != (*LargestBin).first ) + if( j.key() != LargestBin.key() ) { - for( vector :: iterator k = (*j).second.begin( ); k != (*j).second.end( ); k++ ) + for( QList :: iterator k = j.value().begin( ); k != j.value().end( ); k++ ) { CGamePlayer *Player = GetPlayerFromPID( *k ); if( Player ) { - Player->SetDeleteMe( true ); - Player->SetLeftReason( m_GHost->m_Language->WasDroppedDesync( ) ); + Player->SetLeftReason( m_GHost->GetLanguage( )->WasDroppedDesync( ) ); Player->SetLeftCode( PLAYERLEAVE_LOST ); + Player->deleteLater(); } } } @@ -2758,11 +2689,8 @@ void CBaseGame :: EventPlayerKeepAlive( CGamePlayer *player, uint32_t checkSum ) } } - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( !(*i)->GetDeleteMe( ) ) - (*i)->GetCheckSums( )->pop( ); - } + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + (*i)->GetCheckSums( )->dequeue( ); // add checksum to replay @@ -2779,12 +2707,12 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye // relay the chat message to other players bool Relay = !player->GetMuted( ); - BYTEARRAY ExtraFlags = chatPlayer->GetExtraFlags( ); + QByteArray ExtraFlags = chatPlayer->GetExtraFlags( ); // calculate timestamp - string MinString = UTIL_ToString( ( m_GameTicks / 1000 ) / 60 ); - string SecString = UTIL_ToString( ( m_GameTicks / 1000 ) % 60 ); + QString MinString = QString::number( ( m_GameTicks / 1000 ) / 60 ); + QString SecString = QString::number( ( m_GameTicks / 1000 ) % 60 ); if( MinString.size( ) == 1 ) MinString.insert( 0, "0" ); @@ -2792,9 +2720,9 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye if( SecString.size( ) == 1 ) SecString.insert( 0, "0" ); - if( !ExtraFlags.empty( ) ) + if( !ExtraFlags.isEmpty( ) ) { - if( ExtraFlags[0] == 0 ) + if( ExtraFlags.at(0) == 0 ) { // this is an ingame [All] message, print it to the console @@ -2806,7 +2734,7 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye if( m_MuteAll ) Relay = false; } - else if( ExtraFlags[0] == 2 ) + else if( ExtraFlags.at(0) == 2 ) { // this is an ingame [Obs/Ref] message, print it to the console @@ -2819,7 +2747,7 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye // this includes allied chat and private chat from both teams as long as it was relayed if( m_Replay ) - m_Replay->AddChatMessage( chatPlayer->GetFromPID( ), chatPlayer->GetFlag( ), UTIL_ByteArrayToUInt32( chatPlayer->GetExtraFlags( ), false ), chatPlayer->GetMessage( ) ); + m_Replay->AddChatMessage( chatPlayer->GetFromPID( ), chatPlayer->GetFlag( ), Util::extractUInt32(chatPlayer->GetExtraFlags( )), chatPlayer->GetMessage( ) ); } } else @@ -2834,28 +2762,28 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye // handle bot commands - string Message = chatPlayer->GetMessage( ); + QString Message = chatPlayer->GetMessage( ); if( Message == "?trigger" ) - SendChat( player, m_GHost->m_Language->CommandTrigger( string( 1, m_GHost->m_CommandTrigger ) ) ); - else if( !Message.empty( ) && Message[0] == m_GHost->m_CommandTrigger ) + SendChat( player, m_GHost->GetLanguage( )->CommandTrigger( QString( 1, m_GHost->m_CommandTrigger ) ) ); + else if( !Message.isEmpty( ) && Message[0] == m_GHost->m_CommandTrigger ) { // extract the command trigger, the command, and the payload // e.g. "!say hello world" -> command: "say", payload: "hello world" - string Command; - string Payload; - string :: size_type PayloadStart = Message.find( " " ); + QString Command; + QString Payload; + int PayloadStart = Message.indexOf( ' ' ); - if( PayloadStart != string :: npos ) + if( PayloadStart != -1 ) { - Command = Message.substr( 1, PayloadStart - 1 ); - Payload = Message.substr( PayloadStart + 1 ); + Command = Message.mid( 1, PayloadStart - 1 ); + Payload = Message.mid( PayloadStart + 1 ); } else - Command = Message.substr( 1 ); + Command = Message.mid( 1 ); - transform( Command.begin( ), Command.end( ), Command.begin( ), (int(*)(int))tolower ); + Command = Command.toLower(); // don't allow EventPlayerBotCommand to veto a previous instruction to set Relay to false // so if Relay is already false (e.g. because the player is muted) then it cannot be forced back to true here @@ -2878,10 +2806,10 @@ void CBaseGame :: EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlaye } } -bool CBaseGame :: EventPlayerBotCommand( CGamePlayer *player, string command, string payload ) +bool CBaseGame :: EventPlayerBotCommand( CGamePlayer *player, const QString &command, const QString &payload ) { // return true if the command itself should be hidden from other players - + emit SignalPlayerCommand( this, player, command, payload ); return false; } @@ -3031,20 +2959,20 @@ void CBaseGame :: EventPlayerDropRequest( CGamePlayer *player ) if( m_Lagging ) { CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + player->GetName( ) + "] voted to drop laggers" ); - SendAllChat( m_GHost->m_Language->PlayerVotedToDropLaggers( player->GetName( ) ) ); + SendAllChat( m_GHost->GetLanguage( )->PlayerVotedToDropLaggers( player->GetName( ) ) ); // check if at least half the players voted to drop - uint32_t Votes = 0; + quint32 Votes = 0; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetDropVote( ) ) Votes++; } if( (float)Votes / m_Players.size( ) > 0.49 ) - StopLaggers( m_GHost->m_Language->LaggedOutDroppedByVote( ) ); + StopLaggers( m_GHost->GetLanguage( )->LaggedOutDroppedByVote( ) ); } } @@ -3055,7 +2983,7 @@ void CBaseGame :: EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *map // todotodo: the variable names here are confusing due to extremely poor design on my part - uint32_t MapSize = UTIL_ByteArrayToUInt32( m_Map->GetMapSize( ), false ); + quint32 MapSize = Util::extractUInt32(m_Map->GetMapSize( )); if( mapSize->GetSizeFlag( ) != 1 || mapSize->GetMapSize( ) != MapSize ) { @@ -3063,9 +2991,9 @@ void CBaseGame :: EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *map if( m_GHost->m_AllowDownloads != 0 ) { - string *MapData = m_Map->GetMapData( ); + const QByteArray &MapData = m_Map->GetMapData( ); - if( !MapData->empty( ) ) + if( !MapData.isEmpty( ) ) { if( m_GHost->m_AllowDownloads == 1 || ( m_GHost->m_AllowDownloads == 2 && player->GetDownloadAllowed( ) ) ) { @@ -3084,17 +3012,17 @@ void CBaseGame :: EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *map } else { - player->SetDeleteMe( true ); player->SetLeftReason( "doesn't have the map and there is no local copy of the map to send" ); player->SetLeftCode( PLAYERLEAVE_LOBBY ); + player->deleteLater(); OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); } } else { - player->SetDeleteMe( true ); player->SetLeftReason( "doesn't have the map and map downloads are disabled" ); player->SetLeftCode( PLAYERLEAVE_LOBBY ); + player->deleteLater(); OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); } } @@ -3106,8 +3034,8 @@ void CBaseGame :: EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *map float Seconds = (float)( GetTicks( ) - player->GetStartedDownloadingTicks( ) ) / 1000; float Rate = (float)MapSize / 1024 / Seconds; - CONSOLE_Print( "[GAME: " + m_GameName + "] map download finished for player [" + player->GetName( ) + "] in " + UTIL_ToString( Seconds, 1 ) + " seconds" ); - SendAllChat( m_GHost->m_Language->PlayerDownloadedTheMap( player->GetName( ), UTIL_ToString( Seconds, 1 ), UTIL_ToString( Rate, 1 ) ) ); + CONSOLE_Print( "[GAME: " + m_GameName + "] map download finished for player [" + player->GetName( ) + "] in " + QString::number( Seconds, 'g', 1 ) + " seconds" ); + SendAllChat( m_GHost->GetLanguage( )->PlayerDownloadedTheMap( player->GetName( ), QString::number( Seconds, 'g', 1 ), QString::number( Rate, 'g', 1 ) ) ); player->SetDownloadFinished( true ); player->SetFinishedDownloadingTime( GetTime( ) ); @@ -3136,30 +3064,56 @@ void CBaseGame :: EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *map // if we send a new slot update for every percentage change in their download status it adds up to a lot of data // instead, we mark the slot info as "out of date" and update it only once in awhile (once per second when this comment was made) - m_SlotInfoChanged = true; + if (!m_SlotInfoTimer.isActive()) + m_SlotInfoTimer.start(); + } + } +} + +void CBaseGame::EventCallableUpdateTimeout() +{ + // update callables + + for( QList :: iterator i = m_ScoreChecks.begin( ); i != m_ScoreChecks.end( ); ) + { + if( (*i)->GetReady( ) ) + { + double Score = (*i)->GetResult( ); + + for( QList :: iterator j = m_Potentials.begin( ); j != m_Potentials.end( ); j++ ) + { + if( (*j)->GetJoinPlayer( ) && (*j)->GetJoinPlayer( )->GetName( ) == (*i)->GetName( ) ) + EventPlayerJoinedWithScore( *j, (*j)->GetJoinPlayer( ), Score ); + } + + m_GHost->m_DB->RecoverCallable( *i ); + delete *i; + i = m_ScoreChecks.erase( i ); } + else + i++; } } -void CBaseGame :: EventPlayerPongToHost( CGamePlayer *player, uint32_t pong ) +void CBaseGame :: EventPlayerPongToHost( CGamePlayer *player, quint32 /*pong*/ ) { // autokick players with excessive pings but only if they're not reserved and we've received at least 3 pings from them // also don't kick anyone if the game is loading or loaded - this could happen because we send pings during loading but we stop sending them after the game is loaded // see the Update function for where we send pings - if( !m_GameLoading && !m_GameLoaded && !player->GetDeleteMe( ) && !player->GetReserved( ) && player->GetNumPings( ) >= 3 && player->GetPing( m_GHost->m_LCPings ) > m_GHost->m_AutoKickPing ) + if( !m_GameLoading && !m_GameLoaded && !player->GetReserved( ) && player->GetNumPings( ) >= 3 && player->GetPing( m_GHost->m_LCPings ) > m_GHost->m_AutoKickPing ) { // send a chat message because we don't normally do so when a player leaves the lobby - SendAllChat( m_GHost->m_Language->AutokickingPlayerForExcessivePing( player->GetName( ), UTIL_ToString( player->GetPing( m_GHost->m_LCPings ) ) ) ); - player->SetDeleteMe( true ); - player->SetLeftReason( "was autokicked for excessive ping of " + UTIL_ToString( player->GetPing( m_GHost->m_LCPings ) ) ); + SendAllChat( m_GHost->GetLanguage( )->AutokickingPlayerForExcessivePing( player->GetName( ), QString::number( player->GetPing( m_GHost->m_LCPings ) ) ) ); + player->SetLeftReason( "was autokicked for excessive ping of " + QString::number( player->GetPing( m_GHost->m_LCPings ) ) ); player->SetLeftCode( PLAYERLEAVE_LOBBY ); + player->deleteLater(); OpenSlot( GetSIDFromPID( player->GetPID( ) ), false ); } } -void CBaseGame :: EventGameRefreshed( string server ) +void CBaseGame :: EventGameRefreshed( const QString &/*server*/ ) { if( m_RefreshRehosted ) { @@ -3167,19 +3121,19 @@ void CBaseGame :: EventGameRefreshed( string server ) // but since we unqueue game refreshes when rehosting, the only way this can happen is due to network delay // it's a risk we're willing to take but can result in a false positive here - SendAllChat( m_GHost->m_Language->RehostWasSuccessful( ) ); + SendAllChat( m_GHost->GetLanguage( )->RehostWasSuccessful( ) ); m_RefreshRehosted = false; } } void CBaseGame :: EventGameStarted( ) { - CONSOLE_Print( "[GAME: " + m_GameName + "] started loading with " + UTIL_ToString( GetNumHumanPlayers( ) ) + " players" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] started loading with " + QString::number( GetNumHumanPlayers( ) ) + " players" ); - // encode the HCL command string in the slot handicaps + // encode the HCL command QString in the slot handicaps // here's how it works: - // the user inputs a command string to be sent to the map - // it is almost impossible to send a message from the bot to the map so we encode the command string in the slot handicaps + // the user inputs a command QString to be sent to the map + // it is almost impossible to send a message from the bot to the map so we encode the command QString in the slot handicaps // this works because there are only 6 valid handicaps but Warcraft III allows the bot to set up to 256 handicaps // we encode the original (unmodified) handicaps in the new handicaps and use the remaining space to store a short message // only occupied slots deliver their handicaps to the map and we can send one character (from a list) per handicap @@ -3190,18 +3144,18 @@ void CBaseGame :: EventGameStarted( ) // note: if you attempt to use the HCL system on a map that does not support HCL the bot will drastically modify the handicaps // since the map won't automatically restore the original handicaps in this case your game will be ruined - if( !m_HCLCommandString.empty( ) ) + if( !m_HCLCommandString.isEmpty( ) ) { - if( m_HCLCommandString.size( ) <= GetSlotsOccupied( ) ) + if( m_HCLCommandString.size( ) <= (int)GetSlotsOccupied( ) ) { - string HCLChars = "abcdefghijklmnopqrstuvwxyz0123456789 -=,."; + QString HCLChars = "abcdefghijklmnopqrstuvwxyz0123456789 -=,."; - if( m_HCLCommandString.find_first_not_of( HCLChars ) == string :: npos ) + if( m_HCLCommandString.indexOf( QRegExp( "[^" + HCLChars + "]" ) ) == -1 ) { unsigned char EncodingMap[256]; unsigned char j = 0; - for( uint32_t i = 0; i < 256; i++ ) + for( quint32 i = 0; i < 256; i++ ) { // the following 7 handicap values are forbidden @@ -3213,24 +3167,24 @@ void CBaseGame :: EventGameStarted( ) unsigned char CurrentSlot = 0; - for( string :: iterator si = m_HCLCommandString.begin( ); si != m_HCLCommandString.end( ); si++ ) + for( QString :: iterator si = m_HCLCommandString.begin( ); si != m_HCLCommandString.end( ); si++ ) { while( m_Slots[CurrentSlot].GetSlotStatus( ) != SLOTSTATUS_OCCUPIED ) CurrentSlot++; unsigned char HandicapIndex = ( m_Slots[CurrentSlot].GetHandicap( ) - 50 ) / 10; - unsigned char CharIndex = HCLChars.find( *si ); + unsigned char CharIndex = HCLChars.indexOf( *si ); m_Slots[CurrentSlot++].SetHandicap( EncodingMap[HandicapIndex + CharIndex * 6] ); } SendAllSlotInfo( ); - CONSOLE_Print( "[GAME: " + m_GameName + "] successfully encoded HCL command string [" + m_HCLCommandString + "]" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] successfully encoded HCL command QString [" + m_HCLCommandString + "]" ); } else - CONSOLE_Print( "[GAME: " + m_GameName + "] encoding HCL command string [" + m_HCLCommandString + "] failed because it contains invalid characters" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] encoding HCL command QString [" + m_HCLCommandString + "] failed because it contains invalid characters" ); } else - CONSOLE_Print( "[GAME: " + m_GameName + "] encoding HCL command string [" + m_HCLCommandString + "] failed because there aren't enough occupied slots" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] encoding HCL command QString [" + m_HCLCommandString + "] failed because there aren't enough occupied slots" ); } // send a final slot info update if necessary @@ -3239,11 +3193,10 @@ void CBaseGame :: EventGameStarted( ) // this is because we only permit slot info updates to be flagged when it's just a change in download status, all others are sent immediately // it might not be necessary but let's clean up the mess anyway - if( m_SlotInfoChanged ) + //if( m_SlotInfoChanged ) SendAllSlotInfo( ); m_StartedLoadingTicks = GetTicks( ); - m_LastLagScreenResetTime = GetTime( ); m_GameLoading = true; // since we use a fake countdown to deal with leavers during countdown the COUNTDOWN_START and COUNTDOWN_END packets are sent in quick succession @@ -3275,7 +3228,7 @@ void CBaseGame :: EventGameStarted( ) // delete any potential players that are still hanging around - for( vector :: iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) + for( QList :: const_iterator i = m_Potentials.begin( ); i != m_Potentials.end( ); i++ ) delete *i; m_Potentials.clear( ); @@ -3284,7 +3237,7 @@ void CBaseGame :: EventGameStarted( ) if( m_Replay ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) m_Replay->AddPlayer( (*i)->GetPID( ), (*i)->GetName( ) ); if( m_FakePlayerPID != 255 ) @@ -3297,7 +3250,7 @@ void CBaseGame :: EventGameStarted( ) if( m_SaveGame ) { - uint32_t MapGameType = MAPGAMETYPE_SAVEDGAME; + quint32 MapGameType = MAPGAMETYPE_SAVEDGAME; if( m_GameState == GAME_PRIVATE ) MapGameType |= MAPGAMETYPE_PRIVATEGAME; @@ -3306,7 +3259,7 @@ void CBaseGame :: EventGameStarted( ) } else { - uint32_t MapGameType = m_Map->GetMapGameType( ); + quint32 MapGameType = m_Map->GetMapGameType( ); MapGameType |= MAPGAMETYPE_UNKNOWN0; if( m_GameState == GAME_PRIVATE ) @@ -3315,7 +3268,7 @@ void CBaseGame :: EventGameStarted( ) m_Replay->SetMapGameType( MapGameType ); } - if( !m_Players.empty( ) ) + if( !m_Players.isEmpty( ) ) { // this might not be necessary since we're going to overwrite the replay's host PID and name everytime a player leaves @@ -3324,21 +3277,21 @@ void CBaseGame :: EventGameStarted( ) } } - // build a stat string for use when saving the replay + // build a stat QString for use when saving the replay // we have to build this now because the map data is going to be deleted - BYTEARRAY StatString; - UTIL_AppendByteArray( StatString, m_Map->GetMapGameFlags( ) ); - StatString.push_back( 0 ); - UTIL_AppendByteArray( StatString, m_Map->GetMapWidth( ) ); - UTIL_AppendByteArray( StatString, m_Map->GetMapHeight( ) ); - UTIL_AppendByteArray( StatString, m_Map->GetMapCRC( ) ); - UTIL_AppendByteArray( StatString, m_Map->GetMapPath( ) ); - UTIL_AppendByteArray( StatString, "GHost++" ); - StatString.push_back( 0 ); - UTIL_AppendByteArray( StatString, m_Map->GetMapSHA1( ) ); // note: in replays generated by Warcraft III it stores 20 zeros for the SHA1 instead of the real thing + QByteArray StatString; + StatString.append(m_Map->GetMapGameFlags( )); + StatString.push_back( (char)0 ); + StatString.append(m_Map->GetMapWidth( )); + StatString.append(m_Map->GetMapHeight( )); + StatString.append(m_Map->GetMapCRC( )); + StatString.append(m_Map->GetMapPath( ).toUtf8()); + StatString.append("GHost++"); + StatString.push_back( (char)0 ); + StatString.append(m_Map->GetMapSHA1( )); // note: in replays generated by Warcraft III it stores 20 zeros for the SHA1 instead of the real thing StatString = UTIL_EncodeStatString( StatString ); - m_StatString = string( StatString.begin( ), StatString.end( ) ); + m_StatString = StatString; // delete the map data @@ -3347,41 +3300,31 @@ void CBaseGame :: EventGameStarted( ) if( m_LoadInGame ) { + m_LoadInGameTimer.start(); + // buffer all the player loaded messages // this ensures that every player receives the same set of player loaded messages in the same order, even if someone leaves during loading // if someone leaves during loading we buffer the leave message to ensure it gets sent in the correct position but the player loaded message wouldn't get sent if we didn't buffer it now - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - for( vector :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) + for( QList :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) (*j)->AddLoadInGameData( m_Protocol->SEND_W3GS_GAMELOADED_OTHERS( (*i)->GetPID( ) ) ); } } - - // move the game to the games in progress vector - - m_GHost->m_CurrentGame = NULL; - m_GHost->m_Games.push_back( this ); - - // and finally reenter battle.net chat - - for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) - { - (*i)->QueueGameUncreate( ); - (*i)->QueueEnterChat( ); - } } void CBaseGame :: EventGameLoaded( ) { - CONSOLE_Print( "[GAME: " + m_GameName + "] finished loading with " + UTIL_ToString( GetNumHumanPlayers( ) ) + " players" ); + CONSOLE_Print( "[GAME: " + m_GameName + "] finished loading with " + QString::number( GetNumHumanPlayers( ) ) + " players" ); // send shortest, longest, and personal load times to each player CGamePlayer *Shortest = NULL; CGamePlayer *Longest = NULL; + m_LoadInGameTimer.stop(); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !Shortest || (*i)->GetFinishedLoadingTicks( ) < Shortest->GetFinishedLoadingTicks( ) ) Shortest = *i; @@ -3392,41 +3335,24 @@ void CBaseGame :: EventGameLoaded( ) if( Shortest && Longest ) { - SendAllChat( m_GHost->m_Language->ShortestLoadByPlayer( Shortest->GetName( ), UTIL_ToString( (float)( Shortest->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 2 ) ) ); - SendAllChat( m_GHost->m_Language->LongestLoadByPlayer( Longest->GetName( ), UTIL_ToString( (float)( Longest->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->ShortestLoadByPlayer( Shortest->GetName( ), QString::number( (float)( Shortest->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 'g', 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->LongestLoadByPlayer( Longest->GetName( ), QString::number( (float)( Longest->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 'g', 2 ) ) ); } - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - SendChat( *i, m_GHost->m_Language->YourLoadingTimeWas( UTIL_ToString( (float)( (*i)->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 2 ) ) ); + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + SendChat( *i, m_GHost->GetLanguage( )->YourLoadingTimeWas( QString::number( (float)( (*i)->GetFinishedLoadingTicks( ) - m_StartedLoadingTicks ) / 1000, 'g', 2 ) ) ); // read from gameloaded.txt if available - ifstream in; - in.open( m_GHost->m_GameLoadedFile.c_str( ) ); + QFile f(m_GHost->m_GameLoadedFile); - if( !in.fail( ) ) + if( f.open(QFile::ReadOnly) ) { // don't print more than 8 lines - uint32_t Count = 0; - string Line; - - while( !in.eof( ) && Count < 8 ) - { - getline( in, Line ); - - if( Line.empty( ) ) - { - if( !in.eof( ) ) - SendAllChat( " " ); - } - else - SendAllChat( Line ); - - Count++; - } - - in.close( ); + QStringList data = QString::fromUtf8(f.readAll()).replace('\r', "").split('\n'); + for (int i = 0; i < 8 && i < data.size(); i++) + SendAllChat(data.at(i)); } } @@ -3446,7 +3372,7 @@ unsigned char CBaseGame :: GetSIDFromPID( unsigned char PID ) CGamePlayer *CBaseGame :: GetPlayerFromPID( unsigned char PID ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && (*i)->GetPID( ) == PID ) return *i; @@ -3463,51 +3389,41 @@ CGamePlayer *CBaseGame :: GetPlayerFromSID( unsigned char SID ) return NULL; } -CGamePlayer *CBaseGame :: GetPlayerFromName( string name, bool sensitive ) +CGamePlayer *CBaseGame :: GetPlayerFromName( const QString &name, bool sensitive ) { - if( !sensitive ) - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) { - string TestName = (*i)->GetName( ); - - if( !sensitive ) - transform( TestName.begin( ), TestName.end( ), TestName.begin( ), (int(*)(int))tolower ); - - if( TestName == name ) - return *i; + if( name.compare( (*i)->GetName( ), sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive ) == 0 ) + return *i; } } return NULL; } -uint32_t CBaseGame :: GetPlayerFromNamePartial( string name, CGamePlayer **player ) +quint32 CBaseGame :: GetPlayerFromNamePartial( const QString &name, CGamePlayer **player ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t Matches = 0; + quint32 Matches = 0; *player = NULL; - // try to match each player with the passed string (e.g. "Varlock" would be matched with "lock") + // try to match each player with the passed QString (e.g. "Varlock" would be matched with "lock") - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) { - string TestName = (*i)->GetName( ); - transform( TestName.begin( ), TestName.end( ), TestName.begin( ), (int(*)(int))tolower ); + QString TestName = (*i)->GetName( ); - if( TestName.find( name ) != string :: npos ) + if( TestName.contains( name, Qt::CaseInsensitive ) ) { Matches++; *player = *i; // if the name matches exactly stop any further matching - if( TestName == name ) + if( TestName.compare( name, Qt::CaseInsensitive ) == 0 ) { Matches = 1; break; @@ -3541,7 +3457,7 @@ unsigned char CBaseGame :: GetNewPID( ) bool InUse = false; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && (*i)->GetPID( ) == TestPID ) { @@ -3585,11 +3501,11 @@ unsigned char CBaseGame :: GetNewColour( ) return 12; } -BYTEARRAY CBaseGame :: GetPIDs( ) +QByteArray CBaseGame :: GetPIDs( ) { - BYTEARRAY result; + QByteArray result; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) result.push_back( (*i)->GetPID( ) ); @@ -3598,11 +3514,11 @@ BYTEARRAY CBaseGame :: GetPIDs( ) return result; } -BYTEARRAY CBaseGame :: GetPIDs( unsigned char excludePID ) +QByteArray CBaseGame :: GetPIDs( unsigned char excludePID ) { - BYTEARRAY result; + QByteArray result; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && (*i)->GetPID( ) != excludePID ) result.push_back( (*i)->GetPID( ) ); @@ -3626,7 +3542,7 @@ unsigned char CBaseGame :: GetHostPID( ) // try to find the owner player next - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) && IsOwner( (*i)->GetName( ) ) ) return (*i)->GetPID( ); @@ -3634,7 +3550,7 @@ unsigned char CBaseGame :: GetHostPID( ) // okay then, just use the first available player - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetLeftMessageSent( ) ) return (*i)->GetPID( ); @@ -3653,7 +3569,7 @@ unsigned char CBaseGame :: GetEmptySlot( bool reserved ) // unfortunately we don't know which slot each player was assigned in the savegame // but we do know which slots were occupied and which weren't so let's at least force players to use previously occupied slots - vector SaveGameSlots = m_SaveGame->GetSlots( ); + QList SaveGameSlots = m_SaveGame->GetSlots( ); for( unsigned char i = 0; i < m_Slots.size( ); i++ ) { @@ -3740,7 +3656,7 @@ unsigned char CBaseGame :: GetEmptySlot( unsigned char team, unsigned char PID ) if( m_SaveGame ) { - vector SaveGameSlots = m_SaveGame->GetSlots( ); + QList SaveGameSlots = m_SaveGame->GetSlots( ); for( unsigned char i = StartSlot; i < m_Slots.size( ); i++ ) { @@ -3814,14 +3730,14 @@ void CBaseGame :: OpenSlot( unsigned char SID, bool kick ) if( Player ) { - Player->SetDeleteMe( true ); Player->SetLeftReason( "was kicked when opening a slot" ); Player->SetLeftCode( PLAYERLEAVE_LOBBY ); + Player->deleteLater(); } } CGameSlot Slot = m_Slots[SID]; - m_Slots[SID] = CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, Slot.GetTeam( ), Slot.GetColour( ), Slot.GetRace( ) ); + m_Slots[SID] = CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, Slot.GetTeam( ), Slot.GetColour( ), Slot.GetRace( ) ); SendAllSlotInfo( ); } } @@ -3836,14 +3752,14 @@ void CBaseGame :: CloseSlot( unsigned char SID, bool kick ) if( Player ) { - Player->SetDeleteMe( true ); Player->SetLeftReason( "was kicked when closing a slot" ); Player->SetLeftCode( PLAYERLEAVE_LOBBY ); + Player->deleteLater(); } } CGameSlot Slot = m_Slots[SID]; - m_Slots[SID] = CGameSlot( 0, 255, SLOTSTATUS_CLOSED, 0, Slot.GetTeam( ), Slot.GetColour( ), Slot.GetRace( ) ); + m_Slots[SID] = CGameSlot( 0, 255, SLOTSTATUS_CLOSED, 0, Slot.GetTeam( ), Slot.GetColour( ), Slot.GetRace( ) ); SendAllSlotInfo( ); } } @@ -3858,9 +3774,9 @@ void CBaseGame :: ComputerSlot( unsigned char SID, unsigned char skill, bool kic if( Player ) { - Player->SetDeleteMe( true ); Player->SetLeftReason( "was kicked when creating a computer in a slot" ); Player->SetLeftCode( PLAYERLEAVE_LOBBY ); + Player->deleteLater(); } } @@ -3913,7 +3829,7 @@ void CBaseGame :: OpenAllSlots( ) { bool Changed = false; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_CLOSED ) { @@ -3930,7 +3846,7 @@ void CBaseGame :: CloseAllSlots( ) { bool Changed = false; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OPEN ) { @@ -3949,9 +3865,9 @@ void CBaseGame :: ShuffleSlots( ) // that means we need to prevent this function from shuffling the open/closed/computer slots too // so we start by copying the player slots to a temporary vector - vector PlayerSlots; + QList PlayerSlots; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 && (*i).GetTeam( ) != 12 ) PlayerSlots.push_back( *i ); @@ -3966,7 +3882,7 @@ void CBaseGame :: ShuffleSlots( ) // unfortunately we can't just use PlayerSlots because the team/colour/race shouldn't be modified // so make a vector we can use - vector SIDs; + QList SIDs; for( unsigned char i = 0; i < PlayerSlots.size( ); i++ ) SIDs.push_back( i ); @@ -3975,7 +3891,7 @@ void CBaseGame :: ShuffleSlots( ) // now put the PlayerSlots vector in the same order as the SIDs vector - vector Slots; + QList Slots; // as usual don't modify the team/colour/race @@ -3994,10 +3910,10 @@ void CBaseGame :: ShuffleSlots( ) // now we put m_Slots back together again - vector :: iterator CurrentPlayer = PlayerSlots.begin( ); - vector Slots; + QList :: iterator CurrentPlayer = PlayerSlots.begin( ); + QList Slots; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 && (*i).GetTeam( ) != 12 ) { @@ -4015,7 +3931,7 @@ void CBaseGame :: ShuffleSlots( ) SendAllSlotInfo( ); } -vector CBaseGame :: BalanceSlotsRecursive( vector PlayerIDs, unsigned char *TeamSizes, double *PlayerScores, unsigned char StartTeam ) +QList CBaseGame :: BalanceSlotsRecursive( QList PlayerIDs, unsigned char *TeamSizes, double *PlayerScores, unsigned char StartTeam ) { // take a brute force approach to finding the best balance by iterating through every possible combination of players // 1.) since the number of teams is arbitrary this algorithm must be recursive @@ -4024,7 +3940,7 @@ vector CBaseGame :: BalanceSlotsRecursive( vector // 4.) for every possible combination, check the largest difference in total scores between any two actual teams // 5.) minimize this value by choosing the combination of players with the smallest difference - vector BestOrdering = PlayerIDs; + QList BestOrdering = PlayerIDs; double BestDifference = -1.0; for( unsigned char i = StartTeam; i < 12; i++ ) @@ -4043,17 +3959,18 @@ vector CBaseGame :: BalanceSlotsRecursive( vector // for example, it could contain one, two, or more actual teams worth of players // so recurse using the second "team" as the full set of players to perform the balancing on - vector BestSubOrdering = BalanceSlotsRecursive( vector( PlayerIDs.begin( ) + Mid, PlayerIDs.end( ) ), TeamSizes, PlayerScores, i + 1 ); + QList BestSubOrdering = BalanceSlotsRecursive( PlayerIDs.mid(Mid), TeamSizes, PlayerScores, i + 1 ); // BestSubOrdering now contains the best ordering of all the remaining players (the "right team") given this particular combination of players into two "teams" // in order to calculate the largest difference in total scores we need to recombine the subordering with the first team - vector TestOrdering = vector( PlayerIDs.begin( ), PlayerIDs.begin( ) + Mid ); - TestOrdering.insert( TestOrdering.end( ), BestSubOrdering.begin( ), BestSubOrdering.end( ) ); + QList TestOrdering = PlayerIDs.mid(0, Mid); + for (int k = 0; k < BestSubOrdering.size(); k++) + TestOrdering.push_back(BestSubOrdering.at(k)); // now calculate the team scores for all the teams that we know about (e.g. on subsequent recursion steps this will NOT be every possible team) - vector :: iterator CurrentPID = TestOrdering.begin( ); + QList :: iterator CurrentPID = TestOrdering.begin( ); double TeamScores[12]; for( unsigned char j = StartTeam; j < 12; j++ ) @@ -4113,12 +4030,12 @@ void CBaseGame :: BalanceSlots( ) // setup the necessary variables for the balancing algorithm // use an array of 13 elements for 12 players because GHost++ allocates PID's from 1-12 (i.e. excluding 0) and we use the PID to index the array - vector PlayerIDs; + QList PlayerIDs; unsigned char TeamSizes[12]; double PlayerScores[13]; memset( TeamSizes, 0, sizeof( unsigned char ) * 12 ); - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { unsigned char PID = (*i)->GetPID( ); @@ -4162,8 +4079,8 @@ void CBaseGame :: BalanceSlots( ) // 4 teams of 2 = 2520 ~ 30ms *** ok // 4 teams of 3 = 369600 ~ 3500ms *** unacceptable - uint32_t AlgorithmCost = 0; - uint32_t PlayersLeft = PlayerIDs.size( ); + quint32 AlgorithmCost = 0; + quint32 PlayersLeft = PlayerIDs.size( ); for( unsigned char i = 0; i < 12; i++ ) { @@ -4183,20 +4100,20 @@ void CBaseGame :: BalanceSlots( ) // the cost is too high, don't run the algorithm // a possible alternative: stop after enough iterations and/or time has passed - CONSOLE_Print( "[GAME: " + m_GameName + "] shuffling slots instead of balancing - the algorithm is too slow (with a cost of " + UTIL_ToString( AlgorithmCost ) + ") for this team configuration" ); - SendAllChat( m_GHost->m_Language->ShufflingPlayers( ) ); + CONSOLE_Print( "[GAME: " + m_GameName + "] shuffling slots instead of balancing - the algorithm is too slow (with a cost of " + QString::number( AlgorithmCost ) + ") for this team configuration" ); + SendAllChat( m_GHost->GetLanguage( )->ShufflingPlayers( ) ); ShuffleSlots( ); return; } - uint32_t StartTicks = GetTicks( ); - vector BestOrdering = BalanceSlotsRecursive( PlayerIDs, TeamSizes, PlayerScores, 0 ); - uint32_t EndTicks = GetTicks( ); + quint32 StartTicks = GetTicks( ); + QList BestOrdering = BalanceSlotsRecursive( PlayerIDs, TeamSizes, PlayerScores, 0 ); + quint32 EndTicks = GetTicks( ); // the BestOrdering assumes the teams are in slot order although this may not be the case // so put the players on the correct teams regardless of slot order - vector :: iterator CurrentPID = BestOrdering.begin( ); + QList :: iterator CurrentPID = BestOrdering.begin( ); for( unsigned char i = 0; i < 12; i++ ) { @@ -4222,7 +4139,7 @@ void CBaseGame :: BalanceSlots( ) else { CONSOLE_Print( "[GAME: " + m_GameName + "] shuffling slots instead of balancing - the balancing algorithm tried to do an invalid swap (this shouldn't happen)" ); - SendAllChat( m_GHost->m_Language->ShufflingPlayers( ) ); + SendAllChat( m_GHost->GetLanguage( )->ShufflingPlayers( ) ); ShuffleSlots( ); return; } @@ -4232,8 +4149,8 @@ void CBaseGame :: BalanceSlots( ) } } - CONSOLE_Print( "[GAME: " + m_GameName + "] balancing slots completed in " + UTIL_ToString( EndTicks - StartTicks ) + "ms (with a cost of " + UTIL_ToString( AlgorithmCost ) + ")" ); - SendAllChat( m_GHost->m_Language->BalancingSlotsCompleted( ) ); + CONSOLE_Print( "[GAME: " + m_GameName + "] balancing slots completed in " + QString::number( EndTicks - StartTicks ) + "ms (with a cost of " + QString::number( AlgorithmCost ) + ")" ); + SendAllChat( m_GHost->GetLanguage( )->BalancingSlotsCompleted( ) ); SendAllSlotInfo( ); for( unsigned char i = 0; i < 12; i++ ) @@ -4241,7 +4158,7 @@ void CBaseGame :: BalanceSlots( ) bool TeamHasPlayers = false; double TeamScore = 0.0; - for( vector :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) + for( QList :: iterator j = m_Players.begin( ); j != m_Players.end( ); j++ ) { unsigned char SID = GetSIDFromPID( (*j)->GetPID( ) ); @@ -4258,11 +4175,11 @@ void CBaseGame :: BalanceSlots( ) } if( TeamHasPlayers ) - SendAllChat( m_GHost->m_Language->TeamCombinedScore( UTIL_ToString( i + 1 ), UTIL_ToString( TeamScore, 2 ) ) ); + SendAllChat( m_GHost->GetLanguage( )->TeamCombinedScore( QString::number( i + 1 ), QString::number( TeamScore, 'g', 2 ) ) ); } } -void CBaseGame :: AddToSpoofed( string server, string name, bool sendMessage ) +void CBaseGame :: AddToSpoofed( const QString &server, const QString &name, bool sendMessage ) { CGamePlayer *Player = GetPlayerFromName( name, true ); @@ -4272,54 +4189,42 @@ void CBaseGame :: AddToSpoofed( string server, string name, bool sendMessage ) Player->SetSpoofed( true ); if( sendMessage ) - SendAllChat( m_GHost->m_Language->SpoofCheckAcceptedFor( server, name ) ); + SendAllChat( m_GHost->GetLanguage( )->SpoofCheckAcceptedFor( server, name ) ); } } -void CBaseGame :: AddToReserved( string name ) +void CBaseGame :: AddToReserved( const QString &name ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); + QString nameLower = name.toLower(); // check that the user is not already reserved - for( vector :: iterator i = m_Reserved.begin( ); i != m_Reserved.end( ); i++ ) - { - if( *i == name ) - return; - } + if ( m_Reserved.contains( nameLower ) ) + return; - m_Reserved.push_back( name ); + m_Reserved.push_back( nameLower ); // upgrade the user if they're already in the game - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - string NameLower = (*i)->GetName( ); - transform( NameLower.begin( ), NameLower.end( ), NameLower.begin( ), (int(*)(int))tolower ); - - if( NameLower == name ) + if( name.compare( (*i)->GetName( ), Qt::CaseInsensitive ) == 0 ) (*i)->SetReserved( true ); } } -bool CBaseGame :: IsOwner( string name ) +bool CBaseGame :: IsOwner( const QString &name ) { - string OwnerLower = m_OwnerName; - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - transform( OwnerLower.begin( ), OwnerLower.end( ), OwnerLower.begin( ), (int(*)(int))tolower ); - return name == OwnerLower; + QString OwnerLower = m_OwnerName.toLower(); + return name.toLower() == OwnerLower; } -bool CBaseGame :: IsReserved( string name ) +bool CBaseGame :: IsReserved( const QString &name ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - - for( vector :: iterator i = m_Reserved.begin( ); i != m_Reserved.end( ); i++ ) - { - if( *i == name ) - return true; + if( m_Reserved.contains( name, Qt::CaseInsensitive ) ) { + return true; } - + return false; } @@ -4327,7 +4232,7 @@ bool CBaseGame :: IsDownloading( ) { // returns true if at least one player is downloading the map - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetDownloadStarted( ) && !(*i)->GetDownloadFinished( ) ) return true; @@ -4353,23 +4258,24 @@ void CBaseGame :: StartCountDown( bool force ) if( force ) { m_CountDownStarted = true; + m_CountdownTimer.start(); m_CountDownCounter = 5; } else { - // check if the HCL command string is short enough + // check if the HCL command QString is short enough - if( m_HCLCommandString.size( ) > GetSlotsOccupied( ) ) + if( m_HCLCommandString.size( ) > (int)GetSlotsOccupied( ) ) { - SendAllChat( m_GHost->m_Language->TheHCLIsTooLongUseForceToStart( ) ); + SendAllChat( m_GHost->GetLanguage( )->TheHCLIsTooLongUseForceToStart( ) ); return; } // check if everyone has the map - string StillDownloading; + QString StillDownloading; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) { if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 && (*i).GetDownloadStatus( ) != 100 ) { @@ -4377,7 +4283,7 @@ void CBaseGame :: StartCountDown( bool force ) if( Player ) { - if( StillDownloading.empty( ) ) + if( StillDownloading.isEmpty( ) ) StillDownloading = Player->GetName( ); else StillDownloading += ", " + Player->GetName( ); @@ -4385,55 +4291,56 @@ void CBaseGame :: StartCountDown( bool force ) } } - if( !StillDownloading.empty( ) ) - SendAllChat( m_GHost->m_Language->PlayersStillDownloading( StillDownloading ) ); + if( !StillDownloading.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->PlayersStillDownloading( StillDownloading ) ); // check if everyone is spoof checked - string NotSpoofChecked; + QString NotSpoofChecked; if( m_GHost->m_RequireSpoofChecks ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetSpoofed( ) ) { - if( NotSpoofChecked.empty( ) ) + if( NotSpoofChecked.isEmpty( ) ) NotSpoofChecked = (*i)->GetName( ); else NotSpoofChecked += ", " + (*i)->GetName( ); } } - if( !NotSpoofChecked.empty( ) ) - SendAllChat( m_GHost->m_Language->PlayersNotYetSpoofChecked( NotSpoofChecked ) ); + if( !NotSpoofChecked.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->PlayersNotYetSpoofChecked( NotSpoofChecked ) ); } // check if everyone has been pinged enough (3 times) that the autokicker would have kicked them by now // see function EventPlayerPongToHost for the autokicker code - string NotPinged; + QString NotPinged; - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( !(*i)->GetReserved( ) && (*i)->GetNumPings( ) < 3 ) { - if( NotPinged.empty( ) ) + if( NotPinged.isEmpty( ) ) NotPinged = (*i)->GetName( ); else NotPinged += ", " + (*i)->GetName( ); } } - if( !NotPinged.empty( ) ) - SendAllChat( m_GHost->m_Language->PlayersNotYetPinged( NotPinged ) ); + if( !NotPinged.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->PlayersNotYetPinged( NotPinged ) ); // if no problems found start the game - if( StillDownloading.empty( ) && NotSpoofChecked.empty( ) && NotPinged.empty( ) ) + if( StillDownloading.isEmpty( ) && NotSpoofChecked.isEmpty( ) && NotPinged.isEmpty( ) ) { m_CountDownStarted = true; m_CountDownCounter = 5; + m_CountdownTimer.start(); } } } @@ -4441,119 +4348,126 @@ void CBaseGame :: StartCountDown( bool force ) void CBaseGame :: StartCountDownAuto( bool requireSpoofChecks ) { - if( !m_CountDownStarted ) - { - // check if enough players are present + if( m_CountDownStarted ) + return; - if( GetNumHumanPlayers( ) < m_AutoStartPlayers ) - { - SendAllChat( m_GHost->m_Language->WaitingForPlayersBeforeAutoStart( UTIL_ToString( m_AutoStartPlayers ), UTIL_ToString( m_AutoStartPlayers - GetNumHumanPlayers( ) ) ) ); - return; - } + // check if enough players are present + + if( GetNumHumanPlayers( ) < m_AutoStartPlayers ) + { + SendAllChat( m_GHost->GetLanguage( )->WaitingForPlayersBeforeAutoStart( QString::number( m_AutoStartPlayers ), QString::number( m_AutoStartPlayers - GetNumHumanPlayers( ) ) ) ); + return; + } - // check if everyone has the map + // check if everyone has the map - string StillDownloading; + QString StillDownloading; - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + { + if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 && (*i).GetDownloadStatus( ) != 100 ) { - if( (*i).GetSlotStatus( ) == SLOTSTATUS_OCCUPIED && (*i).GetComputer( ) == 0 && (*i).GetDownloadStatus( ) != 100 ) - { - CGamePlayer *Player = GetPlayerFromPID( (*i).GetPID( ) ); + CGamePlayer *Player = GetPlayerFromPID( (*i).GetPID( ) ); - if( Player ) - { - if( StillDownloading.empty( ) ) - StillDownloading = Player->GetName( ); - else - StillDownloading += ", " + Player->GetName( ); - } + if( Player ) + { + if( StillDownloading.isEmpty( ) ) + StillDownloading = Player->GetName( ); + else + StillDownloading += ", " + Player->GetName( ); } } + } - if( !StillDownloading.empty( ) ) - { - SendAllChat( m_GHost->m_Language->PlayersStillDownloading( StillDownloading ) ); - return; - } + if( !StillDownloading.isEmpty( ) ) + { + SendAllChat( m_GHost->GetLanguage( )->PlayersStillDownloading( StillDownloading ) ); + return; + } - // check if everyone is spoof checked + // check if everyone is spoof checked - string NotSpoofChecked; + QString NotSpoofChecked; - if( requireSpoofChecks ) + if( requireSpoofChecks ) + { + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + if( !(*i)->GetSpoofed( ) ) { - if( !(*i)->GetSpoofed( ) ) - { - if( NotSpoofChecked.empty( ) ) - NotSpoofChecked = (*i)->GetName( ); - else - NotSpoofChecked += ", " + (*i)->GetName( ); - } + if( NotSpoofChecked.isEmpty( ) ) + NotSpoofChecked = (*i)->GetName( ); + else + NotSpoofChecked += ", " + (*i)->GetName( ); } - - if( !NotSpoofChecked.empty( ) ) - SendAllChat( m_GHost->m_Language->PlayersNotYetSpoofChecked( NotSpoofChecked ) ); } - // check if everyone has been pinged enough (3 times) that the autokicker would have kicked them by now - // see function EventPlayerPongToHost for the autokicker code + if( !NotSpoofChecked.isEmpty( ) ) + SendAllChat( m_GHost->GetLanguage( )->PlayersNotYetSpoofChecked( NotSpoofChecked ) ); + } - string NotPinged; + // check if everyone has been pinged enough (3 times) that the autokicker would have kicked them by now + // see function EventPlayerPongToHost for the autokicker code - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) - { - if( !(*i)->GetReserved( ) && (*i)->GetNumPings( ) < 3 ) - { - if( NotPinged.empty( ) ) - NotPinged = (*i)->GetName( ); - else - NotPinged += ", " + (*i)->GetName( ); - } - } + QString NotPinged; - if( !NotPinged.empty( ) ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + { + if( !(*i)->GetReserved( ) && (*i)->GetNumPings( ) < 3 ) { - SendAllChat( m_GHost->m_Language->PlayersNotYetPingedAutoStart( NotPinged ) ); - return; + if( NotPinged.isEmpty( ) ) + NotPinged = (*i)->GetName( ); + else + NotPinged += ", " + (*i)->GetName( ); } + } + + if( !NotPinged.isEmpty( ) ) + { + SendAllChat( m_GHost->GetLanguage( )->PlayersNotYetPingedAutoStart( NotPinged ) ); + return; + } - // if no problems found start the game + // if no problems found start the game - if( StillDownloading.empty( ) && NotSpoofChecked.empty( ) && NotPinged.empty( ) ) - { - m_CountDownStarted = true; - m_CountDownCounter = 10; - } + if( StillDownloading.isEmpty( ) && NotSpoofChecked.isEmpty( ) && NotPinged.isEmpty( ) ) + { + m_CountDownStarted = true; + m_CountdownTimer.start(); + m_CountDownCounter = 10; } } -void CBaseGame :: StopPlayers( string reason ) +void CBaseGame :: StopPlayers( const QString &reason ) { - // disconnect every player and set their left reason to the passed string + // disconnect every player and set their left reason to the passed QString // we use this function when we want the code in the Update function to run before the destructor (e.g. saving players to the database) // therefore calling this function when m_GameLoading || m_GameLoaded is roughly equivalent to setting m_Exiting = true // the only difference is whether the code in the Update function is executed or not - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: iterator i = m_Players.begin( ); i != m_Players.end( ); ) { - (*i)->SetDeleteMe( true ); - (*i)->SetLeftReason( reason ); - (*i)->SetLeftCode( PLAYERLEAVE_LOST ); + CGamePlayer *p = *i; + i = m_Players.erase(i); + + p->SetLeftReason( reason ); + p->SetLeftCode( PLAYERLEAVE_LOST ); + p->deleteLater(); } } -void CBaseGame :: StopLaggers( string reason ) +void CBaseGame :: StopLaggers( const QString &reason ) { - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i)->GetLagging( ) ) { - (*i)->SetDeleteMe( true ); - (*i)->SetLeftReason( reason ); - (*i)->SetLeftCode( PLAYERLEAVE_DISCONNECT ); + CGamePlayer *p = *i; + i = m_Players.erase(i); + + p->SetLeftReason( reason ); + p->SetLeftCode( PLAYERLEAVE_LOST ); + p->deleteLater(); } } } @@ -4564,11 +4478,11 @@ void CBaseGame :: CreateVirtualHost( ) return; m_VirtualHostPID = GetNewPID( ); - BYTEARRAY IP; - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); + QByteArray IP; + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); SendAll( m_Protocol->SEND_W3GS_PLAYERINFO( m_VirtualHostPID, m_VirtualHostName, IP, IP ) ); } @@ -4594,11 +4508,11 @@ void CBaseGame :: CreateFakePlayer( ) DeleteVirtualHost( ); m_FakePlayerPID = GetNewPID( ); - BYTEARRAY IP; - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); - IP.push_back( 0 ); + QByteArray IP; + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); + IP.push_back( (char)0 ); SendAll( m_Protocol->SEND_W3GS_PLAYERINFO( m_FakePlayerPID, "FakePlayer", IP, IP ) ); m_Slots[SID] = CGameSlot( m_FakePlayerPID, 100, SLOTSTATUS_OCCUPIED, 0, m_Slots[SID].GetTeam( ), m_Slots[SID].GetColour( ), m_Slots[SID].GetRace( ) ); SendAllSlotInfo( ); @@ -4613,7 +4527,7 @@ void CBaseGame :: DeleteFakePlayer( ) for( unsigned char i = 0; i < m_Slots.size( ); i++ ) { if( m_Slots[i].GetPID( ) == m_FakePlayerPID ) - m_Slots[i] = CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, m_Slots[i].GetTeam( ), m_Slots[i].GetColour( ), m_Slots[i].GetRace( ) ); + m_Slots[i] = CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, m_Slots[i].GetTeam( ), m_Slots[i].GetColour( ), m_Slots[i].GetRace( ) ); } SendAll( m_Protocol->SEND_W3GS_PLAYERLEAVE_OTHERS( m_FakePlayerPID, PLAYERLEAVE_LOBBY ) ); diff --git a/src/libghost/game_base.h b/src/libghost/game_base.h new file mode 100644 index 0000000..617a3d3 --- /dev/null +++ b/src/libghost/game_base.h @@ -0,0 +1,304 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GAME_BASE_H +#define GAME_BASE_H + +#include "includes.h" +#include "gameslot.h" + +// +// CBaseGame +// + +class CTCPServer; +class CGameProtocol; +class CPotentialPlayer; +class CGamePlayer; +class CMap; +class CSaveGame; +class CReplay; +class CIncomingJoinPlayer; +class CIncomingAction; +class CIncomingChatPlayer; +class CIncomingMapSize; +class CCallableScoreCheck; +class CGHost; +QT_FORWARD_DECLARE_CLASS(QTcpServer) + +#include +#include +#include + +class CBaseGame : public QObject +{ + Q_OBJECT + +signals: + void startedLoading(); + void finishedLoading(); + void SignalPlayerCommand( CBaseGame *game, CGamePlayer *player, const QString &command, const QString &payload ); + +public: + CGHost *m_GHost; + +public slots: + virtual void EventGameStarted( ); + virtual void EventGameLoaded( ); + void EventNewConnection(); + void EventBroadcastTimeout(); + void EventRefreshTimeout(); + void EventRefreshError(); + void EventTryAutoRehost(); + void EventMapDataTimeout(); + void EventCountdownTimeout(); + void EventAutostartTimeout(); + void EventGameOverTimeout(); + void EventVotekickTimeout(); + virtual void EventCallableUpdateTimeout(); + void EventResetDownloadCounter(); + void EventAnnounceTimeout(); + void EventLobbyTimeout(); + void EventPlayerStoppedLagging(); + void CheckPlayersStartedLaggging(); + void EventLoadInGameTimeout(); + void EventResetLagscreenTimeout(); + void EventDropLaggerTimeout(); + void EventPlayerLaggedOut(CGamePlayer *player); + void EventSendActions(); + virtual void SendAllSlotInfo(); + virtual void EventPlayerLoaded(); + virtual void EventPlayerDeleted(); + +protected: + QTimer m_BroadcastTimer, m_RefreshTimer, m_MapDataTimer, m_CountdownTimer, m_AutostartTimer, m_GameOverTimer, m_VotekickTimer, + m_SlotInfoTimer, m_DownloadCounterTimer, m_CallableUpdateTimer, m_AnnounceTimer, m_LobbyTimeoutTimer, + m_DropLaggerTimer, m_LoadInGameTimer, m_ResetLagscreenTimer, m_SendActionTimer; + + void CheckGameLoaded(); + +protected: + QTcpServer *m_Socket; // listening socket + CGameProtocol *m_Protocol; // game protocol + QList m_Slots; // vector of slots + QList m_Potentials; // vector of potential players (connections that haven't sent a W3GS_REQJOIN packet yet) + QList m_Players; // vector of players + QList m_ScoreChecks; + QQueue m_Actions; // queue of actions to be sent + QStringList m_Reserved; // vector of player names with reserved slots (from the !hold command) + QSet m_IgnoredNames; // set of player names to NOT print ban messages for when joining because they've already been printed + QSet m_IPBlackList; // set of IP addresses to blacklist from joining (todotodo: convert to uint32's for efficiency) + QList m_EnforceSlots; // vector of slots to force players to use (used with saved games) + QList m_EnforcePlayers; // vector of pids to force players to use (used with saved games) + CMap *m_Map; // map data + CSaveGame *m_SaveGame; // savegame data (this is a pointer to global data) + CReplay *m_Replay; // replay + bool m_Saving; // if we're currently saving game data to the database + quint16 m_HostPort; // the port to host games on + unsigned char m_GameState; // game state, public or private + unsigned char m_VirtualHostPID; // virtual host's PID + unsigned char m_FakePlayerPID; // the fake player's PID (if present) + unsigned char m_GProxyEmptyActions; + QString m_GameName; // game name + QString m_LastGameName; // last game name (the previous game name before it was rehosted) + QString m_VirtualHostName; // virtual host's name + QString m_OwnerName; // name of the player who owns this game (should be considered an admin) + QString m_CreatorName; // name of the player who created this game + QString m_CreatorServer; // battle.net server the player who created this game was on + QString m_AnnounceMessage; // a message to be sent every m_AnnounceInterval seconds + QString m_StatString; // the stat QString when the game started (used when saving replays) + QString m_KickVotePlayer; // the player to be kicked with the currently running kick vote + QString m_HCLCommandString; // the "HostBot Command Library" command QString, used to pass a limited amount of data to specially designed maps + quint32 m_WaitTime; + quint32 m_RandomSeed; // the random seed sent to the Warcraft III clients + quint32 m_HostCounter; // a unique game number + quint32 m_Latency; // the number of ms to wait between sending action packets (we queue any received during this time) + quint32 m_RequestedLatency; + quint32 m_SyncLimit; // the maximum number of packets a player can fall out of sync before starting the lag screen + quint32 m_SyncCounter; // the number of actions sent so far (for determining if anyone is lagging) + quint32 m_GameTicks; // ingame ticks + quint32 m_CreationTime; // GetTime when the game was created + quint32 m_LastDownloadTicks; // GetTicks when the last map download cycle was performed + quint32 m_DownloadCounter; // # of map bytes downloaded in the last second + quint32 m_AutoStartPlayers; // auto start the game when there are this many players or more + quint32 m_CountDownCounter; // the countdown is finished when this reaches zero + quint32 m_StartedLoadingTicks; // GetTicks when the game started loading + quint32 m_StartPlayers; // number of players when the game started + quint32 m_LastActionSentTicks; // GetTicks when the last action packet was sent + quint32 m_StartedLaggingTime; // GetTime when the last lag screen started + quint32 m_LastPlayerLeaveTicks; // GetTicks when the most recent player left the game + static quint32 m_GlobalHostCounter; // the current host counter (a unique number to identify a game, incremented each time a game is created) + double m_MinimumScore; // the minimum allowed score for matchmaking mode + double m_MaximumScore; // the maximum allowed score for matchmaking mode + bool m_Locked; // if the game owner is the only one allowed to run game commands or not + bool m_RefreshMessages; // if we should display "game refreshed..." messages or not + bool m_RefreshError; // if there was an error refreshing the game + bool m_RefreshRehosted; // if we just rehosted and are waiting for confirmation that it was successful + bool m_MuteAll; // if we should stop forwarding ingame chat messages targeted for all players or not + bool m_MuteLobby; // if we should stop forwarding lobby chat messages + bool m_CountDownStarted; // if the game start countdown has started or not + bool m_GameLoading; // if the game is currently loading or not + bool m_GameLoaded; // if the game has loaded or not + bool m_LoadInGame; // if the load-in-game feature is enabled or not + bool m_Lagging; // if the lag screen is active or not + bool m_AutoSave; // if we should auto save the game before someone disconnects + bool m_MatchMaking; // if matchmaking mode is enabled + bool m_LocalAdminMessages; // if local admin messages should be relayed or not + + quint32 GetNewHostCounter( ) { return m_GlobalHostCounter++; } + +public: + CBaseGame( CGHost *nGHost, CMap *nMap, CSaveGame *nSaveGame, quint16 nHostPort, unsigned char nGameState, QString nGameName, QString nOwnerName, QString nCreatorName, QString nCreatorServer ); + virtual ~CBaseGame( ); + + static quint32 GetCurrentHostCounter( ) { return m_GlobalHostCounter; } + + + virtual const QList &GetEnforceSlots( ) { return m_EnforceSlots; } + virtual const QList &GetEnforcePlayers( ) { return m_EnforcePlayers; } + virtual CSaveGame *GetSaveGame( ) const { return m_SaveGame; } + virtual quint16 GetHostPort( ) const { return m_HostPort; } + virtual unsigned char GetGameState( ) const { return m_GameState; } + virtual unsigned char GetGProxyEmptyActions( ) const { return m_GProxyEmptyActions; } + virtual const QString &GetGameName( ) const { return m_GameName; } + virtual const QString &GetLastGameName( ) const { return m_LastGameName; } + virtual const QString &GetVirtualHostName( ) const { return m_VirtualHostName; } + virtual const QString &GetOwnerName( ) const { return m_OwnerName; } + virtual const QString &GetCreatorName( ) const { return m_CreatorName; } + virtual const QString &GetCreatorServer( ) const { return m_CreatorServer; } + virtual quint32 GetHostCounter( ) const { return m_HostCounter; } + virtual quint32 GetStartedLaggingTime( ) const { return m_StartedLaggingTime; } + virtual quint32 GetAutoStartPlayers( ) const { return m_AutoStartPlayers; } + virtual bool GetLocked( ) const { return m_Locked; } + virtual bool GetRefreshMessages( ) const { return m_RefreshMessages; } + virtual bool GetCountDownStarted( ) const { return m_CountDownStarted; } + virtual bool GetGameLoading( ) const { return m_GameLoading; } + virtual bool GetGameLoaded( ) const { return m_GameLoaded; } + virtual bool GetLagging( ) const { return m_Lagging; } + + virtual void SetEnforceSlots( QList nEnforceSlots ) { m_EnforceSlots = nEnforceSlots; } + virtual void SetEnforcePlayers( QList nEnforcePlayers ) { m_EnforcePlayers = nEnforcePlayers; } + virtual void SetAutoStartPlayers( quint32 nAutoStartPlayers ) { m_AutoStartPlayers = nAutoStartPlayers; } + virtual void SetMinimumScore( double nMinimumScore ) { m_MinimumScore = nMinimumScore; } + virtual void SetMaximumScore( double nMaximumScore ) { m_MaximumScore = nMaximumScore; } + virtual void SetMatchMaking( bool nMatchMaking ) { m_MatchMaking = nMatchMaking; } + + virtual quint32 GetSlotsOccupied( ) const; + virtual quint32 GetSlotsOpen( ) const; + virtual quint32 GetNumPlayers( ) const; + virtual quint32 GetNumHumanPlayers( ) const; + virtual QString GetDescription( ) const; + quint32 GetSyncCounter() { return m_SyncCounter; } + quint32 GetSyncLimit() { return m_SyncLimit; } + + virtual void SetAnnounce( quint32 interval, const QString &message ); + + // generic functions to send packets to players + + virtual void Send( CGamePlayer *player, const QByteArray &data ); + virtual void Send( unsigned char PID, const QByteArray &data ); + virtual void Send( const QByteArray &PIDs, const QByteArray &data ); + virtual void SendAll( const QByteArray &data ); + + // functions to send packets to players + + virtual void SendChat( unsigned char fromPID, CGamePlayer *player, const QString &message ); + virtual void SendChat( unsigned char fromPID, unsigned char toPID, const QString &message ); + virtual void SendChat( CGamePlayer *player, const QString &message ); + virtual void SendChat( unsigned char toPID, const QString &message ); + virtual void SendAllChat( unsigned char fromPID, const QString &message ); + virtual void SendAllChat( const QString &message ); + virtual void SendLocalAdminChat( const QString &message ); + virtual void SendVirtualHostPlayerInfo( CGamePlayer *player ); + virtual void SendFakePlayerInfo( CGamePlayer *player ); + virtual void SendAllActions( ); + virtual void SendWelcomeMessage( CGamePlayer *player ); + virtual void SendEndMessage( ); + + // events + // note: these are only called while iterating through the m_Potentials or m_Players vectors + // therefore you can't modify those vectors and must use the player's m_DeleteMe member to flag for deletion + + virtual void EventPlayerDisconnectTimedOut( CGamePlayer *player ); + virtual void EventPlayerDisconnectPlayerError( CGamePlayer *player ); + virtual void EventPlayerDisconnectSocketError( CGamePlayer *player ); + virtual void EventPlayerDisconnectConnectionClosed( CGamePlayer *player ); + virtual void EventPlayerJoined( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer ); + virtual void EventPlayerJoinedWithScore( CPotentialPlayer *potential, CIncomingJoinPlayer *joinPlayer, double score ); + virtual void EventPlayerLeft( CGamePlayer *player, quint32 reason ); + virtual void EventPlayerAction( CGamePlayer *player, CIncomingAction *action ); + virtual void EventPlayerKeepAlive( CGamePlayer *player, quint32 checkSum ); + virtual void EventPlayerChatToHost( CGamePlayer *player, CIncomingChatPlayer *chatPlayer ); + virtual bool EventPlayerBotCommand( CGamePlayer *player, const QString &command, const QString &payload ); + virtual void EventPlayerChangeTeam( CGamePlayer *player, unsigned char team ); + virtual void EventPlayerChangeColour( CGamePlayer *player, unsigned char colour ); + virtual void EventPlayerChangeRace( CGamePlayer *player, unsigned char race ); + virtual void EventPlayerChangeHandicap( CGamePlayer *player, unsigned char handicap ); + virtual void EventPlayerDropRequest( CGamePlayer *player ); + virtual void EventPlayerMapSize( CGamePlayer *player, CIncomingMapSize *mapSize ); + virtual void EventPlayerPongToHost( CGamePlayer *player, quint32 pong ); + + // these events are called outside of any iterations + + virtual void EventGameRefreshed( const QString &server ); + + // other functions + + virtual unsigned char GetSIDFromPID( unsigned char PID ); + virtual CGamePlayer *GetPlayerFromPID( unsigned char PID ); + virtual CGamePlayer *GetPlayerFromSID( unsigned char SID ); + virtual CGamePlayer *GetPlayerFromName( const QString &name, bool sensitive ); + virtual quint32 GetPlayerFromNamePartial( const QString &name, CGamePlayer **player ); + virtual CGamePlayer *GetPlayerFromColour( unsigned char colour ); + virtual unsigned char GetNewPID( ); + virtual unsigned char GetNewColour( ); + virtual QByteArray GetPIDs( ); + virtual QByteArray GetPIDs( unsigned char excludePID ); + virtual unsigned char GetHostPID( ); + virtual unsigned char GetEmptySlot( bool reserved ); + virtual unsigned char GetEmptySlot( unsigned char team, unsigned char PID ); + virtual void SwapSlots( unsigned char SID1, unsigned char SID2 ); + virtual void OpenSlot( unsigned char SID, bool kick ); + virtual void CloseSlot( unsigned char SID, bool kick ); + virtual void ComputerSlot( unsigned char SID, unsigned char skill, bool kick ); + virtual void ColourSlot( unsigned char SID, unsigned char colour ); + virtual void OpenAllSlots( ); + virtual void CloseAllSlots( ); + virtual void ShuffleSlots( ); + virtual QList BalanceSlotsRecursive( QList PlayerIDs, unsigned char *TeamSizes, double *PlayerScores, unsigned char StartTeam ); + virtual void BalanceSlots( ); + virtual void AddToSpoofed( const QString &server, const QString &name, bool sendMessage ); + virtual void AddToReserved( const QString &name ); + virtual bool IsOwner( const QString &name ); + virtual bool IsReserved( const QString &name ); + virtual bool IsDownloading( ); + virtual bool IsGameDataSaved( ); + virtual void SaveGameData( ); + virtual void StartCountDown( bool force ); + virtual void StartCountDownAuto( bool requireSpoofChecks ); + virtual void StopPlayers( const QString &reason ); + virtual void StopLaggers( const QString &reason ); + virtual void CreateVirtualHost( ); + virtual void DeleteVirtualHost( ); + virtual void CreateFakePlayer( ); + virtual void DeleteFakePlayer( ); +}; + +#endif diff --git a/ghost/gameplayer.cpp b/src/libghost/gameplayer.cpp similarity index 55% rename from ghost/gameplayer.cpp rename to src/libghost/gameplayer.cpp index 0a78367..6c1b01f 100644 --- a/ghost/gameplayer.cpp +++ b/src/libghost/gameplayer.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -21,7 +21,6 @@ #include "ghost.h" #include "util.h" #include "language.h" -#include "socket.h" #include "commandpacket.h" #include "bnet.h" #include "map.h" @@ -34,124 +33,203 @@ // CPotentialPlayer // -CPotentialPlayer :: CPotentialPlayer( CGameProtocol *nProtocol, CBaseGame *nGame, CTCPSocket *nSocket ) +#include +#include +#include + +CPotentialPlayer :: CPotentialPlayer( CGameProtocol *nProtocol, CBaseGame *nGame, QAbstractSocket *nSocket ) + : QObject(NULL) { m_Protocol = nProtocol; m_Game = nGame; m_Socket = nSocket; - m_DeleteMe = false; + m_Socket->setParent(this); + m_Error = false; m_IncomingJoinPlayer = NULL; + + QObject::connect(nSocket, SIGNAL(readyRead()), this, SLOT(EventDataReady())); + QObject::connect(nSocket, SIGNAL(disconnected()), this, SLOT(EventConnectionClosed())); + QObject::connect(nSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(EventConnectionError(QAbstractSocket::SocketError))); } -CPotentialPlayer :: ~CPotentialPlayer( ) +void CPotentialPlayer::deleteLater() { - if( m_Socket ) - delete m_Socket; + emit aboutToDelete(); + QObject::deleteLater(); +} - while( !m_Packets.empty( ) ) - { - delete m_Packets.front( ); - m_Packets.pop( ); - } +CPotentialPlayer :: ~CPotentialPlayer( ) +{ + while( !m_Packets.isEmpty( ) ) + delete m_Packets.dequeue( ); delete m_IncomingJoinPlayer; + m_IncomingJoinPlayer = NULL; } -BYTEARRAY CPotentialPlayer :: GetExternalIP( ) +void CPotentialPlayer::EventDataReady() { - unsigned char Zeros[] = { 0, 0, 0, 0 }; + m_TimeoutTimer.start(); - if( m_Socket ) - return m_Socket->GetIP( ); + ExtractPackets( ); + ProcessPackets( ); +} - return UTIL_CreateByteArray( Zeros, 4 ); +void CPotentialPlayer::EventConnectionError(QAbstractSocket::SocketError /*error*/) +{ + DEBUG_Print("CPotentialPlayer::EventConnectionError()"); + deleteLater(); } -string CPotentialPlayer :: GetExternalIPString( ) +void CPotentialPlayer::EventConnectionClosed() { - if( m_Socket ) - return m_Socket->GetIPString( ); + DEBUG_Print("CPotentialPlayer::EventConnectionClosed()"); + deleteLater(); +} - return string( ); +void CGamePlayer::EventPingTimeout() +{ + Send(m_Protocol->SEND_W3GS_PING_FROM_HOST( ) ); } -bool CPotentialPlayer :: Update( void *fd ) +void CGamePlayer::EventACKTimeout() { - if( m_DeleteMe ) - return true; + DEBUG_Print("EventACKTimeout()"); + // GProxy++ acks - if( !m_Socket ) - return false; + Send( m_Game->m_GHost->GetGPSProtocol().SEND_GPSS_ACK( m_TotalPacketsReceived ) ); +} - m_Socket->DoRecv( (fd_set *)fd ); - ExtractPackets( ); - ProcessPackets( ); +void CGamePlayer::EventWhoisTimeout() +{ + // wait 4 seconds after joining before sending the /whois or /w + // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results + + if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.isEmpty( ) ) + { + // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking + + for( QList :: const_iterator i = m_Game->m_GHost->m_BNETs.begin( ); i != m_Game->m_GHost->m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == m_JoinedRealm ) + { + if( m_Game->GetGameState( ) == GAME_PUBLIC ) + { + if( (*i)->GetPasswordHashType( ) == "pvpgn" ) + (*i)->QueueChatCommand( "/whereis " + m_Name ); + else + (*i)->QueueChatCommand( "/whois " + m_Name ); + } + else if( m_Game->GetGameState( ) == GAME_PRIVATE ) + (*i)->QueueChatCommand( m_Game->m_GHost->GetLanguage( )->SpoofCheckByReplying( ), m_Name, true ); + } + } - // don't call DoSend here because some other players may not have updated yet and may generate a packet for this player - // also m_Socket may have been set to NULL during ProcessPackets but we're banking on the fact that m_DeleteMe has been set to true as well so it'll short circuit before dereferencing + m_WhoisSent = true; + } - return m_DeleteMe || m_Error || m_Socket->HasError( ) || !m_Socket->GetConnected( ); } -void CPotentialPlayer :: ExtractPackets( ) +void CGamePlayer::EventConnectionError(QAbstractSocket::SocketError /*error*/) { - if( !m_Socket ) + m_Game->EventPlayerDisconnectSocketError( this ); + deleteLater(); +} + +void CGamePlayer::EventConnectionTimeout() +{ + // check for socket timeouts + // if we don't receive anything from a player for 30 seconds we can assume they've dropped + // this works because in the lobby we send pings every 5 seconds and expect a response to each one + // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) + m_Game->EventPlayerDisconnectTimedOut( this ); + deleteLater(); +} + +void CGamePlayer::EventConnectionClosed() +{ + if (m_Socket->error() != QAbstractSocket::UnknownSocketError) + { + DEBUG_Print("Error is " + QString::number((int)m_Socket->error())); return; + } - // extract as many packets as possible from the socket's receive buffer and put them in the m_Packets queue + m_Game->EventPlayerDisconnectConnectionClosed( this ); + deleteLater(); +} - string *RecvBuffer = m_Socket->GetBytes( ); - BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); +QByteArray CPotentialPlayer :: GetExternalIP( ) const +{ + if( m_Socket ) + return Util::fromUInt32(m_Socket->peerAddress().toIPv4Address()); + + unsigned char Zeros[] = { 0, 0, 0, 0 }; + return QByteArray( (char*)Zeros, 4 ); +} + +QString CPotentialPlayer :: GetExternalIPString( ) const +{ + if( m_Socket ) + return m_Socket->peerAddress().toString(); + + return QString( ); +} + +void CPotentialPlayer :: ExtractPackets( ) +{ + if( !m_Socket || !m_Socket->isValid() ) + return; + // extract as many packets as possible from the socket's receive buffer and put them in the m_Packets queue // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes - while( Bytes.size( ) >= 4 ) + while( m_Socket->bytesAvailable() >= 4 ) { - if( Bytes[0] == W3GS_HEADER_CONSTANT || Bytes[0] == GPS_HEADER_CONSTANT ) + unsigned char header = m_Socket->peek(1).at(0); + if (header != W3GS_HEADER_CONSTANT && header != GPS_HEADER_CONSTANT ) { - // bytes 2 and 3 contain the length of the packet + m_Error = true; + m_ErrorString = "received invalid packet from player (bad header constant)"; + m_Socket->abort(); + m_Socket->deleteLater(); + m_Socket = NULL; + return; + } - uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); + // bytes 2 and 3 contain the length of the packet - if( Length >= 4 ) - { - if( Bytes.size( ) >= Length ) - { - m_Packets.push( new CCommandPacket( Bytes[0], Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); - *RecvBuffer = RecvBuffer->substr( Length ); - Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); - } - else - return; - } - else - { - m_Error = true; - m_ErrorString = "received invalid packet from player (bad length)"; - return; - } - } - else + quint16 Length = Util::extractUInt16( m_Socket->peek(4), 2 ); + + if( Length < 4 ) { m_Error = true; - m_ErrorString = "received invalid packet from player (bad header constant)"; + m_ErrorString = "received invalid packet from player (bad length)"; + m_Socket->abort(); + m_Socket->deleteLater(); + m_Socket = NULL; return; } + + if( m_Socket->bytesAvailable() < Length ) + return; + + QByteArray Bytes = m_Socket->read(Length); + m_Packets.enqueue( new CCommandPacket( header, Bytes.at(1), Bytes ) ); } } void CPotentialPlayer :: ProcessPackets( ) { - if( !m_Socket ) + if( !m_Socket || !m_Socket->isValid()) return; // process all the received packets in the m_Packets queue - while( !m_Packets.empty( ) ) + while( !m_Packets.isEmpty( ) ) { CCommandPacket *Packet = m_Packets.front( ); - m_Packets.pop( ); + m_Packets.dequeue( ); if( Packet->GetPacketType( ) == W3GS_HEADER_CONSTANT ) { @@ -179,17 +257,18 @@ void CPotentialPlayer :: ProcessPackets( ) } } -void CPotentialPlayer :: Send( BYTEARRAY data ) +void CPotentialPlayer :: Send( const QByteArray &data ) { - if( m_Socket ) - m_Socket->PutBytes( data ); + if( m_Socket && m_Socket->isValid() ) + m_Socket->write(data); } // // CGamePlayer // - -CGamePlayer :: CGamePlayer( CGameProtocol *nProtocol, CBaseGame *nGame, CTCPSocket *nSocket, unsigned char nPID, string nJoinedRealm, string nName, BYTEARRAY nInternalIP, bool nReserved ) : CPotentialPlayer( nProtocol, nGame, nSocket ) +#include +CGamePlayer :: CGamePlayer( CGameProtocol *nProtocol, CBaseGame *nGame, QAbstractSocket *nSocket, unsigned char nPID, QString nJoinedRealm, QString nName, QByteArray nInternalIP, bool nReserved ) + : CPotentialPlayer( nProtocol, nGame, nSocket ) { m_PID = nPID; m_Name = nName; @@ -231,11 +310,18 @@ CGamePlayer :: CGamePlayer( CGameProtocol *nProtocol, CBaseGame *nGame, CTCPSock m_LastGProxyAckTime = 0; } -CGamePlayer :: CGamePlayer( CPotentialPlayer *potential, unsigned char nPID, string nJoinedRealm, string nName, BYTEARRAY nInternalIP, bool nReserved ) : CPotentialPlayer( potential->m_Protocol, potential->m_Game, potential->GetSocket( ) ) +CGamePlayer :: CGamePlayer( CPotentialPlayer *potential, unsigned char nPID, QString nJoinedRealm, QString nName, QByteArray nInternalIP, bool nReserved ) + : CPotentialPlayer( potential->m_Protocol, potential->m_Game, potential->GetSocket( ) ) { // todotodo: properly copy queued packets to the new player, this just discards them // this isn't a big problem because official Warcraft III clients don't send any packets after the join request until they receive a response + QAbstractSocket *s = potential->GetSocket(); + + s->disconnect(potential, SLOT(EventConnectionClosed())); + s->disconnect(potential, SLOT(EventConnectionError(QAbstractSocket::SocketError))); + s->disconnect(potential, SLOT(EventDataReady())); + // m_Packets = potential->GetPackets( ); m_PID = nPID; m_Name = nName; @@ -281,39 +367,92 @@ CGamePlayer :: CGamePlayer( CPotentialPlayer *potential, unsigned char nPID, str m_GProxyDisconnectNoticeSent = false; m_GProxyReconnectKey = GetTicks( ); m_LastGProxyAckTime = 0; + init(); +} + +void CGamePlayer::EventSpoofCheckTimeout() +{ + // kick players who don't spoof check within 20 seconds when spoof checks are required and the game is autohosted + + if (GetSpoofed()) + return; + + if (m_Game->GetCountDownStarted() || !m_Game->m_GHost->m_RequireSpoofChecks || + m_Game->GetGameState() != GAME_PUBLIC || !m_Game->m_GHost->m_AutoHostGameName.isEmpty() || + m_Game->m_GHost->m_AutoHostMaximumGames == 0 || m_Game->m_GHost->m_AutoHostAutoStartPlayers == 0 || + m_Game->GetAutoStartPlayers() == 0) + return; + + deleteLater(); + SetLeftReason( m_Game->m_GHost->GetLanguage( )->WasKickedForNotSpoofChecking( ) ); + SetLeftCode( PLAYERLEAVE_LOBBY ); + m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); +} + +void CGamePlayer::init() +{ + QObject::connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(EventConnectionTimeout())); + QObject::connect(&m_ACKTimer, SIGNAL(timeout()), this, SLOT(EventACKTimeout())); + QObject::connect(&m_PingTimer, SIGNAL(timeout()), this, SLOT(EventPingTimeout())); + QTimer::singleShot(4000, this, SLOT(EventWhoisTimeout())); + + QObject::connect(this, SIGNAL(finishedLoading()), m_Game, SLOT(EventPlayerLoaded())); + QObject::connect(this, SIGNAL(aboutToDelete()), m_Game, SLOT(EventPlayerDeleted())); + QObject::connect(this, SIGNAL(stoppedLagging()), m_Game, SLOT(EventPlayerStoppedLagging())); + m_SendGProxyMessageTimer.setInterval(20000); + QObject::connect(&m_SendGProxyMessageTimer, SIGNAL(timeout()), this, SLOT(EventSendGProxyMessage())); + + QTimer::singleShot(20000, this, SLOT(EventSpoofCheckTimeout())); + + if (m_GProxy) + m_ACKTimer.start(10000); + + m_PingTimer.start(5000); + m_TimeoutTimer.start(30000); + m_TimeoutTimer.setSingleShot(true); } CGamePlayer :: ~CGamePlayer( ) { + emit stoppedLagging(); +} + +void CGamePlayer::EventSendGProxyMessage() +{ + quint32 TimeRemaining = ( m_Game->GetGProxyEmptyActions() + 1 ) * 60 - ( GetTime( ) - m_Game->GetStartedLaggingTime() ); + + if( TimeRemaining > ( (quint32)m_Game->GetGProxyEmptyActions() + 1 ) * 60 ) + TimeRemaining = ( m_Game->GetGProxyEmptyActions() + 1 ) * 60; + m_Game->SendAllChat( GetPID( ), m_Game->m_GHost->GetLanguage( )->WaitForReconnectSecondsRemain( QString::number( TimeRemaining ) ) ); + SetLastGProxyWaitNoticeSentTime( GetTime( ) ); } -string CGamePlayer :: GetNameTerminated( ) +QString CGamePlayer :: GetNameTerminated( ) { // if the player's name contains an unterminated colour code add the colour terminator to the end of their name // this is useful because it allows you to print the player's name in a longer message which doesn't colour all the subsequent text - string LowerName = m_Name; - transform( LowerName.begin( ), LowerName.end( ), LowerName.begin( ), (int(*)(int))tolower ); - string :: size_type Start = LowerName.find( "|c" ); - string :: size_type End = LowerName.find( "|r" ); + QString LowerName = m_Name.toLower(); + int Start = LowerName.indexOf( "|c" ); + int End = LowerName.indexOf( "|r" ); - if( Start != string :: npos && ( End == string :: npos || End < Start ) ) + if( Start != -1 && ( End == -1 || End < Start ) ) return m_Name + "|r"; else return m_Name; } -uint32_t CGamePlayer :: GetPing( bool LCPing ) +quint32 CGamePlayer :: GetPing( bool LCPing ) { // just average all the pings in the vector, nothing fancy - if( m_Pings.empty( ) ) + if( m_Pings.isEmpty( ) ) return 0; - uint32_t AvgPing = 0; + quint32 AvgPing = 0; - for( unsigned int i = 0; i < m_Pings.size( ); i++ ) + for( int i = 0; i < m_Pings.size( ); i++ ) AvgPing += m_Pings[i]; AvgPing /= m_Pings.size( ); @@ -324,149 +463,78 @@ uint32_t CGamePlayer :: GetPing( bool LCPing ) return AvgPing; } -bool CGamePlayer :: Update( void *fd ) -{ - // wait 4 seconds after joining before sending the /whois or /w - // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results - - if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.empty( ) && GetTime( ) - m_JoinTime >= 4 ) - { - // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking - - for( vector :: iterator i = m_Game->m_GHost->m_BNETs.begin( ); i != m_Game->m_GHost->m_BNETs.end( ); i++ ) - { - if( (*i)->GetServer( ) == m_JoinedRealm ) - { - if( m_Game->GetGameState( ) == GAME_PUBLIC ) - { - if( (*i)->GetPasswordHashType( ) == "pvpgn" ) - (*i)->QueueChatCommand( "/whereis " + m_Name ); - else - (*i)->QueueChatCommand( "/whois " + m_Name ); - } - else if( m_Game->GetGameState( ) == GAME_PRIVATE ) - (*i)->QueueChatCommand( m_Game->m_GHost->m_Language->SpoofCheckByReplying( ), m_Name, true ); - } - } - - m_WhoisSent = true; - } - - // check for socket timeouts - // if we don't receive anything from a player for 30 seconds we can assume they've dropped - // this works because in the lobby we send pings every 5 seconds and expect a response to each one - // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) - - if( m_Socket && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) - m_Game->EventPlayerDisconnectTimedOut( this ); - - // GProxy++ acks - - if( m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) - { - if( m_Socket ) - m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); - - m_LastGProxyAckTime = GetTime( ); - } - - // base class update - - CPotentialPlayer :: Update( fd ); - bool Deleting; - - if( m_GProxy && m_Game->GetGameLoaded( ) ) - Deleting = m_DeleteMe || m_Error; - else - Deleting = m_DeleteMe || m_Error || m_Socket->HasError( ) || !m_Socket->GetConnected( ); - - // try to find out why we're requesting deletion - // in cases other than the ones covered here m_LeftReason should have been set when m_DeleteMe was set - - if( m_Error ) - m_Game->EventPlayerDisconnectPlayerError( this ); - - if( m_Socket ) - { - if( m_Socket->HasError( ) ) - m_Game->EventPlayerDisconnectSocketError( this ); - - if( !m_Socket->GetConnected( ) ) - m_Game->EventPlayerDisconnectConnectionClosed( this ); - } - - return Deleting; -} - void CGamePlayer :: ExtractPackets( ) { - if( !m_Socket ) + if( !m_Socket || !m_Socket->isValid() ) return; // extract as many packets as possible from the socket's receive buffer and put them in the m_Packets queue - - string *RecvBuffer = m_Socket->GetBytes( ); - BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) ); - // a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes - while( Bytes.size( ) >= 4 ) + while( m_Socket->bytesAvailable() >= 4 ) { - if( Bytes[0] == W3GS_HEADER_CONSTANT || Bytes[0] == GPS_HEADER_CONSTANT ) + unsigned char header = m_Socket->peek(1).at(0); + if (header != W3GS_HEADER_CONSTANT && header != GPS_HEADER_CONSTANT ) { - // bytes 2 and 3 contain the length of the packet - - uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 ); + m_Error = true; + m_ErrorString = "received invalid packet from player (bad header constant)"; + m_Game->EventPlayerDisconnectPlayerError( this ); + m_Socket->abort(); + m_Socket->deleteLater(); + m_Socket = NULL; + deleteLater(); + return; + } - if( Length >= 4 ) - { - if( Bytes.size( ) >= Length ) - { - m_Packets.push( new CCommandPacket( Bytes[0], Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) ); + // bytes 2 and 3 contain the length of the packet - if( Bytes[0] == W3GS_HEADER_CONSTANT ) - m_TotalPacketsReceived++; + quint16 Length = Util::extractUInt16( m_Socket->peek(4), 2 ); - *RecvBuffer = RecvBuffer->substr( Length ); - Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); - } - else - return; - } - else - { - m_Error = true; - m_ErrorString = "received invalid packet from player (bad length)"; - return; - } - } - else + if( Length < 4 ) { m_Error = true; - m_ErrorString = "received invalid packet from player (bad header constant)"; + m_ErrorString = "received invalid packet from player (bad length)"; + m_Socket->abort(); + m_Socket->deleteLater(); + m_Socket = NULL; return; } + + if( m_Socket->bytesAvailable() < Length ) + return; + + QByteArray Bytes = m_Socket->read(Length); + m_Packets.enqueue( new CCommandPacket( header, Bytes.at(1), Bytes ) ); + + if( header == W3GS_HEADER_CONSTANT ) + m_TotalPacketsReceived++; } } void CGamePlayer :: ProcessPackets( ) { - if( !m_Socket ) + if( !m_Socket || !m_Socket->isValid() ) return; CIncomingAction *Action = NULL; CIncomingChatPlayer *ChatPlayer = NULL; CIncomingMapSize *MapSize = NULL; - bool HasMap = false; - uint32_t CheckSum = 0; - uint32_t Pong = 0; + quint32 CheckSum = 0; + quint32 Pong = 0; + + if( m_Lagging && m_Game->GetSyncCounter() - m_SyncCounter < m_Game->GetSyncLimit() / 2 ) + { + // stop the lag screen for this player + m_Lagging = false; + emit stoppedLagging(); + } // process all the received packets in the m_Packets queue - while( !m_Packets.empty( ) ) + while( !m_Packets.isEmpty( ) ) { CCommandPacket *Packet = m_Packets.front( ); - m_Packets.pop( ); + m_Packets.dequeue( ); if( Packet->GetPacketType( ) == W3GS_HEADER_CONSTANT ) { @@ -483,7 +551,7 @@ void CGamePlayer :: ProcessPackets( ) { m_FinishedLoading = true; m_FinishedLoadingTicks = GetTicks( ); - m_Game->EventPlayerLoaded( this ); + emit finishedLoading(); } else { @@ -505,7 +573,7 @@ void CGamePlayer :: ProcessPackets( ) case CGameProtocol :: W3GS_OUTGOING_KEEPALIVE: CheckSum = m_Protocol->RECEIVE_W3GS_OUTGOING_KEEPALIVE( Packet->GetData( ) ); - m_CheckSums.push( CheckSum ); + m_CheckSums.enqueue( CheckSum ); m_SyncCounter++; m_Game->EventPlayerKeepAlive( this, CheckSum ); break; @@ -532,7 +600,7 @@ void CGamePlayer :: ProcessPackets( ) break; case CGameProtocol :: W3GS_MAPSIZE: - MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( Packet->GetData( ), m_Game->m_GHost->m_Map->GetMapSize( ) ); + MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( Packet->GetData( ), m_Game->m_GHost->GetCurrentMap( )->GetMapSize( ) ); if( MapSize ) m_Game->EventPlayerMapSize( this, MapSize ); @@ -572,14 +640,14 @@ void CGamePlayer :: ProcessPackets( ) } else if( Packet->GetPacketType( ) == GPS_HEADER_CONSTANT ) { - BYTEARRAY Data = Packet->GetData( ); + QByteArray Data = Packet->GetData( ); if( Packet->GetID( ) == CGPSProtocol :: GPS_INIT ) { if( m_Game->m_GHost->m_Reconnect ) { m_GProxy = true; - m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_INIT( m_Game->m_GHost->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) ); + m_Socket->write( m_Game->m_GHost->GetGPSProtocol().SEND_GPSS_INIT( m_Game->m_GHost->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) ); CONSOLE_Print( "[GAME: " + m_Game->GetGameName( ) + "] player [" + m_Name + "] is using GProxy++" ); } else @@ -595,19 +663,19 @@ void CGamePlayer :: ProcessPackets( ) } else if( Packet->GetID( ) == CGPSProtocol :: GPS_ACK && Data.size( ) == 8 ) { - uint32_t LastPacket = UTIL_ByteArrayToUInt32( Data, false, 4 ); - uint32_t PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); + int LastPacket = Util::extractUInt32( Data, 4 ); + int PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); if( LastPacket > PacketsAlreadyUnqueued ) { - uint32_t PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; + int PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; if( PacketsToUnqueue > m_GProxyBuffer.size( ) ) PacketsToUnqueue = m_GProxyBuffer.size( ); while( PacketsToUnqueue > 0 ) { - m_GProxyBuffer.pop( ); + m_GProxyBuffer.dequeue( ); PacketsToUnqueue--; } } @@ -618,54 +686,61 @@ void CGamePlayer :: ProcessPackets( ) } } -void CGamePlayer :: Send( BYTEARRAY data ) +void CGamePlayer :: Send( const QByteArray &data ) { // must start counting packet total from beginning of connection // but we can avoid buffering packets until we know the client is using GProxy++ since that'll be determined before the game starts // this prevents us from buffering packets for non-GProxy++ clients + //if (data.toHex() != "f70c06006400") + // DEBUG_Print("Sending " + data.toHex()); m_TotalPacketsSent++; if( m_GProxy && m_Game->GetGameLoaded( ) ) - m_GProxyBuffer.push( data ); + m_GProxyBuffer.enqueue( data ); CPotentialPlayer :: Send( data ); } -void CGamePlayer :: EventGProxyReconnect( CTCPSocket *NewSocket, uint32_t LastPacket ) +void CGamePlayer :: EventGProxyReconnect( QAbstractSocket *NewSocket, quint32 LastPacket ) { - delete m_Socket; + m_Socket->deleteLater(); m_Socket = NewSocket; - m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_RECONNECT( m_TotalPacketsReceived ) ); - uint32_t PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); + QObject::connect(m_Socket, SIGNAL(readyRead()), this, SLOT(EventDataReady())); + QObject::connect(m_Socket, SIGNAL(disconnected()), this, SLOT(EventConnectionClosed())); + QObject::connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(EventConnectionError(QAbstractSocket::SocketError))); + + m_Socket->write( m_Game->m_GHost->GetGPSProtocol().SEND_GPSS_RECONNECT( m_TotalPacketsReceived ) ); + + quint32 PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); if( LastPacket > PacketsAlreadyUnqueued ) { - uint32_t PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; + int PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; if( PacketsToUnqueue > m_GProxyBuffer.size( ) ) PacketsToUnqueue = m_GProxyBuffer.size( ); while( PacketsToUnqueue > 0 ) { - m_GProxyBuffer.pop( ); + m_GProxyBuffer.dequeue( ); PacketsToUnqueue--; } } // send remaining packets from buffer, preserve buffer - queue TempBuffer; + QQueue TempBuffer; - while( !m_GProxyBuffer.empty( ) ) + while( !m_GProxyBuffer.isEmpty( ) ) { - m_Socket->PutBytes( m_GProxyBuffer.front( ) ); - TempBuffer.push( m_GProxyBuffer.front( ) ); - m_GProxyBuffer.pop( ); + m_Socket->write( m_GProxyBuffer.front( ) ); + TempBuffer.enqueue( m_GProxyBuffer.front( ) ); + m_GProxyBuffer.dequeue( ); } m_GProxyBuffer = TempBuffer; m_GProxyDisconnectNoticeSent = false; - m_Game->SendAllChat( m_Game->m_GHost->m_Language->PlayerReconnectedWithGProxy( m_Name ) ); + m_Game->SendAllChat( m_Game->m_GHost->GetLanguage( )->PlayerReconnectedWithGProxy( m_Name ) ); } diff --git a/src/libghost/gameplayer.h b/src/libghost/gameplayer.h new file mode 100644 index 0000000..5b5479c --- /dev/null +++ b/src/libghost/gameplayer.h @@ -0,0 +1,255 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GAMEPLAYER_H +#define GAMEPLAYER_H + +class CCommandPacket; +class CGameProtocol; +class CGame; +class CIncomingJoinPlayer; + +#include "includes.h" +class CBaseGame; +// +// CPotentialPlayer +// + +#include +#include + +class CPotentialPlayer + : public QObject +{ + Q_OBJECT + +signals: + void aboutToDelete(); + +public slots: + void EventDataReady(); + virtual void EventConnectionError(QAbstractSocket::SocketError); + virtual void EventConnectionClosed(); + virtual void deleteLater(); + +public: + CGameProtocol *m_Protocol; + CBaseGame *m_Game; + QTimer m_TimeoutTimer, m_SendGProxyMessageTimer; + +protected: + // note: we permit m_Socket to be NULL in this class to allow for the virtual host player which doesn't really exist + // it also allows us to convert CPotentialPlayers to CGamePlayers without the CPotentialPlayer's destructor closing the socket + + QAbstractSocket *m_Socket; + QQueue m_Packets; + bool m_Error; + QString m_ErrorString; + CIncomingJoinPlayer *m_IncomingJoinPlayer; + +public: + CPotentialPlayer( CGameProtocol *nProtocol, CBaseGame *nGame, QAbstractSocket *nSocket ); + virtual ~CPotentialPlayer( ); + + virtual QAbstractSocket *GetSocket( ) const { return m_Socket; } + virtual QByteArray GetExternalIP( ) const; + virtual QString GetExternalIPString( ) const; + virtual const QQueue &GetPackets( ) const { return m_Packets; } + virtual bool GetError( ) const { return m_Error; } + virtual const QString &GetErrorString( ) const { return m_ErrorString; } + virtual CIncomingJoinPlayer *GetJoinPlayer( ) const { return m_IncomingJoinPlayer; } + + virtual void SetSocket( QAbstractSocket *nSocket ) { m_Socket = nSocket; } + + // processing functions + + virtual void ExtractPackets( ); + virtual void ProcessPackets( ); + + // other functions + + virtual void Send( const QByteArray &data ); +}; + + +// +// CGamePlayer +// +class CGamePlayer : public CPotentialPlayer +{ + Q_OBJECT + +public slots: + virtual void EventConnectionError(QAbstractSocket::SocketError); + virtual void EventConnectionClosed(); + void EventConnectionTimeout(); + void EventWhoisTimeout(); + void EventACKTimeout(); + void EventPingTimeout(); + void EventSendGProxyMessage(); + void EventSpoofCheckTimeout(); + +signals: + void finishedLoading(); + void stoppedLagging(); + +private: + QTimer m_ACKTimer; + QTimer m_PingTimer; + void init(); + +private: + unsigned char m_PID; + QString m_Name; // the player's name + QByteArray m_InternalIP; // the player's internal IP address as reported by the player when connecting + QList m_Pings; // store the last few (20) pings received so we can take an average + QQueue m_CheckSums; // the last few checksums the player has sent (for detecting desyncs) + QString m_LeftReason; // the reason the player left the game + QString m_SpoofedRealm; // the realm the player last spoof checked on + QString m_JoinedRealm; // the realm the player joined on (probable, can be spoofed) + quint32 m_TotalPacketsSent; + quint32 m_TotalPacketsReceived; + quint32 m_LeftCode; // the code to be sent in W3GS_PLAYERLEAVE_OTHERS for why this player left the game + quint32 m_LoginAttempts; // the number of attempts to login (used with CAdminGame only) + quint32 m_SyncCounter; // the number of keepalive packets received from this player + quint32 m_JoinTime; // GetTime when the player joined the game (used to delay sending the /whois a few seconds to allow for some lag) + quint32 m_LastMapPartSent; // the last mappart sent to the player (for sending more than one part at a time) + quint32 m_LastMapPartAcked; // the last mappart acknowledged by the player + quint32 m_StartedDownloadingTicks; // GetTicks when the player started downloading the map + quint32 m_FinishedDownloadingTime; // GetTime when the player finished downloading the map + quint32 m_FinishedLoadingTicks; // GetTicks when the player finished loading the game + quint32 m_StartedLaggingTicks; // GetTicks when the player started lagging + quint32 m_StatsSentTime; // GetTime when we sent this player's stats to the chat (to prevent players from spamming !stats) + quint32 m_StatsDotASentTime; // GetTime when we sent this player's dota stats to the chat (to prevent players from spamming !statsdota) + quint32 m_LastGProxyWaitNoticeSentTime; + QQueue m_LoadInGameData; // queued data to be sent when the player finishes loading when using "load in game" + double m_Score; // the player's generic "score" for the matchmaking algorithm + bool m_LoggedIn; // if the player has logged in or not (used with CAdminGame only) + bool m_Spoofed; // if the player has spoof checked or not + bool m_Reserved; // if the player is reserved (VIP) or not + bool m_WhoisShouldBeSent; // if a battle.net /whois should be sent for this player or not + bool m_WhoisSent; // if we've sent a battle.net /whois for this player yet (for spoof checking) + bool m_DownloadAllowed; // if we're allowed to download the map or not (used with permission based map downloads) + bool m_DownloadStarted; // if we've started downloading the map or not + bool m_DownloadFinished; // if we've finished downloading the map or not + bool m_FinishedLoading; // if the player has finished loading or not + bool m_Lagging; // if the player is lagging or not (on the lag screen) + bool m_DropVote; // if the player voted to drop the laggers or not (on the lag screen) + bool m_KickVote; // if the player voted to kick a player or not + bool m_Muted; // if the player is muted or not + bool m_LeftMessageSent; // if the playerleave message has been sent or not + bool m_GProxy; // if the player is using GProxy++ + bool m_GProxyDisconnectNoticeSent; // if a disconnection notice has been sent or not when using GProxy++ + QQueue m_GProxyBuffer; + quint32 m_GProxyReconnectKey; + quint32 m_LastGProxyAckTime; + +public: + CGamePlayer( CGameProtocol *nProtocol, CBaseGame *nGame, QAbstractSocket *nSocket, unsigned char nPID, QString nJoinedRealm, QString nName, QByteArray nInternalIP, bool nReserved ); + CGamePlayer( CPotentialPlayer *potential, unsigned char nPID, QString nJoinedRealm, QString nName, QByteArray nInternalIP, bool nReserved ); + virtual ~CGamePlayer( ); + + unsigned char GetPID( ) { return m_PID; } + QString GetName( ) { return m_Name; } + QByteArray GetInternalIP( ) { return m_InternalIP; } + unsigned int GetNumPings( ) { return m_Pings.size( ); } + unsigned int GetNumCheckSums( ) { return m_CheckSums.size( ); } + QQueue *GetCheckSums( ) { return &m_CheckSums; } + QString GetLeftReason( ) { return m_LeftReason; } + QString GetSpoofedRealm( ) { return m_SpoofedRealm; } + QString GetJoinedRealm( ) { return m_JoinedRealm; } + quint32 GetLeftCode( ) { return m_LeftCode; } + quint32 GetLoginAttempts( ) { return m_LoginAttempts; } + quint32 GetSyncCounter( ) { return m_SyncCounter; } + quint32 GetJoinTime( ) { return m_JoinTime; } + quint32 GetLastMapPartSent( ) { return m_LastMapPartSent; } + quint32 GetLastMapPartAcked( ) { return m_LastMapPartAcked; } + quint32 GetStartedDownloadingTicks( ) { return m_StartedDownloadingTicks; } + quint32 GetFinishedDownloadingTime( ) { return m_FinishedDownloadingTime; } + quint32 GetFinishedLoadingTicks( ) { return m_FinishedLoadingTicks; } + quint32 GetStartedLaggingTicks( ) { return m_StartedLaggingTicks; } + quint32 GetStatsSentTime( ) { return m_StatsSentTime; } + quint32 GetStatsDotASentTime( ) { return m_StatsDotASentTime; } + quint32 GetLastGProxyWaitNoticeSentTime( ) { return m_LastGProxyWaitNoticeSentTime; } + QQueue *GetLoadInGameData( ) { return &m_LoadInGameData; } + double GetScore( ) { return m_Score; } + bool GetLoggedIn( ) { return m_LoggedIn; } + bool GetSpoofed( ) { return m_Spoofed; } + bool GetReserved( ) { return m_Reserved; } + bool GetWhoisShouldBeSent( ) { return m_WhoisShouldBeSent; } + bool GetWhoisSent( ) { return m_WhoisSent; } + bool GetDownloadAllowed( ) { return m_DownloadAllowed; } + bool GetDownloadStarted( ) { return m_DownloadStarted; } + bool GetDownloadFinished( ) { return m_DownloadFinished; } + bool GetFinishedLoading( ) { return m_FinishedLoading; } + bool GetLagging( ) { return m_Lagging; } + bool GetDropVote( ) { return m_DropVote; } + bool GetKickVote( ) { return m_KickVote; } + bool GetMuted( ) { return m_Muted; } + bool GetLeftMessageSent( ) { return m_LeftMessageSent; } + bool GetGProxy( ) { return m_GProxy; } + bool GetGProxyDisconnectNoticeSent( ) { return m_GProxyDisconnectNoticeSent; } + quint32 GetGProxyReconnectKey( ) { return m_GProxyReconnectKey; } + + void SetLeftReason( QString nLeftReason ) { m_LeftReason = nLeftReason; } + void SetSpoofedRealm( QString nSpoofedRealm ) { m_SpoofedRealm = nSpoofedRealm; } + void SetLeftCode( quint32 nLeftCode ) { m_LeftCode = nLeftCode; } + void SetLoginAttempts( quint32 nLoginAttempts ) { m_LoginAttempts = nLoginAttempts; } + void SetSyncCounter( quint32 nSyncCounter ) { m_SyncCounter = nSyncCounter; } + void SetLastMapPartSent( quint32 nLastMapPartSent ) { m_LastMapPartSent = nLastMapPartSent; } + void SetLastMapPartAcked( quint32 nLastMapPartAcked ) { m_LastMapPartAcked = nLastMapPartAcked; } + void SetStartedDownloadingTicks( quint32 nStartedDownloadingTicks ) { m_StartedDownloadingTicks = nStartedDownloadingTicks; } + void SetFinishedDownloadingTime( quint32 nFinishedDownloadingTime ) { m_FinishedDownloadingTime = nFinishedDownloadingTime; } + void SetStartedLaggingTicks( quint32 nStartedLaggingTicks ) { m_StartedLaggingTicks = nStartedLaggingTicks; } + void SetStatsSentTime( quint32 nStatsSentTime ) { m_StatsSentTime = nStatsSentTime; } + void SetStatsDotASentTime( quint32 nStatsDotASentTime ) { m_StatsDotASentTime = nStatsDotASentTime; } + void SetLastGProxyWaitNoticeSentTime( quint32 nLastGProxyWaitNoticeSentTime ) { m_LastGProxyWaitNoticeSentTime = nLastGProxyWaitNoticeSentTime; } + void SetScore( double nScore ) { m_Score = nScore; } + void SetLoggedIn( bool nLoggedIn ) { m_LoggedIn = nLoggedIn; } + void SetSpoofed( bool nSpoofed ) { m_Spoofed = nSpoofed; } + void SetReserved( bool nReserved ) { m_Reserved = nReserved; } + void SetWhoisShouldBeSent( bool nWhoisShouldBeSent ) { m_WhoisShouldBeSent = nWhoisShouldBeSent; } + void SetDownloadAllowed( bool nDownloadAllowed ) { m_DownloadAllowed = nDownloadAllowed; } + void SetDownloadStarted( bool nDownloadStarted ) { m_DownloadStarted = nDownloadStarted; } + void SetDownloadFinished( bool nDownloadFinished ) { m_DownloadFinished = nDownloadFinished; } + void SetLagging( bool nLagging ) { m_Lagging = nLagging; } + void SetDropVote( bool nDropVote ) { m_DropVote = nDropVote; } + void SetKickVote( bool nKickVote ) { m_KickVote = nKickVote; } + void SetMuted( bool nMuted ) { m_Muted = nMuted; } + void SetLeftMessageSent( bool nLeftMessageSent ) { m_LeftMessageSent = nLeftMessageSent; } + void SetGProxyDisconnectNoticeSent( bool nGProxyDisconnectNoticeSent ) { m_GProxyDisconnectNoticeSent = nGProxyDisconnectNoticeSent; } + + QString GetNameTerminated( ); + quint32 GetPing( bool LCPing ); + + void AddLoadInGameData( const QByteArray &nLoadInGameData ) { m_LoadInGameData.enqueue( nLoadInGameData ); } + + // processing functions + + virtual void ExtractPackets( ); + virtual void ProcessPackets( ); + + // other functions + + virtual void Send( const QByteArray &data ); + virtual void EventGProxyReconnect( QAbstractSocket *NewSocket, quint32 LastPacket ); +}; + +#endif diff --git a/src/libghost/gameprotocol.cpp b/src/libghost/gameprotocol.cpp new file mode 100644 index 0000000..8c9a18c --- /dev/null +++ b/src/libghost/gameprotocol.cpp @@ -0,0 +1,1063 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "crc32.h" +#include "gameplayer.h" +#include "gameprotocol.h" +#include "game_base.h" + +#include +// +// CGameProtocol +// + +CGameProtocol :: CGameProtocol( CGHost *nGHost ) +{ + m_GHost = nGHost; +} + +CGameProtocol :: ~CGameProtocol( ) +{ + +} + +/////////////////////// +// RECEIVE FUNCTIONS // +/////////////////////// + +CIncomingJoinPlayer *CGameProtocol :: RECEIVE_W3GS_REQJOIN( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_REQJOIN" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Host Counter (Game ID) + // 4 bytes -> Entry Key (used in LAN) + // 1 byte -> ??? + // 2 bytes -> Listen Port + // 4 bytes -> Peer Key + // null terminated QString -> Name + // 4 bytes -> ??? + // 2 bytes -> InternalPort (???) + // 4 bytes -> InternalIP + + if( ValidateLength( data ) && data.size( ) >= 20 ) + { + quint32 HostCounter = Util::extractUInt32( data, 4 ); + QByteArray Name = UTIL_ExtractCString( data, 19 ); + + if( !Name.isEmpty( ) && data.size( ) >= Name.size( ) + 30 ) + { + QByteArray InternalIP = data.mid(Name.size() + 26, 4); + return new CIncomingJoinPlayer( HostCounter, Name, InternalIP ); + } + } + + return NULL; +} + +quint32 CGameProtocol :: RECEIVE_W3GS_LEAVEGAME( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_LEAVEGAME" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Reason + + if( ValidateLength( data ) && data.size( ) >= 8 ) + return Util::extractUInt32( data, 4 ); + + return 0; +} + +bool CGameProtocol :: RECEIVE_W3GS_GAMELOADED_SELF( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_GAMELOADED_SELF" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + + if( ValidateLength( data ) ) + return true; + + return false; +} + +CIncomingAction *CGameProtocol :: RECEIVE_W3GS_OUTGOING_ACTION( const QByteArray & data, unsigned char PID ) +{ + // DEBUG_Print( "RECEIVED W3GS_OUTGOING_ACTION" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> CRC + // remainder of packet -> Action + + if( PID != 255 && ValidateLength( data ) && data.size( ) >= 8 ) + { + QByteArray CRC = data.mid(4, 4); + QByteArray Action = data.mid(8); + return new CIncomingAction( PID, CRC, Action ); + } + + return NULL; +} + +quint32 CGameProtocol :: RECEIVE_W3GS_OUTGOING_KEEPALIVE( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_OUTGOING_KEEPALIVE" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 1 byte -> ??? + // 4 bytes -> CheckSum??? (used in replays) + + if( ValidateLength( data ) && data.size( ) == 9 ) + return Util::extractUInt32(data, 5); + + return 0; +} + +CIncomingChatPlayer *CGameProtocol :: RECEIVE_W3GS_CHAT_TO_HOST( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_CHAT_TO_HOST" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 1 byte -> Total + // for( 1 .. Total ) + // 1 byte -> ToPID + // 1 byte -> FromPID + // 1 byte -> Flag + // if( Flag == 16 ) + // null term QString -> Message + // elseif( Flag == 17 ) + // 1 byte -> Team + // elseif( Flag == 18 ) + // 1 byte -> Colour + // elseif( Flag == 19 ) + // 1 byte -> Race + // elseif( Flag == 20 ) + // 1 byte -> Handicap + // elseif( Flag == 32 ) + // 4 bytes -> ExtraFlags + // null term QString -> Message + + if( ValidateLength( data ) ) + { + unsigned int i = 5; + unsigned char Total = data[4]; + + if( Total > 0 && (unsigned int)data.size( ) >= i + Total ) + { + QByteArray ToPIDs = data.mid(i, Total ); + i += Total; + unsigned char FromPID = data[i]; + unsigned char Flag = data[i + 1]; + i += 2; + + if( Flag == 16 && (unsigned int)data.size( ) >= i + 1 ) + { + // chat message + + QByteArray Message = UTIL_ExtractCString( data, i ); + return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, QString::fromUtf8(Message) ); + } + else if( ( Flag >= 17 && Flag <= 20 ) && (unsigned int)data.size( ) >= i + 1 ) + { + // team/colour/race/handicap change request + + unsigned char Byte = data[i]; + return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, Byte ); + } + else if( Flag == 32 && (unsigned int)data.size( ) >= i + 5 ) + { + // chat message with extra flags + + QByteArray ExtraFlags = data.mid(i, 4); + QByteArray Message = UTIL_ExtractCString( data, i + 4 ); + return new CIncomingChatPlayer( FromPID, ToPIDs, Flag, QString::fromUtf8(Message), ExtraFlags ); + } + } + } + + return NULL; +} + +bool CGameProtocol :: RECEIVE_W3GS_SEARCHGAME( const QByteArray & data, unsigned char war3Version ) +{ + quint32 ProductID = 1462982736; // "W3XP" + quint32 Version = war3Version; + + // DEBUG_Print( "RECEIVED W3GS_SEARCHGAME" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> ProductID + // 4 bytes -> Version + // 4 bytes -> ??? (Zero) + + if( ValidateLength( data ) && data.size( ) >= 16 ) + { + if( Util::extractUInt32(data, 4) == ProductID ) + { + if( Util::extractUInt32(data, 8) == Version ) + { + if( Util::extractUInt32(data, 12) == 0 ) + return true; + } + } + } + + return false; +} + +CIncomingMapSize *CGameProtocol :: RECEIVE_W3GS_MAPSIZE( const QByteArray & data, const QByteArray & /*mapSize*/ ) +{ + // DEBUG_Print( "RECEIVED W3GS_MAPSIZE" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> ??? + // 1 byte -> SizeFlag (1 = have map, 3 = continue download) + // 4 bytes -> MapSize + + if( ValidateLength( data ) && data.size( ) >= 13 ) + return new CIncomingMapSize( data[8], Util::extractUInt32(data, 9) ); + + return NULL; +} + +quint32 CGameProtocol :: RECEIVE_W3GS_MAPPARTOK( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_MAPPARTOK" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 1 byte -> SenderPID + // 1 byte -> ReceiverPID + // 4 bytes -> ??? + // 4 bytes -> MapSize + + if( ValidateLength( data ) && data.size( ) >= 14 ) + return Util::extractUInt32(data, 10); + + return 0; +} + +quint32 CGameProtocol :: RECEIVE_W3GS_PONG_TO_HOST( const QByteArray & data ) +{ + // DEBUG_Print( "RECEIVED W3GS_PONG_TO_HOST" ); + // DEBUG_Print( data ); + + // 2 bytes -> Header + // 2 bytes -> Length + // 4 bytes -> Pong + + // the pong value is just a copy of whatever was sent in SEND_W3GS_PING_FROM_HOST which was GetTicks( ) at the time of sending + // so as long as we trust that the client isn't trying to fake us out and mess with the pong value we can find the round trip time by simple subtraction + // (the subtraction is done elsewhere because the very first pong value seems to be 1 and we want to discard that one) + + if( ValidateLength( data ) && data.size( ) >= 8 ) + return Util::extractUInt32(data, 4); + + return 1; +} + +//////////////////// +// SEND FUNCTIONS // +//////////////////// + +QByteArray CGameProtocol :: SEND_W3GS_PING_FROM_HOST( ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_PING_FROM_HOST ); // W3GS_PING_FROM_HOST + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt32(GetTicks( ))); // ping value + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_PING_FROM_HOST" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_SLOTINFOJOIN( unsigned char PID, const QByteArray &port, const QByteArray &externalIP, QList &lslots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) +{ + char Zeros[] = { 0, 0, 0, 0 }; + + QByteArray SlotInfo = EncodeSlotInfo( lslots, randomSeed, layoutStyle, playerSlots ); + QByteArray packet; + + if( port.size( ) == 2 && externalIP.size( ) == 4 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_SLOTINFOJOIN ); // W3GS_SLOTINFOJOIN + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt16(SlotInfo.size( ))); // SlotInfo length + packet.append(SlotInfo); // SlotInfo + packet.push_back( PID ); // PID + packet.push_back( 2 ); // AF_INET + packet.push_back( (char)0 ); // AF_INET continued... + packet.append(port); // port + packet.append(externalIP); // external IP + packet.append(QByteArray(Zeros, 4 )); // ??? + packet.append(QByteArray(Zeros, 4 )); // ??? + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_SLOTINFOJOIN (" + + QString::number(port.size()) + ": " + port.toHex() + ", " + + QString::number(externalIP.size()) + ": " + externalIP.toHex() + ")"); + + // DEBUG_Print( "SENT W3GS_SLOTINFOJOIN" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_REJECTJOIN( quint32 reason ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_REJECTJOIN ); // W3GS_REJECTJOIN + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt32(reason)); // reason + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_REJECTJOIN" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_PLAYERINFO( unsigned char PID, const QString & name, const QByteArray & externalIP, const QByteArray & internalIP ) +{ + char PlayerJoinCounter[] = { 2, 0, 0, 0 }; + char Zeros[] = { 0, 0, 0, 0 }; + + QByteArray packet; + + if( !name.isEmpty( ) && name.size( ) <= 15 && externalIP.size( ) == 4 && internalIP.size( ) == 4 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_PLAYERINFO ); // W3GS_PLAYERINFO + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append( QByteArray(PlayerJoinCounter, 4) ); // player join counter + packet.push_back( PID ); // PID + packet.append(name); // player name + packet.push_back( (char)0 ); // 0 term + packet.push_back( 1 ); // ??? + packet.push_back( (char)0 ); // ??? + packet.push_back( 2 ); // AF_INET + packet.push_back( (char)0 ); // AF_INET continued... + packet.push_back( (char)0 ); // port + packet.push_back( (char)0 ); // port continued... + packet.append(externalIP); // external IP + packet.append( QByteArray(Zeros, 4) ); // ??? + packet.append( QByteArray(Zeros, 4) ); // ??? + packet.push_back( 2 ); // AF_INET + packet.push_back( (char)0 ); // AF_INET continued... + packet.push_back( (char)0 ); // port + packet.push_back( (char)0 ); // port continued... + packet.append(internalIP); // internal IP + packet.append( QByteArray(Zeros, 4) ); // ??? + packet.append( QByteArray(Zeros, 4) ); // ??? + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_PLAYERINFO" ); + + // DEBUG_Print( "SENT W3GS_PLAYERINFO" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_PLAYERLEAVE_OTHERS( unsigned char PID, quint32 leftCode ) +{ + QByteArray packet; + + if( PID != 255 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_PLAYERLEAVE_OTHERS ); // W3GS_PLAYERLEAVE_OTHERS + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( PID ); // PID + packet.append(Util::fromUInt32(leftCode)); // left code (see PLAYERLEAVE_ constants in gameprotocol.h) + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_PLAYERLEAVE_OTHERS" ); + + // DEBUG_Print( "SENT W3GS_PLAYERLEAVE_OTHERS" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_GAMELOADED_OTHERS( unsigned char PID ) +{ + QByteArray packet; + + if( PID != 255 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_GAMELOADED_OTHERS ); // W3GS_GAMELOADED_OTHERS + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( PID ); // PID + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMELOADED_OTHERS" ); + + // DEBUG_Print( "SENT W3GS_GAMELOADED_OTHERS" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_SLOTINFO( const QList &lslots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) +{ + QByteArray SlotInfo = EncodeSlotInfo( lslots, randomSeed, layoutStyle, playerSlots ); + QByteArray packet; + + // f709 1900 1300 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0c + // f709 1c00 1600 0c01 ff02 0000 0000 0000 0000 0000 0000 0000 0000 000c + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_SLOTINFO ); // W3GS_SLOTINFO + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt16(SlotInfo.size( ))); // SlotInfo length + packet.append(SlotInfo); // SlotInfo + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_SLOTINFO" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_COUNTDOWN_START( ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_COUNTDOWN_START ); // W3GS_COUNTDOWN_START + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_COUNTDOWN_START" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_COUNTDOWN_END( ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_COUNTDOWN_END ); // W3GS_COUNTDOWN_END + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_COUNTDOWN_END" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_INCOMING_ACTION( const QList &actions, quint16 sendInterval ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_INCOMING_ACTION ); // W3GS_INCOMING_ACTION + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(Util::fromUInt16(sendInterval)); // send interval + + // create subpacket + + if( !actions.isEmpty( ) ) + { + QByteArray subpacket; + + // discarding QQueue qualities because we don't need it here and can take advantage of not copying the data when using const QQueue& + for( QList :: const_iterator i = actions.begin( ); i != actions.end( ); i++ ) + { + CIncomingAction *Action = (*i); + + subpacket.push_back( Action->GetPID( ) ); + subpacket.append(Util::fromUInt16(Action->GetAction( ).size( ))); + subpacket.append(Action->GetAction( )); + } + + // calculate crc (we only care about the first 2 bytes though) + + QByteArray crc32 = Util::fromUInt32(m_GHost->m_CRC->FullCRC( subpacket )); + crc32.resize( 2 ); + + // finish subpacket + + packet.append(crc32); // crc + packet.append(subpacket); // subpacket + } + + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_INCOMING_ACTION" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_CHAT_FROM_HOST( unsigned char fromPID, const QByteArray &toPIDs, unsigned char flag, const QByteArray & flagExtra, const QString & message ) +{ + QByteArray packet; + + if( !toPIDs.isEmpty( ) && !message.isEmpty( ) && message.size( ) < 255 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_CHAT_FROM_HOST ); // W3GS_CHAT_FROM_HOST + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( toPIDs.size( ) ); // number of receivers + packet.append(toPIDs); // receivers + packet.push_back( fromPID ); // sender + packet.push_back( flag ); // flag + packet.append(flagExtra); // extra flag + packet.append(message); // message + packet.push_back( (char)0 ); // ??? + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_CHAT_FROM_HOST" ); + + // DEBUG_Print( "SENT W3GS_CHAT_FROM_HOST" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_START_LAG( const QList &players, bool loadInGame ) +{ + QByteArray packet; + + unsigned char NumLaggers = 0; + + for( QList :: const_iterator i = players.begin( ); i != players.end( ); i++ ) + { + if( loadInGame ) + { + if( !(*i)->GetFinishedLoading( ) ) + NumLaggers++; + } + else + { + if( (*i)->GetLagging( ) ) + NumLaggers++; + } + } + + if( NumLaggers > 0 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_START_LAG ); // W3GS_START_LAG + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( NumLaggers ); + + for( QList :: const_iterator i = players.begin( ); i != players.end( ); i++ ) + { + if( loadInGame ) + { + if( !(*i)->GetFinishedLoading( ) ) + { + packet.push_back( (*i)->GetPID( ) ); + packet.append(Util::fromUInt32(0)); + } + } + else + { + if( (*i)->GetLagging( ) ) + { + packet.push_back( (*i)->GetPID( ) ); + packet.append(Util::fromUInt32(GetTicks( ) - (*i)->GetStartedLaggingTicks( ))); + } + } + } + + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] no laggers passed to SEND_W3GS_START_LAG" ); + + // DEBUG_Print( "SENT W3GS_START_LAG" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_STOP_LAG( CGamePlayer *player, bool loadInGame ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_STOP_LAG ); // W3GS_STOP_LAG + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( player->GetPID( ) ); + + if( loadInGame ) + packet.append(Util::fromUInt32(0)); + else + packet.append(Util::fromUInt32(GetTicks( ) - player->GetStartedLaggingTicks( ))); + + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_STOP_LAG" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_SEARCHGAME( bool TFT, unsigned char war3Version ) +{ + char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" + char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" + char Version[] = { war3Version, 0, 0, 0 }; + char Unknown[] = { 0, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_SEARCHGAME ); // W3GS_SEARCHGAME + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + + if( TFT ) + packet.append(QByteArray(ProductID_TFT, 4)); // Product ID (TFT) + else + packet.append(QByteArray(ProductID_ROC, 4)); // Product ID (ROC) + + packet.append(QByteArray(Version, 4)); // Version + packet.append(QByteArray(Unknown, 4)); // ??? + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_SEARCHGAME" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_GAMEINFO( bool TFT, unsigned char war3Version, const QByteArray & mapGameType, const QByteArray & mapFlags, const QByteArray & mapWidth, const QByteArray & mapHeight, const QString &gameName, const QString &hostName, quint32 upTime, const QString &mapPath, const QByteArray & mapCRC, quint32 slotsTotal, quint32 slotsOpen, quint16 port, quint32 hostCounter ) +{ + char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" + char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" + char Version[] = { war3Version, 0, 0, 0 }; + char Unknown1[] = { 1, 2, 3, 4 }; + char Unknown2[] = { 1, 0, 0, 0 }; + + QByteArray packet; + + if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && !gameName.isEmpty( ) && !hostName.isEmpty( ) && !mapPath.isEmpty( ) && mapCRC.size( ) == 4 ) + { + // make the stat QString + + QByteArray StatString; + StatString.append(mapFlags); + StatString.push_back( (char)0 ); + StatString.append(mapWidth); + StatString.append(mapHeight); + StatString.append(mapCRC); + StatString.append(mapPath); + StatString.push_back( (char)0 ); + StatString.append(hostName); + StatString.push_back( (char)0 ); + StatString.push_back( (char)0 ); + StatString = UTIL_EncodeStatString( StatString ); + + // make the rest of the packet + + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_GAMEINFO ); // W3GS_GAMEINFO + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + + if( TFT ) + packet.append(QByteArray(ProductID_TFT, 4)); // Product ID (TFT) + else + packet.append(QByteArray(ProductID_ROC, 4)); // Product ID (ROC) + + packet.append(QByteArray(Version, 4)); // Version + packet.append(Util::fromUInt32(hostCounter)); // Host Counter + packet.append(QByteArray(Unknown1, 4)); // ??? (this varies wildly even between two identical games created one after another) + packet.append(gameName); // Game Name + packet.push_back( (char)0 ); // 0term for gamename + packet.push_back( (char)0 ); // ??? (maybe game password) + packet.append(StatString); // Stat String + packet.push_back( (char)0 ); // Stat String null terminator (the stat QString is encoded to remove all even numbers i.e. zeros) + packet.append(Util::fromUInt32(slotsTotal)); // Slots Total + packet.append(mapGameType); // Game Type + packet.append(QByteArray(Unknown2, 4)); // ??? + packet.append(Util::fromUInt32(slotsOpen)); // Slots Open + packet.append(Util::fromUInt32(upTime)); // time since creation + packet.append(Util::fromUInt16(port)); // port + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO" ); + + // DEBUG_Print( "SENT W3GS_GAMEINFO" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_CREATEGAME( bool TFT, unsigned char war3Version ) +{ + char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" + char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" + char Version[] = { war3Version, 0, 0, 0 }; + char HostCounter[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_CREATEGAME ); // W3GS_CREATEGAME + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + + if( TFT ) + packet.append(QByteArray(ProductID_TFT, 4)); // Product ID (TFT) + else + packet.append(QByteArray(ProductID_ROC, 4)); // Product ID (ROC) + + packet.append(QByteArray(Version, 4)); // Version + packet.append(QByteArray(HostCounter, 4)); // Host Counter + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_CREATEGAME" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_REFRESHGAME( quint32 players, quint32 playerSlots ) +{ + char HostCounter[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_REFRESHGAME ); // W3GS_REFRESHGAME + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(HostCounter, 4)); // Host Counter + packet.append(Util::fromUInt32(players)); // Players + packet.append(Util::fromUInt32(playerSlots)); // Player Slots + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_REFRESHGAME" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_DECREATEGAME( ) +{ + char HostCounter[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_DECREATEGAME ); // W3GS_DECREATEGAME + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(HostCounter, 4)); // Host Counter + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_DECREATEGAME" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_MAPCHECK( const QString &mapPath, const QByteArray & mapSize, const QByteArray & mapInfo, const QByteArray & mapCRC, const QByteArray & mapSHA1 ) +{ + char Unknown[] = { 1, 0, 0, 0 }; + + QByteArray packet; + + if( !mapPath.isEmpty( ) && mapSize.size( ) == 4 && mapInfo.size( ) == 4 && mapCRC.size( ) == 4 && mapSHA1.size( ) == 20 ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_MAPCHECK ); // W3GS_MAPCHECK + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(Unknown, 4)); // ??? + packet.append(mapPath); // map path + packet.push_back( (char)0 ); // 0 term + packet.append(mapSize); // map size + packet.append(mapInfo); // map info + packet.append(mapCRC); // map crc + packet.append(mapSHA1); // map sha1 + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_MAPCHECK" ); + + // DEBUG_Print( "SENT W3GS_MAPCHECK" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_STARTDOWNLOAD( unsigned char fromPID ) +{ + char Unknown[] = { 1, 0, 0, 0 }; + + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_STARTDOWNLOAD ); // W3GS_STARTDOWNLOAD + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.append(QByteArray(Unknown, 4)); // ??? + packet.push_back( fromPID ); // from PID + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_STARTDOWNLOAD" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_MAPPART( unsigned char fromPID, unsigned char toPID, quint32 start, const QByteArray &mapData ) +{ + char Unknown[] = { 1, 0, 0, 0 }; + + QByteArray packet; + + if( start < (unsigned int)mapData.size( ) ) + { + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_MAPPART ); // W3GS_MAPPART + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( toPID ); // to PID + packet.push_back( fromPID ); // from PID + packet.append(QByteArray(Unknown, 4)); // ??? + packet.append(Util::fromUInt32(start)); // start position + + // calculate end position (don't send more than 1442 map bytes in one packet) + + quint32 End = start + 1442; + + if( End > (unsigned int)mapData.size( ) ) + End = mapData.size( ); + + // calculate crc + + QByteArray crc32 = Util::fromUInt32( m_GHost->m_CRC->FullCRC( mapData.mid(start, End - start) ) ); + packet.append(crc32); + + // map data + + packet.append( mapData.mid(start, End - start) ); + AssignLength( packet ); + } + else + CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_MAPPART" ); + + // DEBUG_Print( "SENT W3GS_MAPPART" ); + // DEBUG_Print( packet ); + return packet; +} + +QByteArray CGameProtocol :: SEND_W3GS_INCOMING_ACTION2( const QList &actions ) +{ + QByteArray packet; + packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant + packet.push_back( W3GS_INCOMING_ACTION2 ); // W3GS_INCOMING_ACTION2 + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // packet length will be assigned later + packet.push_back( (char)0 ); // ??? (send interval?) + packet.push_back( (char)0 ); // ??? (send interval?) + + // create subpacket + + if( !actions.isEmpty( ) ) + { + QByteArray subpacket; + + // discarding QQueue qualities because we don't need it here and can take advantage of not copying the data when using const QQueue& + for( QList :: const_iterator i = actions.begin( ); i != actions.end( ); i++ ) + { + CIncomingAction *Action = (*i); + + subpacket.push_back( Action->GetPID( ) ); + subpacket.append(Util::fromUInt16(Action->GetAction( ).size( ))); + subpacket.append(Action->GetAction( )); + } + + // calculate crc (we only care about the first 2 bytes though) + + QByteArray crc32 = Util::fromUInt32( m_GHost->m_CRC->FullCRC(subpacket) ); + crc32.resize( 2 ); + + // finish subpacket + + packet.append(crc32); // crc + packet.append(subpacket); // subpacket + } + + AssignLength( packet ); + // DEBUG_Print( "SENT W3GS_INCOMING_ACTION2" ); + // DEBUG_Print( packet ); + return packet; +} + +///////////////////// +// OTHER FUNCTIONS // +///////////////////// + +bool CGameProtocol :: AssignLength( QByteArray &content ) const +{ + // insert the actual length of the content array into bytes 3 and 4 (indices 2 and 3) + + QByteArray LengthBytes; + + if( content.size( ) >= 4 && content.size( ) <= 65535 ) + { + LengthBytes = Util::fromUInt16( content.size( ) ); + content[2] = LengthBytes[0]; + content[3] = LengthBytes[1]; + return true; + } + + return false; +} + +bool CGameProtocol :: ValidateLength( const QByteArray &content ) const +{ + // verify that bytes 3 and 4 (indices 2 and 3) of the content array describe the length + + quint16 Length; + QByteArray LengthBytes; + + if( content.size( ) >= 4 && content.size( ) <= 65535 ) + { + LengthBytes.push_back( content[2] ); + LengthBytes.push_back( content[3] ); + Length = Util::extractUInt16( LengthBytes ); + + if( Length == content.size( ) ) + return true; + } + + return false; +} + +QByteArray CGameProtocol :: EncodeSlotInfo( const QList &lslots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ) +{ + QByteArray SlotInfo; + SlotInfo.push_back( (unsigned char)lslots.size( ) ); // number of slots + + for( int i = 0; i < lslots.size( ); i++ ) + SlotInfo.append(lslots[i].GetQByteArray( )); + + SlotInfo.append(Util::fromUInt32(randomSeed)); // random seed + SlotInfo.push_back( layoutStyle ); // LayoutStyle (0 = melee, 1 = custom forces, 3 = custom forces + fixed player settings) + SlotInfo.push_back( playerSlots ); // number of player slots (non observer) + return SlotInfo; +} + +// +// CIncomingJoinPlayer +// + +CIncomingJoinPlayer :: CIncomingJoinPlayer( quint32 nHostCounter, const QString &nName, const QByteArray &nInternalIP ) +{ + m_HostCounter = nHostCounter; + m_Name = nName; + m_InternalIP = nInternalIP; +} + +CIncomingJoinPlayer :: ~CIncomingJoinPlayer( ) +{ + +} + +// +// CIncomingAction +// + +CIncomingAction :: CIncomingAction( unsigned char nPID, const QByteArray &nCRC, const QByteArray &nAction ) +{ + m_PID = nPID; + m_CRC = nCRC; + m_Action = nAction; +} + +CIncomingAction :: ~CIncomingAction( ) +{ + +} + +// +// CIncomingChatPlayer +// + +CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, const QString &nMessage ) +{ + m_Type = CTH_MESSAGE; + m_FromPID = nFromPID; + m_ToPIDs = nToPIDs; + m_Flag = nFlag; + m_Message = nMessage; +} + +CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, const QString &nMessage, const QByteArray &nExtraFlags ) +{ + m_Type = CTH_MESSAGEEXTRA; + m_FromPID = nFromPID; + m_ToPIDs = nToPIDs; + m_Flag = nFlag; + m_Message = nMessage; + m_ExtraFlags = nExtraFlags; +} + +CIncomingChatPlayer :: CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, unsigned char nByte ) +{ + if( nFlag == 17 ) + m_Type = CTH_TEAMCHANGE; + else if( nFlag == 18 ) + m_Type = CTH_COLOURCHANGE; + else if( nFlag == 19 ) + m_Type = CTH_RACECHANGE; + else if( nFlag == 20 ) + m_Type = CTH_HANDICAPCHANGE; + + m_FromPID = nFromPID; + m_ToPIDs = nToPIDs; + m_Flag = nFlag; + m_Byte = nByte; +} + +CIncomingChatPlayer :: ~CIncomingChatPlayer( ) +{ + +} + +// +// CIncomingMapSize +// + +CIncomingMapSize :: CIncomingMapSize( unsigned char nSizeFlag, quint32 nMapSize ) +{ + m_SizeFlag = nSizeFlag; + m_MapSize = nMapSize; +} + +CIncomingMapSize :: ~CIncomingMapSize( ) +{ + +} diff --git a/src/libghost/gameprotocol.h b/src/libghost/gameprotocol.h new file mode 100644 index 0000000..b6e1ce1 --- /dev/null +++ b/src/libghost/gameprotocol.h @@ -0,0 +1,252 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GAMEPROTOCOL_H +#define GAMEPROTOCOL_H + +// +// CGameProtocol +// + +#define W3GS_HEADER_CONSTANT 247 + +#define GAME_NONE 0 // this case isn't part of the protocol, it's for internal use only +#define GAME_FULL 2 +#define GAME_PUBLIC 16 +#define GAME_PRIVATE 17 + +#define GAMETYPE_CUSTOM 1 +#define GAMETYPE_BLIZZARD 9 + +#define PLAYERLEAVE_DISCONNECT 1 +#define PLAYERLEAVE_LOST 7 +#define PLAYERLEAVE_LOSTBUILDINGS 8 +#define PLAYERLEAVE_WON 9 +#define PLAYERLEAVE_DRAW 10 +#define PLAYERLEAVE_OBSERVER 11 +#define PLAYERLEAVE_LOBBY 13 +#define PLAYERLEAVE_GPROXY 100 + +#define REJECTJOIN_FULL 9 +#define REJECTJOIN_STARTED 10 +#define REJECTJOIN_WRONGPASSWORD 27 + +#include +#include "includes.h" +#include "gameslot.h" + +class CGHost; +class CGamePlayer; +class CIncomingJoinPlayer; +class CIncomingAction; +class CIncomingChatPlayer; +class CIncomingMapSize; + +class CGameProtocol +{ +public: + CGHost *m_GHost; + + enum Protocol { + W3GS_PING_FROM_HOST = 1, // 0x01 + W3GS_SLOTINFOJOIN = 4, // 0x04 + W3GS_REJECTJOIN = 5, // 0x05 + W3GS_PLAYERINFO = 6, // 0x06 + W3GS_PLAYERLEAVE_OTHERS = 7, // 0x07 + W3GS_GAMELOADED_OTHERS = 8, // 0x08 + W3GS_SLOTINFO = 9, // 0x09 + W3GS_COUNTDOWN_START = 10, // 0x0A + W3GS_COUNTDOWN_END = 11, // 0x0B + W3GS_INCOMING_ACTION = 12, // 0x0C + W3GS_CHAT_FROM_HOST = 15, // 0x0F + W3GS_START_LAG = 16, // 0x10 + W3GS_STOP_LAG = 17, // 0x11 + W3GS_HOST_KICK_PLAYER = 28, // 0x1C + W3GS_REQJOIN = 30, // 0x1E + W3GS_LEAVEGAME = 33, // 0x21 + W3GS_GAMELOADED_SELF = 35, // 0x23 + W3GS_OUTGOING_ACTION = 38, // 0x26 + W3GS_OUTGOING_KEEPALIVE = 39, // 0x27 + W3GS_CHAT_TO_HOST = 40, // 0x28 + W3GS_DROPREQ = 41, // 0x29 + W3GS_SEARCHGAME = 47, // 0x2F (UDP/LAN) + W3GS_GAMEINFO = 48, // 0x30 (UDP/LAN) + W3GS_CREATEGAME = 49, // 0x31 (UDP/LAN) + W3GS_REFRESHGAME = 50, // 0x32 (UDP/LAN) + W3GS_DECREATEGAME = 51, // 0x33 (UDP/LAN) + W3GS_CHAT_OTHERS = 52, // 0x34 + W3GS_PING_FROM_OTHERS = 53, // 0x35 + W3GS_PONG_TO_OTHERS = 54, // 0x36 + W3GS_MAPCHECK = 61, // 0x3D + W3GS_STARTDOWNLOAD = 63, // 0x3F + W3GS_MAPSIZE = 66, // 0x42 + W3GS_MAPPART = 67, // 0x43 + W3GS_MAPPARTOK = 68, // 0x44 + W3GS_MAPPARTNOTOK = 69, // 0x45 - just a guess, received this packet after forgetting to send a crc in W3GS_MAPPART (f7 45 0a 00 01 02 01 00 00 00) + W3GS_PONG_TO_HOST = 70, // 0x46 + W3GS_INCOMING_ACTION2 = 72 // 0x48 - received this packet when there are too many actions to fit in W3GS_INCOMING_ACTION + }; + + CGameProtocol( CGHost *nGHost ); + ~CGameProtocol( ); + + // receive functions + + CIncomingJoinPlayer *RECEIVE_W3GS_REQJOIN( const QByteArray &data ); + quint32 RECEIVE_W3GS_LEAVEGAME( const QByteArray &data ); + bool RECEIVE_W3GS_GAMELOADED_SELF( const QByteArray &data ); + CIncomingAction *RECEIVE_W3GS_OUTGOING_ACTION( const QByteArray &data, unsigned char PID ); + quint32 RECEIVE_W3GS_OUTGOING_KEEPALIVE( const QByteArray &data ); + CIncomingChatPlayer *RECEIVE_W3GS_CHAT_TO_HOST( const QByteArray &data ); + bool RECEIVE_W3GS_SEARCHGAME( const QByteArray &data, unsigned char war3Version ); + CIncomingMapSize *RECEIVE_W3GS_MAPSIZE( const QByteArray &data, const QByteArray &mapSize ); + quint32 RECEIVE_W3GS_MAPPARTOK( const QByteArray &data ); + quint32 RECEIVE_W3GS_PONG_TO_HOST( const QByteArray &data ); + + // send functions + + QByteArray SEND_W3GS_PING_FROM_HOST( ); + QByteArray SEND_W3GS_SLOTINFOJOIN( unsigned char PID, const QByteArray & port, const QByteArray & externalIP, QList &lslots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); + QByteArray SEND_W3GS_REJECTJOIN( quint32 reason ); + QByteArray SEND_W3GS_PLAYERINFO( unsigned char PID, const QString &name, const QByteArray & externalIP, const QByteArray & internalIP ); + QByteArray SEND_W3GS_PLAYERLEAVE_OTHERS( unsigned char PID, quint32 leftCode ); + QByteArray SEND_W3GS_GAMELOADED_OTHERS( unsigned char PID ); + QByteArray SEND_W3GS_SLOTINFO( const QList &lslots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); + QByteArray SEND_W3GS_COUNTDOWN_START( ); + QByteArray SEND_W3GS_COUNTDOWN_END( ); + QByteArray SEND_W3GS_INCOMING_ACTION( const QList &actions, quint16 sendInterval ); + QByteArray SEND_W3GS_CHAT_FROM_HOST( unsigned char fromPID, const QByteArray & toPIDs, unsigned char flag, const QByteArray & flagExtra, const QString & message ); + QByteArray SEND_W3GS_START_LAG( const QList &players, bool loadInGame = false ); + QByteArray SEND_W3GS_STOP_LAG( CGamePlayer *player, bool loadInGame = false ); + QByteArray SEND_W3GS_SEARCHGAME( bool TFT, unsigned char war3Version ); + QByteArray SEND_W3GS_GAMEINFO( bool TFT, unsigned char war3Version, const QByteArray & mapGameType, const QByteArray & mapFlags, const QByteArray & mapWidth, const QByteArray & mapHeight, const QString & gameName, const QString & hostName, quint32 upTime, const QString & mapPath, const QByteArray & mapCRC, quint32 slotsTotal, quint32 slotsOpen, quint16 port, quint32 hostCounter ); + QByteArray SEND_W3GS_CREATEGAME( bool TFT, unsigned char war3Version ); + QByteArray SEND_W3GS_REFRESHGAME( quint32 players, quint32 playerSlots ); + QByteArray SEND_W3GS_DECREATEGAME( ); + QByteArray SEND_W3GS_MAPCHECK( const QString & mapPath, const QByteArray & mapSize, const QByteArray & mapInfo, const QByteArray & mapCRC, const QByteArray & mapSHA1 ); + QByteArray SEND_W3GS_STARTDOWNLOAD( unsigned char fromPID ); + QByteArray SEND_W3GS_MAPPART( unsigned char fromPID, unsigned char toPID, quint32 start, const QByteArray &mapData ); + QByteArray SEND_W3GS_INCOMING_ACTION2( const QList &actions ); + + // other functions + +private: + bool AssignLength( QByteArray &content ) const; + bool ValidateLength( const QByteArray &content ) const; + QByteArray EncodeSlotInfo( const QList &slots, quint32 randomSeed, unsigned char layoutStyle, unsigned char playerSlots ); +}; + +// +// CIncomingJoinPlayer +// + +class CIncomingJoinPlayer +{ +private: + quint32 m_HostCounter; + QString m_Name; + QByteArray m_InternalIP; + +public: + CIncomingJoinPlayer( quint32 nHostCounter, const QString &nName, const QByteArray &nInternalIP ); + ~CIncomingJoinPlayer( ); + + quint32 GetHostCounter( ) const { return m_HostCounter; } + const QString &GetName( ) const { return m_Name; } + const QByteArray &GetInternalIP( ) const { return m_InternalIP; } +}; + +// +// CIncomingAction +// + +class CIncomingAction +{ +private: + unsigned char m_PID; + QByteArray m_CRC; + QByteArray m_Action; + +public: + CIncomingAction( unsigned char nPID, const QByteArray &nCRC, const QByteArray &nAction ); + ~CIncomingAction( ); + + unsigned char GetPID( ) const { return m_PID; } + const QByteArray &GetCRC( ) const { return m_CRC; } + const QByteArray &GetAction( ) const { return m_Action; } + quint32 GetLength( ) const { return m_Action.size( ) + 3; } +}; + +// +// CIncomingChatPlayer +// + +class CIncomingChatPlayer +{ +public: + enum ChatToHostType + { + CTH_MESSAGE = 0, // a chat message + CTH_MESSAGEEXTRA = 1, // a chat message with extra flags + CTH_TEAMCHANGE = 2, // a team change request + CTH_COLOURCHANGE = 3, // a colour change request + CTH_RACECHANGE = 4, // a race change request + CTH_HANDICAPCHANGE = 5 // a handicap change request + }; + +private: + ChatToHostType m_Type; + unsigned char m_FromPID; + QByteArray m_ToPIDs; + unsigned char m_Flag; + QString m_Message; + unsigned char m_Byte; + QByteArray m_ExtraFlags; + +public: + CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, const QString &nMessage ); + CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, const QString &nMessage, const QByteArray &nExtraFlags ); + CIncomingChatPlayer( unsigned char nFromPID, const QByteArray &nToPIDs, unsigned char nFlag, unsigned char nByte ); + ~CIncomingChatPlayer( ); + + ChatToHostType GetType( ) const { return m_Type; } + unsigned char GetFromPID( ) const { return m_FromPID; } + const QByteArray &GetToPIDs( ) const { return m_ToPIDs; } + unsigned char GetFlag( ) const { return m_Flag; } + const QString &GetMessage( ) const { return m_Message; } + unsigned char GetByte( ) const { return m_Byte; } + const QByteArray &GetExtraFlags( ) const { return m_ExtraFlags; } +}; + +class CIncomingMapSize +{ +private: + unsigned char m_SizeFlag; + quint32 m_MapSize; + +public: + CIncomingMapSize( unsigned char nSizeFlag, quint32 nMapSize ); + ~CIncomingMapSize( ); + + unsigned char GetSizeFlag( ) { return m_SizeFlag; } + quint32 GetMapSize( ) { return m_MapSize; } +}; + +#endif diff --git a/ghost/gameslot.cpp b/src/libghost/gameslot.cpp similarity index 85% rename from ghost/gameslot.cpp rename to src/libghost/gameslot.cpp index a04b203..8045197 100644 --- a/ghost/gameslot.cpp +++ b/src/libghost/gameslot.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -25,7 +25,7 @@ // CGameSlot // -CGameSlot :: CGameSlot( BYTEARRAY &n ) +CGameSlot :: CGameSlot( QByteArray &n ) { if( n.size( ) >= 7 ) { @@ -74,14 +74,19 @@ CGameSlot :: CGameSlot( unsigned char nPID, unsigned char nDownloadStatus, unsig m_Handicap = nHandicap; } +CGameSlot :: CGameSlot( ) +{ + // do not use this one, only for vector growing +} + CGameSlot :: ~CGameSlot( ) { } -BYTEARRAY CGameSlot :: GetByteArray( ) const +QByteArray CGameSlot :: GetQByteArray( ) const { - BYTEARRAY b; + QByteArray b; b.push_back( m_PID ); b.push_back( m_DownloadStatus ); b.push_back( m_SlotStatus ); diff --git a/ghost/gameslot.h b/src/libghost/gameslot.h similarity index 77% rename from ghost/gameslot.h rename to src/libghost/gameslot.h index 476bfab..e2e74c2 100644 --- a/ghost/gameslot.h +++ b/src/libghost/gameslot.h @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -54,19 +54,20 @@ class CGameSlot unsigned char m_Handicap; // handicap public: - CGameSlot( BYTEARRAY &n ); + CGameSlot( ); + CGameSlot( QByteArray &n ); CGameSlot( unsigned char nPID, unsigned char nDownloadStatus, unsigned char nSlotStatus, unsigned char nComputer, unsigned char nTeam, unsigned char nColour, unsigned char nRace, unsigned char nComputerType = 1, unsigned char nHandicap = 100 ); ~CGameSlot( ); - unsigned char GetPID( ) { return m_PID; } - unsigned char GetDownloadStatus( ) { return m_DownloadStatus; } - unsigned char GetSlotStatus( ) { return m_SlotStatus; } - unsigned char GetComputer( ) { return m_Computer; } - unsigned char GetTeam( ) { return m_Team; } - unsigned char GetColour( ) { return m_Colour; } - unsigned char GetRace( ) { return m_Race; } - unsigned char GetComputerType( ) { return m_ComputerType; } - unsigned char GetHandicap( ) { return m_Handicap; } + unsigned char GetPID( ) const { return m_PID; } + unsigned char GetDownloadStatus( ) const { return m_DownloadStatus; } + unsigned char GetSlotStatus( ) const { return m_SlotStatus; } + unsigned char GetComputer( ) const { return m_Computer; } + unsigned char GetTeam( ) const { return m_Team; } + unsigned char GetColour( ) const { return m_Colour; } + unsigned char GetRace( ) const { return m_Race; } + unsigned char GetComputerType( ) const { return m_ComputerType; } + unsigned char GetHandicap( ) const { return m_Handicap; } void SetPID( unsigned char nPID ) { m_PID = nPID; } void SetDownloadStatus( unsigned char nDownloadStatus ) { m_DownloadStatus = nDownloadStatus; } @@ -78,7 +79,7 @@ class CGameSlot void SetComputerType( unsigned char nComputerType ) { m_ComputerType = nComputerType; } void SetHandicap( unsigned char nHandicap ) { m_Handicap = nHandicap; } - BYTEARRAY GetByteArray( ) const; + QByteArray GetQByteArray( ) const; }; #endif diff --git a/src/libghost/ghost.cpp b/src/libghost/ghost.cpp new file mode 100644 index 0000000..34b6ccf --- /dev/null +++ b/src/libghost/ghost.cpp @@ -0,0 +1,1507 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "ghost_p.h" +#include "util.h" +#include "crc32.h" +#include "sha1.h" +#include "csvparser.h" +#include "config.h" +#include "language.h" +#include "ghostdb.h" +#include "ghostdbsqlite.h" +#include "ghostdbmysql.h" +#include "bnet.h" +#include "map.h" +#include "packed.h" +#include "savegame.h" +#include "gameplayer.h" +#include "gameprotocol.h" +#include "gpsprotocol.h" +#include "game_base.h" +#include "game.h" +#include "game_admin.h" +#include "interfaces.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODOTODO: remove this crappy implementation and replace it with something monotonic :) +static bool timerStarted=FALSE; +static QTime gBasicTime; + +QThreadStorage currentGHost; + + +quint32 GetTime() +{ + return GetTicks( ) / 1000; +} + +quint32 GetTicks() +{ + if( !timerStarted ) + gBasicTime.start(); + return gBasicTime.elapsed(); +} + +void CONSOLE_Print( QString message ) +{ + if( currentGHost.hasLocalData( ) ) + currentGHost.localData()->LogInfo( message ); + + // logging + + /*if (!gLogFile.fileName().isEmpty()) + { + if( gLogMethod == 1 ) + { + gLogFile.open(QFile::WriteOnly | QFile::Append); + + if( gLogFile.isWritable() ) + { + gLogStream << "[" << QTime::currentTime().toString() << "] " << message << endl; + gLogFile.close(); + } + } + else if( gLogMethod == 2 && gLogFile.isWritable() ) + gLogStream << "[" << QTime::currentTime().toString() << "] " << message << endl; + }*/ +} + +void DEBUG_Print( QString message ) +{ + cout << message.toStdString() << endl; +} + + + +// +// CGHost +// + +CGame *CGHost :: GetCurrentGame() const +{ + return m_CurrentGame; +} + +CAdminGame *CGHost :: GetAdminGame() const +{ + return m_AdminGame; +} + +CLanguage *CGHost :: GetLanguage( ) const +{ + return m_Language; +} + +CMap *CGHost :: GetCurrentMap( ) const +{ + return m_Map; +} + +void CGHost :: SetCurrentMap( CMap *map) +{ + if( m_Map ) + delete m_Map; + m_Map = map; +} + +CMap *CGHost :: GetAdminMap( ) const +{ + return m_AdminMap; +} + +CMap *CGHost :: GetAutoHostMap( ) const +{ + return m_AutoHostMap; +} + +void CGHost :: SetAutoHostMap( CMap *map) +{ + if( m_AutoHostMap ) + delete m_AutoHostMap; + m_AutoHostMap = map; +} + +void CGHost :: ExitNice( ) +{ + m_ExitingNice = true; +} + +void CGHost :: Exit( ) +{ + m_Exiting = true; +} + +void CGHost :: SendUdpBroadcast( const QByteArray &data, const quint16 &port, const QHostAddress& target) +{ + m_UDPSocket->writeDatagram( data, target, port ); +} + +void CGHost :: SendUdpBroadcast( const QByteArray &data, const quint16 &port) +{ + SendUdpBroadcast( data, port, m_BroadcastTarget ); +} + +void CGHost :: SendUdpBroadcast( const QByteArray &data) +{ + SendUdpBroadcast( data, 6112, m_BroadcastTarget ); +} + +void CGHost :: LoadSavegame( const QString &path ) +{ + QFileInfo info( path ); + m_SaveGame->Load( path, false ); + m_SaveGame->ParseSaveGame( ); + m_SaveGame->SetFileName( path ); + m_SaveGame->SetFileNameNoPath( info.fileName( ) ); +} + +void CGHost :: Log( const QString &message, int level ) +{ + // TODO: handle logging level + cout << message.toStdString() << endl; +} + +void CGHost :: LogInfo( const QString &message ) +{ + Log( message, 0 ); + for( QList :: const_iterator i = m_LogPlugins.begin( ); i != m_LogPlugins.end( ); i++ ) + { + (*i)->LogInfo( message ); + } +} + +void CGHost :: LogWarning( const QString &message ) +{ + Log( message, 1 ); + for( QList :: const_iterator i = m_LogPlugins.begin( ); i != m_LogPlugins.end( ); i++ ) + { + (*i)->LogWarning( message ); + } +} + +void CGHost :: LogError( const QString &message ) +{ + Log( message, 2 ); + for( QList :: const_iterator i = m_LogPlugins.begin( ); i != m_LogPlugins.end( ); i++ ) + { + (*i)->LogError( message ); + } +} + +void CGHost :: EventGameCommand( CBaseGame *game, CGamePlayer *player, const QString &command, const QString &payload ) +{ + ICommandProvider::CommandData data( command, payload ); + // TODO: what do we do with IsAdmin and IsRootAdmin? + //player->GetSpoofedRealm() + for( QList :: const_iterator i = m_CommandProviders.begin( ); i != m_CommandProviders.end( ); i++ ) + { + (*i)->OnGameCommand( game, player, data ); + } +} + +void CGHost :: EventBnetCommand( CBNET *bnet, const QString &user, const QString &command, const QString &payload, bool whisper ) +{ + ICommandProvider::CommandData data( command, payload ); + data.SetAdmin( bnet->IsAdmin( user ) ); + data.SetRootAdmin( bnet->IsRootAdmin( user ) ); + for( QList :: const_iterator i = m_CommandProviders.begin( ); i != m_CommandProviders.end( ); i++ ) + { + (*i)->OnBNETCommand( bnet, user, whisper, data ); + } +} + +CGHost :: CGHost( CConfig *CFG, QString configFile ) + : d_ptr(new CGHostPrivate()), + m_ConfigFile(configFile) +{ + currentGHost.setLocalData( this ); + foreach( QObject *plugin, QPluginLoader::staticInstances() ) + { + LoadPlugin( plugin, CFG ); + } + QDir pluginsDir = QDir( qApp->applicationDirPath() ); + QString cfgPluginDir = CFG->GetString( "bot_plugindir", "plugins" ); + + pluginsDir.cd( cfgPluginDir ); + LoadPlugins( pluginsDir, CFG ); + + m_UDPSocket = new QUdpSocket(this); + QString broadcastTarget = CFG->GetString( "udp_broadcasttarget", QString( ) ); + if( broadcastTarget.isEmpty( ) ) + m_BroadcastTarget = QHostAddress :: Broadcast; + else + m_BroadcastTarget = QHostAddress( broadcastTarget ); + + //m_UDPSocket->setProperty("target", ); + m_UDPSocket->setProperty("dontroute", CFG->GetInt( "udp_dontroute", 0 ) == 0 ? false : true ); + m_ReconnectSocket = NULL; + m_GPSProtocol = new CGPSProtocol( ); + m_CRC = new CCRC32( ); + m_CRC->Initialize( ); + m_SHA = new CSHA1( ); + m_CurrentGame = NULL; + QString DBType = CFG->GetString( "db_type", "sqlite3" ); + + m_CallableUpdateTimer.setInterval(200); + QObject::connect(&m_CallableUpdateTimer, SIGNAL(timeout()), this, SLOT(EventCallableUpdateTimeout())); + + m_AutoHostTimer.setSingleShot(true); + m_AutoHostTimer.setInterval(500); + QObject::connect(&m_AutoHostTimer, SIGNAL(timeout()), this, SLOT(EventAutoHost())); + + // create connections + + CONSOLE_Print( "[GHOST] opening primary database" ); + + if( DBType == "mysql" ) + { +#ifdef GHOST_MYSQL + m_DB = new CGHostDBMySQL( CFG ); +#else + CONSOLE_Print( "[GHOST] warning - this binary was not compiled with MySQL database support, using SQLite database instead" ); + m_DB = new CGHostDBSQLite( CFG ); +#endif + } + else + m_DB = new CGHostDBSQLite( CFG ); + + CONSOLE_Print( "[GHOST] opening secondary (local) database" ); + m_DBLocal = new CGHostDBSQLite( CFG ); + + if (m_DB->HasError() ) + { + CONSOLE_Print( "[GHOST] database initialization error - " + m_DB->GetError() ); + deleteLater(); + return; + } + if (m_DBLocal->HasError() ) + { + CONSOLE_Print( "[GHOST] local database initialization error - " + m_DB->GetError() ); + deleteLater(); + return; + } + + QObject::connect(m_DBLocal, SIGNAL(error(QString)), this, SLOT(EventDatabaseError(QString))); + QObject::connect(m_DB, SIGNAL(error(QString)), this, SLOT(EventDatabaseError(QString))); + + QString HostName = QHostInfo::localHostName(); + + CONSOLE_Print( "[GHOST] local hostname is [" + HostName + "]" ); + + // get a list of local IP addresses + // this list is used elsewhere to determine if a player connecting to the bot is local or not + + CONSOLE_Print( "[GHOST] attempting to find local IP addresses" ); + + QList ipAddressesList = QNetworkInterface::allAddresses(); + // use non-localhost IPv4 addresses + // TODO: check if address is LAN-address? + for (int i = 0; i < ipAddressesList.size(); ++i) { + if (ipAddressesList.at(i) != QHostAddress::LocalHost && + ipAddressesList.at(i).toIPv4Address()) { + CONSOLE_Print( "[GHOST] local IP address found: " + ipAddressesList.at( i ).toString() ); + m_LocalAddresses.push_back( Util::fromUInt32( ipAddressesList.at( i ).toIPv4Address( ) ) ); + } + } + // if we did not find one, use IPv4 localhost + if (m_LocalAddresses.isEmpty()) + m_LocalAddresses.push_back( Util::fromUInt32( QHostAddress(QHostAddress::LocalHost).toIPv4Address( ) ) ); + + m_Language = NULL; + m_Exiting = false; + m_ExitingNice = false; + m_Enabled = true; + m_Version = "17.0"; + m_AutoHostMaximumGames = CFG->GetInt( "autohost_maxgames", 0 ); + m_AutoHostAutoStartPlayers = CFG->GetInt( "autohost_startplayers", 0 ); + m_AutoHostGameName = CFG->GetString( "autohost_gamename", QString( ) ); + m_AutoHostOwner = CFG->GetString( "autohost_owner", QString( ) ); + m_AutoHostMatchMaking = false; + m_AutoHostMinimumScore = 0.0; + m_AutoHostMaximumScore = 0.0; + m_AllGamesFinished = false; + m_AllGamesFinishedTime = 0; + m_TFT = CFG->GetInt( "bot_tft", 1 ) == 0 ? false : true; + + if( m_TFT ) + CONSOLE_Print( "[GHOST] acting as Warcraft III: The Frozen Throne" ); + else + CONSOLE_Print( "[GHOST] acting as Warcraft III: Reign of Chaos" ); + + m_HostPort = CFG->GetInt( "bot_hostport", 6112 ); + m_Reconnect = CFG->GetInt( "bot_reconnect", 1 ) == 0 ? false : true; + m_ReconnectPort = CFG->GetInt( "bot_reconnectport", 6114 ); + m_DefaultMap = CFG->GetString( "bot_defaultmap", "map" ); + m_AdminGameCreate = CFG->GetInt( "admingame_create", 0 ) == 0 ? false : true; + m_AdminGamePort = CFG->GetInt( "admingame_port", 6113 ); + m_AdminGamePassword = CFG->GetString( "admingame_password", QString( ) ); + m_AdminGameMap = CFG->GetString( "admingame_map", QString( ) ); + m_LANWar3Version = CFG->GetInt( "lan_war3version", 24 ); + m_ReplayWar3Version = CFG->GetInt( "replay_war3version", 24 ); + m_ReplayBuildNumber = CFG->GetInt( "replay_buildnumber", 6059 ); + SetConfigs( CFG ); + + if (m_Reconnect) + CreateReconnectServer(); + + // load the battle.net connections + // we're just loading the config data and creating the CBNET classes here, the connections are established later (in the Update function) + + for( quint32 i = 1; i < 10; i++ ) + { + QString Prefix; + + if( i == 1 ) + Prefix = "bnet_"; + else + Prefix = "bnet" + QString::number( i ) + "_"; + + QString Server = CFG->GetString( Prefix + "server", QString( ) ); + QString ServerAlias = CFG->GetString( Prefix + "serveralias", QString( ) ); + QString CDKeyROC = CFG->GetString( Prefix + "cdkeyroc", QString( ) ); + QString CDKeyTFT = CFG->GetString( Prefix + "cdkeytft", QString( ) ); + QString CountryAbbrev = CFG->GetString( Prefix + "countryabbrev", "USA" ); + QString Country = CFG->GetString( Prefix + "country", "United States" ); + QString Locale = CFG->GetString( Prefix + "locale", "system" ); + quint32 LocaleID; + + if( Locale == "system" ) + { +#ifdef _MSC_VER + LocaleID = GetUserDefaultLangID( ); +#else + LocaleID = 1033; +#endif + } + else + LocaleID = Locale.toUInt(); + + QString UserName = CFG->GetString( Prefix + "username", QString( ) ); + QString UserPassword = CFG->GetString( Prefix + "password", QString( ) ); + QString FirstChannel = CFG->GetString( Prefix + "firstchannel", "The Void" ); + QString RootAdmin = CFG->GetString( Prefix + "rootadmin", QString( ) ); + QString BNETCommandTrigger = CFG->GetString( Prefix + "commandtrigger", "!" ); + + if( BNETCommandTrigger.isEmpty( ) ) + BNETCommandTrigger = "!"; + + bool HoldFriends = CFG->GetInt( Prefix + "holdfriends", 1 ) == 0 ? false : true; + bool HoldClan = CFG->GetInt( Prefix + "holdclan", 1 ) == 0 ? false : true; + bool PublicCommands = CFG->GetInt( Prefix + "publiccommands", 1 ) == 0 ? false : true; + QString BNLSServer = CFG->GetString( Prefix + "bnlsserver", QString( ) ); + int BNLSPort = CFG->GetInt( Prefix + "bnlsport", 9367 ); + int BNLSWardenCookie = CFG->GetInt( Prefix + "bnlswardencookie", 0 ); + unsigned char War3Version = CFG->GetInt( Prefix + "custom_war3version", 24 ); + QByteArray EXEVersion = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversion", QString( ) ), 4 ); + QByteArray EXEVersionHash = UTIL_ExtractNumbers( CFG->GetString( Prefix + "custom_exeversionhash", QString( ) ), 4 ); + QString PasswordHashType = CFG->GetString( Prefix + "custom_passwordhashtype", QString( ) ); + QString PVPGNRealmName = CFG->GetString( Prefix + "custom_pvpgnrealmname", "PvPGN Realm" ); + quint32 MaxMessageLength = CFG->GetInt( Prefix + "custom_maxmessagelength", 200 ); + + if( Server.isEmpty( ) ) + break; + + if( CDKeyROC.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] missing " + Prefix + "cdkeyroc, skipping this battle.net connection" ); + continue; + } + + if( m_TFT && CDKeyTFT.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] missing " + Prefix + "cdkeytft, skipping this battle.net connection" ); + continue; + } + + if( UserName.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] missing " + Prefix + "username, skipping this battle.net connection" ); + continue; + } + + if( UserPassword.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] missing " + Prefix + "password, skipping this battle.net connection" ); + continue; + } + + CONSOLE_Print( "[GHOST] found battle.net connection #" + QString::number( i ) + " for server [" + Server + "]" ); + + if( Locale == "system" ) + { +#ifdef WIN32 + CONSOLE_Print( "[GHOST] using system locale of " + QString::number( LocaleID ) ); +#else + CONSOLE_Print( "[GHOST] unable to get system locale, using default locale of 1033" ); +#endif + } + CBNET *bnet = new CBNET( this, Server, ServerAlias, BNLSServer, (quint16)BNLSPort, (quint32)BNLSWardenCookie, CDKeyROC, CDKeyTFT, CountryAbbrev, Country, LocaleID, UserName, UserPassword, FirstChannel, RootAdmin, BNETCommandTrigger.at(0).toAscii(), HoldFriends, HoldClan, PublicCommands, War3Version, EXEVersion, EXEVersionHash, PasswordHashType, PVPGNRealmName, MaxMessageLength, i ); + QObject::connect(bnet, + SIGNAL(SignalBnetCommand(CBNET*, const QString&, const QString&, const QString&, bool)), + this, + SLOT(EventBnetCommand(CBNET*, const QString&, const QString&, const QString&, bool))); + m_BNETs.push_back( bnet ); + } + + if( m_BNETs.isEmpty( ) ) + CONSOLE_Print( "[GHOST] warning - no battle.net connections found in config file" ); + + // extract common.j and blizzard.j from War3Patch.mpq if we can + // these two files are necessary for calculating "map_crc" when loading maps so we make sure to do it before loading the default map + // see CMap :: Load for more information + + ExtractScripts( ); + + // load the default maps (note: make sure to run ExtractScripts first) + + if( m_DefaultMap.size( ) < 4 || m_DefaultMap.mid( m_DefaultMap.size( ) - 4 ) != ".cfg" ) + { + m_DefaultMap += ".cfg"; + CONSOLE_Print( "[GHOST] adding \".cfg\" to default map -> new default is [" + m_DefaultMap + "]" ); + } + + CConfig MapCFG; + MapCFG.Read( m_MapCFGPath + m_DefaultMap ); + m_Map = new CMap( this, MapCFG, m_MapCFGPath + m_DefaultMap ); + + if( !m_AdminGameMap.isEmpty( ) ) + { + if( m_AdminGameMap.size( ) < 4 || m_AdminGameMap.mid( m_AdminGameMap.size( ) - 4 ) != ".cfg" ) + { + m_AdminGameMap += ".cfg"; + CONSOLE_Print( "[GHOST] adding \".cfg\" to default admin game map -> new default is [" + m_AdminGameMap + "]" ); + } + + CONSOLE_Print( "[GHOST] trying to load default admin game map" ); + CConfig AdminMapCFG; + AdminMapCFG.Read( m_MapCFGPath + m_AdminGameMap ); + m_AdminMap = new CMap( this, AdminMapCFG, m_MapCFGPath + m_AdminGameMap ); + + if( !m_AdminMap->GetValid( ) ) + { + CONSOLE_Print( "[GHOST] default admin game map isn't valid, using hardcoded admin game map instead" ); + delete m_AdminMap; + m_AdminMap = new CMap( this ); + } + } + else + { + CONSOLE_Print( "[GHOST] using hardcoded admin game map" ); + m_AdminMap = new CMap( this ); + } + + m_AutoHostMap = new CMap( *m_Map ); + m_SaveGame = new CSaveGame( ); + + // load the iptocountry data + + LoadIPToCountryData( ); + + // create the admin game + + if( m_AdminGameCreate ) + { + CONSOLE_Print( "[GHOST] creating admin game" ); + m_AdminGame = new CAdminGame( this, m_AdminMap, NULL, m_AdminGamePort, 0, "GHost++ Admin Game", m_AdminGamePassword ); + QObject::connect(m_AdminGame, + SIGNAL(SignalPlayerCommand(CBaseGame*, CGamePlayer *, const QString &, const QString &)), + this, + SLOT(EventGameCommand(CBaseGame*, CGamePlayer *, const QString &, const QString &))); + QObject::connect(m_AdminGame, SIGNAL(destroyed()), this, SLOT(EventAdminGameDeleted())); + + if( m_AdminGamePort == m_HostPort ) + CONSOLE_Print( "[GHOST] warning - admingame_port and bot_hostport are set to the same value, you won't be able to host any games" ); + } + else + m_AdminGame = NULL; + + if( m_BNETs.isEmpty( ) && !m_AdminGame ) + CONSOLE_Print( "[GHOST] warning - no battle.net connections found and no admin game created" ); + +#ifdef GHOST_MYSQL + CONSOLE_Print( "[GHOST] GHost++ Version " + m_Version + " (with MySQL support)" ); +#else + CONSOLE_Print( "[GHOST] GHost++ Version " + m_Version + " (without MySQL support)" ); +#endif + + if( m_BNETs.isEmpty( ) ) + m_AutoHostTimer.start(0); + else + { + for (QList::const_iterator i = m_BNETs.begin(); i != m_BNETs.end(); ++i) + (*i)->socketConnect(); + } +} + +void CGHost :: LoadPlugin( QObject *plugin, CConfig *cfg ) +{ + bool validPlugin = false; + + IGHostPlugin *iPlugin = qobject_cast( plugin ); + if( !iPlugin ) + { + CONSOLE_Print( "[PLUGIN] ERROR: Plugin does not implement IGHostPlugin" ); + return; + } + + m_Plugins.append( iPlugin ); + + iPlugin->PluginLoaded(this, cfg); + + ICommandProvider *iCmd = qobject_cast( plugin ); + if( iCmd ) + { + CONSOLE_Print( "[PLUGIN] Found CommandProvider [" + iCmd->GetName() + "]" ); + validPlugin = true; + m_CommandProviders.append( iCmd ); + } + + ILogPlugin *iLogger = qobject_cast( plugin ); + if( iLogger ) + { + CONSOLE_Print( "[PLUGIN] Found Log plugin [" + iLogger->GetName() + "]" ); + validPlugin = true; + m_LogPlugins.append( iLogger ); + } + + iPlugin->AllPluginsLoaded( this, m_Plugins ); + + if( !validPlugin ) + CONSOLE_Print( "[PLUGIN] INFO: plugin did not contain any special interfaces" ); +} + +void CGHost :: LoadPlugins( QDir path, CConfig *cfg ) +{ + CONSOLE_Print( "[PLUGIN] Loading plugins from [" + path.absolutePath() + "]" ); + + foreach( QString fileName, path.entryList( QDir::Files ) ) { + QPluginLoader loader( path.absoluteFilePath( fileName ) ); + QObject *plugin = loader.instance(); + if( plugin ) + { + CONSOLE_Print( "[PLUGIN] Loading plugin [" + fileName + "]" ); + LoadPlugin( plugin, cfg ); + } + else + CONSOLE_Print( "[PLUGIN] Ignoring non-plugin file [" + fileName + "]" ); + } +} + +void CGHost::EventAdminGameDeleted() +{ + CONSOLE_Print("[GHOST] Admin Game has been deleted, quitting."); + m_AdminGame = NULL; + deleteLater(); +} + +CGHost :: ~CGHost( ) +{ + delete m_GPSProtocol; + delete m_CRC; + delete m_SHA; + + //qDeleteAll( m_BNETs ); + m_BNETs.clear( ); + + delete m_CurrentGame; + delete m_AdminGame; + + //qDeleteAll( m_Games ); + m_Games.clear( ); + + delete m_DB; + delete m_DBLocal; + + // warning: we don't delete any entries of m_Callables here because we can't be guaranteed that the associated threads have terminated + // this is fine if the program is currently exiting because the OS will clean up after us + // but if you try to recreate the CGHost object within a single session you will probably leak resources! + + if( !m_Callables.isEmpty( ) ) + CONSOLE_Print( "[GHOST] warning - " + QString::number( m_Callables.size( ) ) + " orphaned callables were leaked (this is not an error)" ); + + delete m_Language; + delete m_Map; + delete m_AdminMap; + delete m_AutoHostMap; + delete m_SaveGame; + + DEBUG_Print("[GHOST] good bye"); +} + +void CGHost::EventGameStarted() +{ + DEBUG_Print("EventGameStarted"); + // move the game to the games in progress vector + m_Games.push_back( m_CurrentGame ); + m_CurrentGame = NULL; + + // and finally reenter battle.net chat + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + (*i)->QueueGameUncreate( ); + (*i)->QueueEnterChat( ); + } + + m_AutoHostTimer.start(); +} + +void CGHost::EventIncomingReconnection() +{ + QTcpSocket *con = m_ReconnectSocket->nextPendingConnection(); + if (con == NULL) + return; + + QObject::connect(con, SIGNAL(readyRead()), this, SLOT(EventReconnectionSocketReadyRead())); +} + +void CGHost::EventReconnectionSocketReadyRead() +{ + QTcpSocket* con = (QTcpSocket*)QObject::sender(); + + // a packet is at least 4 bytes + if (con->bytesAvailable() < 4) + return; + + if( (unsigned char)con->peek(1).at(0) == GPS_HEADER_CONSTANT ) + { + // bytes 2 and 3 contain the length of the packet + + quint16 Length = Util::extractUInt16( con->peek(4), 2 ); + + if( Length < 4 ) + { + con->write( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_INVALID ) ); + con->deleteLater(); + return; + } + + if( con->bytesAvailable() < Length ) + return; + + QByteArray Bytes = con->read(Length); + if( Bytes.at(0) == CGPSProtocol :: GPS_RECONNECT && Length == 13 ) + { + unsigned char PID = Bytes.at(4); + quint32 ReconnectKey = Util::extractUInt32( Bytes, 5 ); + quint32 LastPacket = Util::extractUInt32( Bytes, 9 ); + + // look for a matching player in a running game + + CGamePlayer *Match = NULL; + + for( QList :: iterator j = m_Games.begin( ); j != m_Games.end( ); j++ ) + { + if( (*j)->GetGameLoaded( ) ) + { + CGamePlayer *Player = (*j)->GetPlayerFromPID( PID ); + + if( Player && Player->GetGProxy( ) && Player->GetGProxyReconnectKey( ) == ReconnectKey ) + { + Match = Player; + break; + } + } + } + + if( Match ) + { + // reconnect successful! + Match->EventGProxyReconnect( con, LastPacket ); + return; + } + else + { + con->write( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_NOTFOUND ) ); + con->deleteLater(); + return; + } + } + else + { + con->write( m_GPSProtocol->SEND_GPSS_REJECT( REJECTGPS_INVALID ) ); + con->deleteLater(); + return; + } + } +} + +void CGHost::EventCallableUpdateTimeout() +{ + // update callables + + for( QList :: iterator i = m_Callables.begin( ); i != m_Callables.end( ); ) + { + if( (*i)->GetReady( ) ) + { + m_DB->RecoverCallable( *i ); + delete *i; + i = m_Callables.erase( i ); + } + else + i++; + } +} + +void CGHost::EventDatabaseError(const QString &error) +{ + // todotodo: do we really want to shutdown if there's a database error? is there any way to recover from this? + if( QObject::sender() == m_DB ) + CONSOLE_Print( "[GHOST] database error - " + error ); + + else if (QObject::sender() == m_DBLocal) + CONSOLE_Print( "[GHOST] local database error - " + error ); + + deleteLater(); +} + +void CGHost::EventExitNice() +{ + m_ExitingNice = true; + + if( !m_BNETs.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] deleting all battle.net connections in preparation for exiting nicely" ); + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + delete *i; + + m_BNETs.clear( ); + } + + if( m_CurrentGame ) + { + CONSOLE_Print( "[GHOST] deleting current game in preparation for exiting nicely" ); + delete m_CurrentGame; + m_CurrentGame = NULL; + } + + if( m_AdminGame ) + { + CONSOLE_Print( "[GHOST] deleting admin game in preparation for exiting nicely" ); + delete m_AdminGame; + m_AdminGame = NULL; + } + + if( m_Games.isEmpty( ) ) + { + if( !m_AllGamesFinished && m_Callables.size( ) > 0 ) + { + CONSOLE_Print( "[GHOST] all games finished, waiting 60 seconds for threads to finish" ); + CONSOLE_Print( "[GHOST] there are " + QString::number( m_Callables.size( ) ) + " threads in progress" ); + m_AllGamesFinished = true; + m_AllGamesFinishedTime = GetTime( ); + QTimer::singleShot(60000, this, SLOT(EventWaitForNiceExitTimeout())); + } + else if( m_Callables.isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] all threads finished, exiting nicely" ); + deleteLater(); + QCoreApplication::instance()->quit(); + return; + } + } + + // try again in 2 seconds + QTimer::singleShot(2000, this, SLOT(EventExitNice())); +} + +void CGHost::EventWaitForNiceExitTimeout() +{ + CONSOLE_Print( "[GHOST] waited 60 seconds for threads to finish, exiting anyway" ); + CONSOLE_Print( "[GHOST] there are " + QString::number( m_Callables.size( ) ) + " threads still in progress which will be terminated" ); + deleteLater(); +} + +void CGHost::EventAutoHost() +{ + DEBUG_Print("EventAutoHost"); + // autohost + if( m_AutoHostGameName.isEmpty( ) || m_AutoHostMaximumGames == 0 || m_AutoHostAutoStartPlayers == 0 ) + return; + + // copy all the checks from CGHost :: CreateGame here because we don't want to spam the chat when there's an error + + if (m_CurrentGame) + DEBUG_Print("Not autohosting because a game is still open"); + + if (m_Games.size( ) >= m_MaxGames) + DEBUG_Print("Not autohosting because m_Games.size( ) >= m_MaxGames"); + + if (m_Games.size( ) >= m_AutoHostMaximumGames) + DEBUG_Print("Not autohosting because m_Games.size( ) >= m_AutoHostMaximumGames"); + + if( m_ExitingNice || !m_Enabled || m_CurrentGame || m_Games.size( ) >= m_MaxGames || m_Games.size( ) >= m_AutoHostMaximumGames ) + return; + + if( !m_AutoHostMap->GetValid( ) ) + { + CONSOLE_Print( "[GHOST] stopped auto hosting, map config file [" + m_AutoHostMap->GetCFGFile( ) + "] is invalid" ); + m_AutoHostGameName.clear( ); + m_AutoHostOwner.clear( ); + m_AutoHostServer.clear( ); + m_AutoHostMaximumGames = 0; + m_AutoHostAutoStartPlayers = 0; + m_AutoHostMatchMaking = false; + m_AutoHostMinimumScore = 0.0; + m_AutoHostMaximumScore = 0.0; + return; + } + + QString GameName = m_AutoHostGameName + " #" + QString::number( CBaseGame::GetCurrentHostCounter( ) ); + + if( GameName.size( ) >= 31 ) + { + CONSOLE_Print( "[GHOST] stopped auto hosting, next game name [" + GameName + "] is too long (the maximum is 31 characters)" ); + m_AutoHostGameName.clear( ); + m_AutoHostOwner.clear( ); + m_AutoHostServer.clear( ); + m_AutoHostMaximumGames = 0; + m_AutoHostAutoStartPlayers = 0; + m_AutoHostMatchMaking = false; + m_AutoHostMinimumScore = 0.0; + m_AutoHostMaximumScore = 0.0; + return; + } + + CreateGame( m_AutoHostMap, GAME_PUBLIC, false, GameName, m_AutoHostOwner, m_AutoHostOwner, m_AutoHostServer, false ); + + if( !m_CurrentGame ) + return; + + m_LastAutoHostTime.restart(); + m_CurrentGame->SetAutoStartPlayers( m_AutoHostAutoStartPlayers ); + + if( !m_AutoHostMatchMaking ) + return; + + if( m_Map->GetMapMatchMakingCategory( ).isEmpty( ) ) + { + CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory not found, matchmaking disabled" ); + return; + } + + if( !( m_Map->GetMapOptions( ) & MAPOPT_FIXEDPLAYERSETTINGS ) ) + { + CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory [" + m_Map->GetMapMatchMakingCategory( ) + "] found but matchmaking can only be used with fixed player settings, matchmaking disabled" ); + return; + } + + CONSOLE_Print( "[GHOST] autohostmm - map_matchmakingcategory [" + m_Map->GetMapMatchMakingCategory( ) + "] found, matchmaking enabled" ); + + m_CurrentGame->SetMatchMaking( true ); + m_CurrentGame->SetMinimumScore( m_AutoHostMinimumScore ); + m_CurrentGame->SetMaximumScore( m_AutoHostMaximumScore ); +} + +void CGHost::CreateReconnectServer() +{ + // create the GProxy++ reconnect listener + if( !m_ReconnectSocket ) + { + m_ReconnectSocket = new QTcpServer( this ); + QObject::connect(m_ReconnectSocket, SIGNAL(newConnection()), this, SLOT(EventIncomingReconnection())); + + if( m_ReconnectSocket->listen( QHostAddress(m_BindAddress), m_ReconnectPort ) ) + CONSOLE_Print( "[GHOST] listening for GProxy++ reconnects on port " + QString::number( m_ReconnectPort ) ); + else + { + CONSOLE_Print( "[GHOST] error listening for GProxy++ reconnects on port " + QString::number( m_ReconnectPort ) ); + delete m_ReconnectSocket; + m_ReconnectSocket = NULL; + m_Reconnect = false; + } + } + else if( !m_ReconnectSocket->isListening() ) + { + CONSOLE_Print( "[GHOST] GProxy++ reconnect listener error (" + m_ReconnectSocket->errorString() + ")" ); + delete m_ReconnectSocket; + m_ReconnectSocket = NULL; + m_Reconnect = false; + } +} + +void CGHost :: EventBNETConnecting( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->ConnectingToBNET( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->SendAllChat( m_Language->ConnectingToBNET( bnet->GetServer( ) ) ); +} + +void CGHost :: EventBNETConnected( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->ConnectedToBNET( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->SendAllChat( m_Language->ConnectedToBNET( bnet->GetServer( ) ) ); +} + +void CGHost :: EventBNETDisconnected( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->DisconnectedFromBNET( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->SendAllChat( m_Language->DisconnectedFromBNET( bnet->GetServer( ) ) ); +} + +void CGHost :: EventBNETLoggedIn( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->LoggedInToBNET( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->SendAllChat( m_Language->LoggedInToBNET( bnet->GetServer( ) ) ); +} + +void CGHost :: EventBNETGameRefreshed( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->BNETGameHostingSucceeded( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->EventGameRefreshed( bnet->GetServer( ) ); +} + +void CGHost :: EventBNETGameRefreshFailed( CBNET *bnet ) +{ + if( !m_CurrentGame ) + return; + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + (*i)->QueueChatCommand( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); + + if( (*i)->GetServer( ) == m_CurrentGame->GetCreatorServer( ) ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ), m_CurrentGame->GetCreatorName( ), true ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->BNETGameHostingFailed( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); + + m_CurrentGame->SendAllChat( m_Language->UnableToCreateGameTryAnotherName( bnet->GetServer( ), m_CurrentGame->GetGameName( ) ) ); + + // we take the easy route and simply close the lobby if a refresh fails + // it's possible at least one refresh succeeded and therefore the game is still joinable on at least one battle.net (plus on the local network) but we don't keep track of that + // we only close the game if it has no players since we support game rehosting (via !priv and !pub in the lobby) + + if( m_CurrentGame->GetNumHumanPlayers( ) == 0 ) + m_CurrentGame->deleteLater(); + + m_CurrentGame->EventRefreshError(); +} + +void CGHost :: EventBNETConnectTimedOut( CBNET *bnet ) +{ + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->ConnectingToBNETTimedOut( bnet->GetServer( ) ) ); + + if( m_CurrentGame ) + m_CurrentGame->SendAllChat( m_Language->ConnectingToBNETTimedOut( bnet->GetServer( ) ) ); +} + +void CGHost :: EventBNETWhisper( CBNET *bnet, const QString &user, const QString &message ) +{ + if( m_AdminGame ) + { + m_AdminGame->SendAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + if( m_CurrentGame ) + m_CurrentGame->SendLocalAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + for( QList :: const_iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) + (*i)->SendLocalAdminChat( "[W: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + } +} + +void CGHost :: EventBNETChat( CBNET *bnet, const QString &user, const QString &message ) +{ + if( m_AdminGame ) + { + m_AdminGame->SendAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + if( m_CurrentGame ) + m_CurrentGame->SendLocalAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + for( QList :: const_iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) + (*i)->SendLocalAdminChat( "[L: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + } +} + +void CGHost :: EventBNETEmote( CBNET *bnet, const QString &user, const QString &message ) +{ + if( m_AdminGame ) + { + m_AdminGame->SendAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + if( m_CurrentGame ) + m_CurrentGame->SendLocalAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + + for( QList :: const_iterator i = m_Games.begin( ); i != m_Games.end( ); i++ ) + (*i)->SendLocalAdminChat( "[E: " + bnet->GetServerAlias( ) + "] [" + user + "] " + message ); + } +} + +void CGHost::EventGameDeleted() +{ + CBaseGame *game = (CBaseGame *)QObject::sender(); + + if (game == m_CurrentGame) + m_CurrentGame = NULL; + + m_Games.removeOne(game); + + m_AutoHostTimer.start(); +} + +void CGHost :: ReloadConfigs( ) +{ + CConfig CFG; + CFG.Read( "default.cfg" ); + CFG.Read( m_ConfigFile ); + SetConfigs( &CFG ); +} + +void CGHost :: SetConfigs( CConfig *CFG ) +{ + // this doesn't set EVERY config value since that would potentially require reconfiguring the battle.net connections + // it just set the easily reloadable values + + m_LanguageFile = CFG->GetString( "bot_language", "language.cfg" ); + delete m_Language; + m_Language = new CLanguage( m_LanguageFile ); + m_Warcraft3Path = UTIL_AddPathSeparator( CFG->GetString( "bot_war3path", "C:\\Program Files\\Warcraft III\\" ) ).toAscii(); + m_BindAddress = CFG->GetString( "bot_bindaddress", QString( ) ); + m_ReconnectWaitTime = CFG->GetInt( "bot_reconnectwaittime", 3 ); + m_MaxGames = CFG->GetInt( "bot_maxgames", 5 ); + QString BotCommandTrigger = CFG->GetString( "bot_commandtrigger", "!" ); + + if( BotCommandTrigger.isEmpty( ) ) + BotCommandTrigger = "!"; + + m_CommandTrigger = BotCommandTrigger[0].toAscii(); + m_MapCFGPath = UTIL_AddPathSeparator( CFG->GetString( "bot_mapcfgpath", QString( ) ) ); + m_SaveGamePath = UTIL_AddPathSeparator( CFG->GetString( "bot_savegamepath", QString( ) ) ); + m_MapPath = UTIL_AddPathSeparator( CFG->GetString( "bot_mappath", QString( ) ) ); + m_SaveReplays = CFG->GetInt( "bot_savereplays", 0 ) == 0 ? false : true; + m_ReplayPath = UTIL_AddPathSeparator( CFG->GetString( "bot_replaypath", QString( ) ) ); + m_VirtualHostName = CFG->GetString( "bot_virtualhostname", "|cFF4080C0GHost" ); + m_HideIPAddresses = CFG->GetInt( "bot_hideipaddresses", 0 ) == 0 ? false : true; + m_CheckMultipleIPUsage = CFG->GetInt( "bot_checkmultipleipusage", 1 ) == 0 ? false : true; + + if( m_VirtualHostName.size( ) > 15 ) + { + m_VirtualHostName = "|cFF4080C0GHost"; + CONSOLE_Print( "[GHOST] warning - bot_virtualhostname is longer than 15 characters, using default virtual host name" ); + } + + m_SpoofChecks = CFG->GetInt( "bot_spoofchecks", 2 ); + m_RequireSpoofChecks = CFG->GetInt( "bot_requirespoofchecks", 0 ) == 0 ? false : true; + m_ReserveAdmins = CFG->GetInt( "bot_reserveadmins", 1 ) == 0 ? false : true; + m_RefreshMessages = CFG->GetInt( "bot_refreshmessages", 0 ) == 0 ? false : true; + m_AutoLock = CFG->GetInt( "bot_autolock", 0 ) == 0 ? false : true; + m_AutoSave = CFG->GetInt( "bot_autosave", 0 ) == 0 ? false : true; + m_AllowDownloads = CFG->GetInt( "bot_allowdownloads", 0 ); + m_PingDuringDownloads = CFG->GetInt( "bot_pingduringdownloads", 0 ) == 0 ? false : true; + m_MaxDownloaders = CFG->GetInt( "bot_maxdownloaders", 3 ); + m_MaxDownloadSpeed = CFG->GetInt( "bot_maxdownloadspeed", 100 ); + m_LCPings = CFG->GetInt( "bot_lcpings", 1 ) == 0 ? false : true; + m_AutoKickPing = CFG->GetInt( "bot_autokickping", 400 ); + m_BanMethod = CFG->GetInt( "bot_banmethod", 1 ); + m_IPBlackListFile = CFG->GetString( "bot_ipblacklistfile", "ipblacklist.txt" ); + m_LobbyTimeLimit = CFG->GetInt( "bot_lobbytimelimit", 10 ); + m_Latency = CFG->GetInt( "bot_latency", 100 ); + m_SyncLimit = CFG->GetInt( "bot_synclimit", 50 ); + m_VoteKickAllowed = CFG->GetInt( "bot_votekickallowed", 1 ) == 0 ? false : true; + m_VoteKickPercentage = CFG->GetInt( "bot_votekickpercentage", 100 ); + + if( m_VoteKickPercentage > 100 ) + { + m_VoteKickPercentage = 100; + CONSOLE_Print( "[GHOST] warning - bot_votekickpercentage is greater than 100, using 100 instead" ); + } + + m_MOTDFile = CFG->GetString( "bot_motdfile", "motd.txt" ); + m_GameLoadedFile = CFG->GetString( "bot_gameloadedfile", "gameloaded.txt" ); + m_GameOverFile = CFG->GetString( "bot_gameoverfile", "gameover.txt" ); + m_LocalAdminMessages = CFG->GetInt( "bot_localadminmessages", 1 ) == 0 ? false : true; + m_TCPNoDelay = CFG->GetInt( "tcp_nodelay", 0 ) == 0 ? false : true; + m_MatchMakingMethod = CFG->GetInt( "bot_matchmakingmethod", 1 ); +} + +void CGHost :: ExtractScripts( ) +{/* + QString PatchMPQFileName = m_Warcraft3Path + "War3Patch.mpq"; + HANDLE PatchMPQ; + + if( SFileOpenArchive( PatchMPQFileName.toUtf8().data( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &PatchMPQ ) ) + { + CONSOLE_Print( "[GHOST] loading MPQ file [" + PatchMPQFileName + "]" ); + HANDLE SubFile; + + // common.j + + if( SFileOpenFileEx( PatchMPQ, "Scripts\\common.j", 0, &SubFile ) ) + { + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); + + if( FileLength > 0 && FileLength != 0xFFFFFFFF ) + { + char *SubFileData = new char[FileLength]; + DWORD BytesRead = 0; + + if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) + { + CONSOLE_Print( "[GHOST] extracting Scripts\\common.j from MPQ file to [" + m_MapCFGPath + "common.j]" ); + UTIL_FileWrite( m_MapCFGPath + "common.j", QByteArray(SubFileData, BytesRead) ); + } + else + CONSOLE_Print( "[GHOST] warning - unable to extract Scripts\\common.j from MPQ file" ); + + delete [] SubFileData; + } + + SFileCloseFile( SubFile ); + } + else + CONSOLE_Print( "[GHOST] couldn't find Scripts\\common.j in MPQ file" ); + + // blizzard.j + + if( SFileOpenFileEx( PatchMPQ, "Scripts\\blizzard.j", 0, &SubFile ) ) + { + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); + + if( FileLength > 0 && FileLength != 0xFFFFFFFF ) + { + char *SubFileData = new char[FileLength]; + DWORD BytesRead = 0; + + if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) ) + { + CONSOLE_Print( "[GHOST] extracting Scripts\\blizzard.j from MPQ file to [" + m_MapCFGPath + "blizzard.j]" ); + UTIL_FileWrite( m_MapCFGPath + "blizzard.j", QByteArray(SubFileData, BytesRead) ); + } + else + CONSOLE_Print( "[GHOST] warning - unable to extract Scripts\\blizzard.j from MPQ file" ); + + delete [] SubFileData; + } + + SFileCloseFile( SubFile ); + } + else + CONSOLE_Print( "[GHOST] couldn't find Scripts\\blizzard.j in MPQ file" ); + + SFileCloseArchive( PatchMPQ ); + } + else + CONSOLE_Print( "[GHOST] warning - unable to load MPQ file [" + PatchMPQFileName + "] - error code " + QString::number( GetLastError( ) ) );*/ +} + +void CGHost :: LoadIPToCountryData( ) +{ + QFile f("ip-to-country.csv"); + f.open(QFile::ReadOnly); + QTextStream in(&f); + + if( f.error() != QFile::NoError ) + CONSOLE_Print( "[GHOST] warning - unable to read file [ip-to-country.csv], iptocountry data not loaded" ); + else + { + CONSOLE_Print( "[GHOST] started loading [ip-to-country.csv]" ); + + // the begin and commit statements are optimizations + // we're about to insert ~4 MB of data into the database so if we allow the database to treat each insert as a transaction it will take a LONG time + // todotodo: handle begin/commit failures a bit more gracefully + + if( !m_DBLocal->Begin( ) ) + CONSOLE_Print( "[GHOST] warning - failed to begin local database transaction, iptocountry data not loaded" ); + else + { + unsigned char Percent = 0; + QString Line; + QString IP1; + QString IP2; + QString Country; + CSVParser parser; + + // get length of file for the progress meter + + quint32 FileLength = f.size(); + + while( !in.atEnd( ) ) + { + Line = in.readLine(); + + if( Line.isEmpty( ) ) + continue; + + parser << Line; + parser >> IP1; + parser >> IP2; + parser >> Country; + m_DBLocal->FromAdd( IP1.toUInt(), IP2.toUInt(), Country ); + + // it's probably going to take awhile to load the iptocountry data (~10 seconds on my 3.2 GHz P4 when using SQLite3) + // so let's print a progress meter just to keep the user from getting worried + + unsigned char NewPercent = (unsigned char)( (float)f.pos() / FileLength * 100 ); + + if( NewPercent != Percent && NewPercent % 10 == 0 ) + { + Percent = NewPercent; + CONSOLE_Print( "[GHOST] iptocountry data: " + QString::number( Percent ) + "% loaded" ); + } + } + + if( !m_DBLocal->Commit( ) ) + CONSOLE_Print( "[GHOST] warning - failed to commit local database transaction, iptocountry data not loaded" ); + else + CONSOLE_Print( "[GHOST] finished loading [ip-to-country.csv]" ); + } + + f.close( ); + } +} + +void CGHost :: CreateGame( CMap *map, unsigned char gameState, bool saveGame, const QString &gameName, const QString &ownerName, const QString &creatorName, const QString &creatorServer, bool whisper ) +{ + if( !m_Enabled ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameDisabled( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameDisabled( gameName ) ); + + return; + } + + if( gameName.size( ) > 31 ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameNameTooLong( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameNameTooLong( gameName ) ); + + return; + } + + if( !map->GetValid( ) ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameInvalidMap( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameInvalidMap( gameName ) ); + + return; + } + + if( saveGame ) + { + if( !m_SaveGame->GetValid( ) ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameInvalidSaveGame( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameInvalidSaveGame( gameName ) ); + + return; + } + + QString MapPath1 = m_SaveGame->GetMapPath( ).toLower(); + QString MapPath2 = map->GetMapPath( ); + MapPath2 = MapPath2.toLower(); + + if( MapPath1 != MapPath2 ) + { + CONSOLE_Print( "[GHOST] path mismatch, saved game path is [" + MapPath1 + "] but map path is [" + MapPath2 + "]" ); + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameSaveGameMapMismatch( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameSaveGameMapMismatch( gameName ) ); + + return; + } + + if( m_EnforcePlayers.isEmpty( ) ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameMustEnforceFirst( gameName ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameMustEnforceFirst( gameName ) ); + + return; + } + } + + if( m_CurrentGame ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameAnotherGameInLobby( gameName, m_CurrentGame->GetDescription( ) ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameAnotherGameInLobby( gameName, m_CurrentGame->GetDescription( ) ) ); + + return; + } + + if( m_Games.size( ) >= m_MaxGames ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetServer( ) == creatorServer ) + (*i)->QueueChatCommand( m_Language->UnableToCreateGameMaxGamesReached( gameName, QString::number( m_MaxGames ) ), creatorName, whisper ); + } + + if( m_AdminGame ) + m_AdminGame->SendAllChat( m_Language->UnableToCreateGameMaxGamesReached( gameName, QString::number( m_MaxGames ) ) ); + + return; + } + + CONSOLE_Print( "[GHOST] creating game [" + gameName + "]" ); + + if( saveGame ) + m_CurrentGame = new CGame( this, map, m_SaveGame, m_HostPort, gameState, gameName, ownerName, creatorName, creatorServer ); + else + m_CurrentGame = new CGame( this, map, NULL, m_HostPort, gameState, gameName, ownerName, creatorName, creatorServer ); + + QObject::connect(m_CurrentGame, + SIGNAL(SignalPlayerCommand(CBaseGame*, CGamePlayer *, const QString &, const QString &)), + this, + SLOT(EventGameCommand(CBaseGame*, CGamePlayer *, const QString &, const QString &))); + QObject::connect(m_CurrentGame, SIGNAL(startedLoading()), this, SLOT(EventGameStarted())); + QObject::connect(m_CurrentGame, SIGNAL(destroyed()), this, SLOT(EventGameDeleted())); + + // todotodo: check if listening failed and report the error to the user + + if( m_SaveGame ) + { + m_CurrentGame->SetEnforcePlayers( m_EnforcePlayers ); + m_EnforcePlayers.clear( ); + } + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( whisper && (*i)->GetServer( ) == creatorServer ) + { + // note that we send this whisper only on the creator server + + if( gameState == GAME_PRIVATE ) + (*i)->QueueChatCommand( m_Language->CreatingPrivateGame( gameName, ownerName ), creatorName, whisper ); + else if( gameState == GAME_PUBLIC ) + (*i)->QueueChatCommand( m_Language->CreatingPublicGame( gameName, ownerName ), creatorName, whisper ); + } + else + { + // note that we send this chat message on all other bnet servers + + if( gameState == GAME_PRIVATE ) + (*i)->QueueChatCommand( m_Language->CreatingPrivateGame( gameName, ownerName ) ); + else if( gameState == GAME_PUBLIC ) + (*i)->QueueChatCommand( m_Language->CreatingPublicGame( gameName, ownerName ) ); + } + + if( saveGame ) + (*i)->QueueGameCreate( gameState, gameName, QString( ), map, m_SaveGame, m_CurrentGame->GetHostCounter( ) ); + else + (*i)->QueueGameCreate( gameState, gameName, QString( ), map, NULL, m_CurrentGame->GetHostCounter( ) ); + } + + if( m_AdminGame ) + { + if( gameState == GAME_PRIVATE ) + m_AdminGame->SendAllChat( m_Language->CreatingPrivateGame( gameName, ownerName ) ); + else if( gameState == GAME_PUBLIC ) + m_AdminGame->SendAllChat( m_Language->CreatingPublicGame( gameName, ownerName ) ); + } + + // if we're creating a private game we don't need to send any game refresh messages so we can rejoin the chat immediately + // unfortunately this doesn't work on PVPGN servers because they consider an enterchat message to be a gameuncreate message when in a game + // so don't rejoin the chat if we're using PVPGN + + if( gameState == GAME_PRIVATE ) + { + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetPasswordHashType( ) != "pvpgn" ) + (*i)->QueueEnterChat( ); + } + } + + // hold friends and/or clan members + + for( QList :: const_iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); i++ ) + { + if( (*i)->GetHoldFriends( ) ) + (*i)->HoldFriends( m_CurrentGame ); + + if( (*i)->GetHoldClan( ) ) + (*i)->HoldClan( m_CurrentGame ); + } +} diff --git a/src/libghost/ghost.h b/src/libghost/ghost.h new file mode 100644 index 0000000..dff00c5 --- /dev/null +++ b/src/libghost/ghost.h @@ -0,0 +1,249 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GHOST_H +#define GHOST_H + +#include "includes.h" + +#include +#include +#include +#include +#include + +// +// CGHost +// + +class CGPSProtocol; +class CCRC32; +class CSHA1; +class CBNET; +class CBaseGame; +class CGame; +class CAdminGame; +class CGHostDB; +class CBaseCallable; +class CLanguage; +class CMap; +class CSaveGame; +class CConfig; +class CGHostPrivate; +class CGamePlayer; +class IGHostPlugin; +class ICommandProvider; +class ILogPlugin; + +QT_FORWARD_DECLARE_CLASS(QDir) +QT_FORWARD_DECLARE_CLASS(QUdpSocket) +QT_FORWARD_DECLARE_CLASS(QTcpServer) + +class CGHost : public QObject +{ + Q_OBJECT +public: + CGame *GetCurrentGame( ) const; + CAdminGame *GetAdminGame( ) const; + CLanguage *GetLanguage( ) const; + CMap *GetCurrentMap( ) const; + void SetCurrentMap( CMap *map); + CMap *GetAdminMap( ) const; + CMap *GetAutoHostMap( ) const; + void SetAutoHostMap( CMap *map ); + bool GetExiting( ) const { return m_Exiting; } + bool GetExitingNice( ) const { return m_ExitingNice; } + void ExitNice( ); + void Exit( ); + + bool IsGameCreationEnabled( ) const { return m_Enabled; } + void EnableGameCreation( ) { m_Enabled = true; } + void DisableGameCreation( ) { m_Enabled = false; } + + void SendUdpBroadcast( const QByteArray &data, const quint16 &port, const QHostAddress& target); + void SendUdpBroadcast( const QByteArray &data, const quint16 &port); + void SendUdpBroadcast( const QByteArray &data); + + void LoadSavegame( const QString& path ); + + const CGPSProtocol &GetGPSProtocol( ) { return *m_GPSProtocol; } + + const QString &GetVersion( ) { return m_Version; } + +private: /*** Plugins ***/ + QList m_Plugins; + QList m_CommandProviders; + QList m_LogPlugins; + void LoadPlugins( QDir path, CConfig *cfg ); +public: + void LoadPlugin( QObject *plugin, CConfig *cfg ); + +private: /*** Logging ***/ + void Log( const QString &message, int level ); +public: + void LogInfo( const QString &message ); + void LogWarning( const QString &message ); + void LogError( const QString &message ); + +// slots for game events +public slots: + void EventGameStarted(); + void EventGameDeleted(); + void EventGameCommand( CBaseGame *game, CGamePlayer *player, const QString &command, const QString &payload ); + void EventBnetCommand( CBNET *bnet, const QString &user, const QString &command, const QString &payload, bool whisper ); +protected: + QScopedPointer d_ptr; +private: + Q_DECLARE_PRIVATE(CGHost) + CGame *m_CurrentGame; // this game is still in the lobby state + CAdminGame *m_AdminGame; // this "fake game" allows an admin who knows the password to control the bot from the local network + CLanguage *m_Language; // language + CMap *m_Map; // the currently loaded map + CMap *m_AdminMap; // the map to use in the admin game + CMap *m_AutoHostMap; // the map to use when autohosting + + + +public slots: + void EventIncomingReconnection(); + void EventReconnectionSocketReadyRead(); + void EventCallableUpdateTimeout(); + void EventDatabaseError(const QString &error); + void EventExitNice(); + void EventWaitForNiceExitTimeout(); + void EventAutoHost(); + void EventAdminGameDeleted(); + void CreateReconnectServer(); + +private: + QTime m_LastAutoHostTime; + QUdpSocket *m_UDPSocket; // a UDP socket for sending broadcasts and other junk (used with !sendlan) + QHostAddress m_BroadcastTarget; + QTcpServer *m_ReconnectSocket; // listening socket for GProxy++ reliable reconnects + CGPSProtocol *m_GPSProtocol; + bool m_Exiting; // set to true to force ghost to shutdown next update (used by SignalCatcher) + bool m_ExitingNice; // set to true to force ghost to disconnect from all battle.net connections and wait for all games to finish before shutting down + bool m_Enabled; // set to false to prevent new games from being created + QString m_Version; // GHost++ version QString + QTimer m_CallableUpdateTimer, m_AutoHostTimer; + CSaveGame *m_SaveGame; // the save game to use + +public: + CCRC32 *m_CRC; // for calculating CRC's + CSHA1 *m_SHA; // for calculating SHA1's + QList m_BNETs; // all our battle.net connections (there can be more than one) + QList m_Games; // these games are in progress + CGHostDB *m_DB; // database + CGHostDB *m_DBLocal; // local database (for temporary data) + QList m_Callables; // vector of orphaned callables waiting to die + QList m_LocalAddresses; // vector of local IP addresses + QList m_EnforcePlayers; // vector of pids to force players to use in the next game (used with saved games) + + + QString m_AutoHostGameName; // the base game name to auto host with + QString m_AutoHostOwner; + QString m_AutoHostServer; + int m_AutoHostMaximumGames; // maximum number of games to auto host + quint32 m_AutoHostAutoStartPlayers; // when using auto hosting auto start the game when this many players have joined + bool m_AutoHostMatchMaking; + double m_AutoHostMinimumScore; + double m_AutoHostMaximumScore; + bool m_AllGamesFinished; // if all games finished (used when exiting nicely) + quint32 m_AllGamesFinishedTime; // GetTime when all games finished (used when exiting nicely) + QString m_LanguageFile; // config value: language file + QByteArray m_Warcraft3Path; // config value: Warcraft 3 path + bool m_TFT; // config value: TFT enabled or not + QString m_BindAddress; // config value: the address to host games on + quint16 m_HostPort; // config value: the port to host games on + bool m_Reconnect; // config value: GProxy++ reliable reconnects enabled or not + quint16 m_ReconnectPort; // config value: the port to listen for GProxy++ reliable reconnects on + quint32 m_ReconnectWaitTime; // config value: the maximum number of minutes to wait for a GProxy++ reliable reconnect + int m_MaxGames; // config value: maximum number of games in progress + char m_CommandTrigger; // config value: the command trigger inside games + QString m_MapCFGPath; // config value: map cfg path + QString m_SaveGamePath; // config value: savegame path + QString m_MapPath; // config value: map path + bool m_SaveReplays; // config value: save replays + QString m_ReplayPath; // config value: replay path + QString m_VirtualHostName; // config value: virtual host name + bool m_HideIPAddresses; // config value: hide IP addresses from players + bool m_CheckMultipleIPUsage; // config value: check for multiple IP address usage + quint32 m_SpoofChecks; // config value: do automatic spoof checks or not + bool m_RequireSpoofChecks; // config value: require spoof checks or not + bool m_ReserveAdmins; // config value: consider admins to be reserved players or not + bool m_RefreshMessages; // config value: display refresh messages or not (by default) + bool m_AutoLock; // config value: auto lock games when the owner is present + bool m_AutoSave; // config value: auto save before someone disconnects + quint32 m_AllowDownloads; // config value: allow map downloads or not + bool m_PingDuringDownloads; // config value: ping during map downloads or not + quint32 m_MaxDownloaders; // config value: maximum number of map downloaders at the same time + quint32 m_MaxDownloadSpeed; // config value: maximum total map download speed in KB/sec + bool m_LCPings; // config value: use LC style pings (divide actual pings by two) + quint32 m_AutoKickPing; // config value: auto kick players with ping higher than this + quint32 m_BanMethod; // config value: ban method (ban by name/ip/both) + QString m_IPBlackListFile; // config value: IP blacklist file (ipblacklist.txt) + quint32 m_LobbyTimeLimit; // config value: auto close the game lobby after this many minutes without any reserved players + quint32 m_Latency; // config value: the latency (by default) + quint32 m_SyncLimit; // config value: the maximum number of packets a player can fall out of sync before starting the lag screen (by default) + bool m_VoteKickAllowed; // config value: if votekicks are allowed or not + quint32 m_VoteKickPercentage; // config value: percentage of players required to vote yes for a votekick to pass + QString m_DefaultMap; // config value: default map (map.cfg) + QString m_MOTDFile; // config value: motd.txt + QString m_GameLoadedFile; // config value: gameloaded.txt + QString m_GameOverFile; // config value: gameover.txt + bool m_LocalAdminMessages; // config value: send local admin messages or not + bool m_AdminGameCreate; // config value: create the admin game or not + quint16 m_AdminGamePort; // config value: the port to host the admin game on + QString m_AdminGamePassword; // config value: the admin game password + QString m_AdminGameMap; // config value: the admin game map config to use + unsigned char m_LANWar3Version; // config value: LAN warcraft 3 version + quint32 m_ReplayWar3Version; // config value: replay warcraft 3 version (for saving replays) + quint32 m_ReplayBuildNumber; // config value: replay build number (for saving replays) + bool m_TCPNoDelay; // config value: use Nagle's algorithm or not + quint32 m_MatchMakingMethod; // config value: the matchmaking method + QString m_ConfigFile; + + CGHost( CConfig *CFG, QString configFile ); + ~CGHost( ); + + // events + + void EventBNETConnecting( CBNET *bnet ); + void EventBNETConnected( CBNET *bnet ); + void EventBNETDisconnected( CBNET *bnet ); + void EventBNETLoggedIn( CBNET *bnet ); + void EventBNETGameRefreshed( CBNET *bnet ); + void EventBNETGameRefreshFailed( CBNET *bnet ); + void EventBNETConnectTimedOut( CBNET *bnet ); + void EventBNETWhisper( CBNET *bnet, const QString &user, const QString &message ); + void EventBNETChat( CBNET *bnet, const QString &user, const QString &message ); + void EventBNETEmote( CBNET *bnet, const QString &user, const QString &message ); +// void EventGameDeleted( CBaseGame *game ); + + // other functions + + void ReloadConfigs( ); + void SetConfigs( CConfig *CFG ); + void ExtractScripts( ); + void LoadIPToCountryData( ); + void CreateGame( CMap *map, unsigned char gameState, bool saveGame, const QString &gameName, const QString &ownerName, const QString &creatorName, const QString &creatorServer, bool whisper ); +}; + +#endif diff --git a/ghost/ghost.vcproj b/src/libghost/ghost.vcproj similarity index 100% rename from ghost/ghost.vcproj rename to src/libghost/ghost.vcproj diff --git a/src/libghost/ghost_p.h b/src/libghost/ghost_p.h new file mode 100644 index 0000000..ba7b97c --- /dev/null +++ b/src/libghost/ghost_p.h @@ -0,0 +1,29 @@ +/* + * ghost_p.h + * ghost + * + * Created by Lucas on 14.05.10. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef GHOST_P_H +#define GHOST_P_H + +class ICommandProvider; + +// +// W A R N I N G +// ------------- +// +// This file is not part of the GHost API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// + +class CGHostPrivate +{ +public: +}; + +#endif diff --git a/src/libghost/ghostdb.cpp b/src/libghost/ghostdb.cpp new file mode 100644 index 0000000..95b1dc5 --- /dev/null +++ b/src/libghost/ghostdb.cpp @@ -0,0 +1,630 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "config.h" +#include "ghostdb.h" + +#include + +// +// CGHostDB +// + +CGHostDB :: CGHostDB( CConfig */*CFG*/ ) +{ + m_HasError = false; +} + +CGHostDB :: ~CGHostDB( ) +{ + +} + +void CGHostDB::SetError(const QString &sError) +{ + m_Error = sError; + m_HasError = true; + emit error(m_Error); +} + +void CGHostDB :: RecoverCallable( CBaseCallable */*callable*/ ) +{ + +} + +bool CGHostDB :: Begin( ) +{ + return true; +} + +bool CGHostDB :: Commit( ) +{ + return true; +} + +quint32 CGHostDB :: AdminCount( QString /*server*/ ) +{ + return 0; +} + +bool CGHostDB :: AdminCheck( QString /*server*/, QString /*user*/ ) +{ + return false; +} + +bool CGHostDB :: AdminAdd( QString /*server*/, QString /*user*/ ) +{ + return false; +} + +bool CGHostDB :: AdminRemove( QString /*server*/, QString /*user*/ ) +{ + return false; +} + +QList CGHostDB :: AdminList( QString /*server*/ ) +{ + return QList( ); +} + +quint32 CGHostDB :: BanCount( QString /*server*/ ) +{ + return 0; +} + +CDBBan *CGHostDB :: BanCheck( QString /*server*/, QString /*user*/, QString /*ip*/ ) +{ + return NULL; +} + +bool CGHostDB :: BanAdd( QString /*server*/, QString /*user*/, QString /*ip*/, QString /*gamename*/, QString /*admin*/, QString /*reason*/ ) +{ + return false; +} + +bool CGHostDB :: BanRemove( QString /*server*/, QString /*user*/ ) +{ + return false; +} + +bool CGHostDB :: BanRemove( QString /*user*/ ) +{ + return false; +} + +QList CGHostDB :: BanList( QString /*server*/ ) +{ + return QList( ); +} + +quint32 CGHostDB :: GameAdd( QString /*server*/, QString /*map*/, QString /*gamename*/, QString /*ownername*/, quint32 /*duration*/, quint32 /*gamestate*/, QString /*creatorname*/, QString /*creatorserver*/ ) +{ + return 0; +} + +quint32 CGHostDB :: GamePlayerAdd( quint32 /*gameid*/, QString /*name*/, QString /*ip*/, quint32 /*spoofed*/, QString /*spoofedrealm*/, quint32 /*reserved*/, quint32 /*loadingtime*/, quint32 /*left*/, QString /*leftreason*/, quint32 /*team*/, quint32 /*colour*/ ) +{ + return 0; +} + +quint32 CGHostDB :: GamePlayerCount( QString /*name*/ ) +{ + return 0; +} + +CDBGamePlayerSummary *CGHostDB :: GamePlayerSummaryCheck( QString /*name*/ ) +{ + return NULL; +} + +quint32 CGHostDB :: DotAGameAdd( quint32 /*gameid*/, quint32 /*winner*/, quint32 /*min*/, quint32 /*sec*/ ) +{ + return 0; +} + +quint32 CGHostDB :: DotAPlayerAdd( quint32 /*gameid*/, quint32 /*colour*/, quint32 /*kills*/, quint32 /*deaths*/, quint32 /*creepkills*/, quint32 /*creepdenies*/, quint32 /*assists*/, quint32 /*gold*/, quint32 /*neutralkills*/, QString /*item1*/, QString /*item2*/, QString /*item3*/, QString /*item4*/, QString /*item5*/, QString /*item6*/, QString /*hero*/, quint32 /*newcolour*/, quint32 /*towerkills*/, quint32 /*raxkills*/, quint32 /*courierkills*/ ) +{ + return 0; +} + +quint32 CGHostDB :: DotAPlayerCount( QString /*name*/ ) +{ + return 0; +} + +CDBDotAPlayerSummary *CGHostDB :: DotAPlayerSummaryCheck( QString /*name*/ ) +{ + return NULL; +} + +QString CGHostDB :: FromCheck( quint32 /*ip*/ ) +{ + return "??"; +} + +bool CGHostDB :: FromAdd( quint32 /*ip1*/, quint32 /*ip2*/, QString /*country*/ ) +{ + return false; +} + +bool CGHostDB :: DownloadAdd( QString /*map*/, quint32 /*mapsize*/, QString /*name*/, QString /*ip*/, quint32 /*spoofed*/, QString /*spoofedrealm*/, quint32 /*downloadtime*/ ) +{ + return false; +} + +quint32 CGHostDB :: W3MMDPlayerAdd( QString /*category*/, quint32 /*gameid*/, quint32 /*pid*/, QString /*name*/, QString /*flag*/, quint32 /*leaver*/, quint32 /*practicing*/ ) +{ + return 0; +} + +bool CGHostDB :: W3MMDVarAdd( quint32 /*gameid*/, QMap /*var_ints*/ ) +{ + return false; +} + +bool CGHostDB :: W3MMDVarAdd( quint32 /*gameid*/, QMap /*var_reals*/ ) +{ + return false; +} + +bool CGHostDB :: W3MMDVarAdd( quint32 /*gameid*/, QMap /*var_strings*/ ) +{ + return false; +} + +void CGHostDB :: CreateThread( CBaseCallable *callable ) +{ + callable->SetReady( true ); +} + +CCallableAdminCount *CGHostDB :: ThreadedAdminCount( QString /*server*/ ) +{ + return NULL; +} + +CCallableAdminCheck *CGHostDB :: ThreadedAdminCheck( QString /*server*/, QString /*user*/ ) +{ + return NULL; +} + +CCallableAdminAdd *CGHostDB :: ThreadedAdminAdd( QString /*server*/, QString /*user*/ ) +{ + return NULL; +} + +CCallableAdminRemove *CGHostDB :: ThreadedAdminRemove( QString /*server*/, QString /*user*/ ) +{ + return NULL; +} + +CCallableAdminList *CGHostDB :: ThreadedAdminList( QString /*server*/ ) +{ + return NULL; +} + +CCallableBanCount *CGHostDB :: ThreadedBanCount( QString /*server*/ ) +{ + return NULL; +} + +CCallableBanCheck *CGHostDB :: ThreadedBanCheck( QString /*server*/, QString /*user*/, QString /*ip*/ ) +{ + return NULL; +} + +CCallableBanAdd *CGHostDB :: ThreadedBanAdd( QString /*server*/, QString /*user*/, QString /*ip*/, QString /*gamename*/, QString /*admin*/, QString /*reason*/ ) +{ + return NULL; +} + +CCallableBanRemove *CGHostDB :: ThreadedBanRemove( QString /*server*/, QString /*user*/ ) +{ + return NULL; +} + +CCallableBanRemove *CGHostDB :: ThreadedBanRemove( QString /*user*/ ) +{ + return NULL; +} + +CCallableBanList *CGHostDB :: ThreadedBanList( QString /*server*/ ) +{ + return NULL; +} + +CCallableGameAdd *CGHostDB :: ThreadedGameAdd( QString /*server*/, QString /*map*/, QString /*gamename*/, QString /*ownername*/, quint32 /*duration*/, quint32 /*gamestate*/, QString /*creatorname*/, QString /*creatorserver*/ ) +{ + return NULL; +} + +CCallableGamePlayerAdd *CGHostDB :: ThreadedGamePlayerAdd( quint32 /*gameid*/, QString /*name*/, QString /*ip*/, quint32 /*spoofed*/, QString /*spoofedrealm*/, quint32 /*reserved*/, quint32 /*loadingtime*/, quint32 /*left*/, QString /*leftreason*/, quint32 /*team*/, quint32 /*colour*/ ) +{ + return NULL; +} + +CCallableGamePlayerSummaryCheck *CGHostDB :: ThreadedGamePlayerSummaryCheck( QString /*name*/ ) +{ + return NULL; +} + +CCallableDotAGameAdd *CGHostDB :: ThreadedDotAGameAdd( quint32 /*gameid*/, quint32 /*winner*/, quint32 /*min*/, quint32 /*sec*/ ) +{ + return NULL; +} + +CCallableDotAPlayerAdd *CGHostDB :: ThreadedDotAPlayerAdd( quint32 /*gameid*/, quint32 /*colour*/, quint32 /*kills*/, quint32 /*deaths*/, quint32 /*creepkills*/, quint32 /*creepdenies*/, quint32 /*assists*/, quint32 /*gold*/, quint32 /*neutralkills*/, QString /*item1*/, QString /*item2*/, QString /*item3*/, QString /*item4*/, QString /*item5*/, QString /*item6*/, QString /*hero*/, quint32 /*newcolour*/, quint32 /*towerkills*/, quint32 /*raxkills*/, quint32 /*courierkills*/ ) +{ + return NULL; +} + +CCallableDotAPlayerSummaryCheck *CGHostDB :: ThreadedDotAPlayerSummaryCheck( QString /*name*/ ) +{ + return NULL; +} + +CCallableDownloadAdd *CGHostDB :: ThreadedDownloadAdd( QString /*map*/, quint32 /*mapsize*/, QString /*name*/, QString /*ip*/, quint32 /*spoofed*/, QString /*spoofedrealm*/, quint32 /*downloadtime*/ ) +{ + return NULL; +} + +CCallableScoreCheck *CGHostDB :: ThreadedScoreCheck( QString /*category*/, QString /*name*/, QString /*server*/ ) +{ + return NULL; +} + +CCallableW3MMDPlayerAdd *CGHostDB :: ThreadedW3MMDPlayerAdd( QString /*category*/, quint32 /*gameid*/, quint32 /*pid*/, QString /*name*/, QString /*flag*/, quint32 /*leaver*/, quint32 /*practicing*/ ) +{ + return NULL; +} + +CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( quint32 /*gameid*/, QMap /*var_ints*/ ) +{ + return NULL; +} + +CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( quint32 /*gameid*/, QMap /*var_reals*/ ) +{ + return NULL; +} + +CCallableW3MMDVarAdd *CGHostDB :: ThreadedW3MMDVarAdd( quint32 /*gameid*/, QMap /*var_strings*/ ) +{ + return NULL; +} + +// +// Callables +// + +void CBaseCallable :: Init( ) +{ + m_StartTicks = GetTicks( ); +} + +void CBaseCallable :: Close( ) +{ + m_EndTicks = GetTicks( ); + SetReady(true); +} + +CCallableAdminCount :: ~CCallableAdminCount( ) +{ + +} + +CCallableAdminCheck :: ~CCallableAdminCheck( ) +{ + +} + +CCallableAdminAdd :: ~CCallableAdminAdd( ) +{ + +} + +CCallableAdminRemove :: ~CCallableAdminRemove( ) +{ + +} + +CCallableAdminList :: ~CCallableAdminList( ) +{ + +} + +CCallableBanCount :: ~CCallableBanCount( ) +{ + +} + +CCallableBanCheck :: ~CCallableBanCheck( ) +{ + delete m_Result; +} + +CCallableBanAdd :: ~CCallableBanAdd( ) +{ + +} + +CCallableBanRemove :: ~CCallableBanRemove( ) +{ + +} + +CCallableBanList :: ~CCallableBanList( ) +{ + // don't delete anything in m_Result here, it's the caller's responsibility +} + +CCallableGameAdd :: ~CCallableGameAdd( ) +{ + +} + +CCallableGamePlayerAdd :: ~CCallableGamePlayerAdd( ) +{ + +} + +CCallableGamePlayerSummaryCheck :: ~CCallableGamePlayerSummaryCheck( ) +{ + delete m_Result; +} + +CCallableDotAGameAdd :: ~CCallableDotAGameAdd( ) +{ + +} + +CCallableDotAPlayerAdd :: ~CCallableDotAPlayerAdd( ) +{ + +} + +CCallableDotAPlayerSummaryCheck :: ~CCallableDotAPlayerSummaryCheck( ) +{ + delete m_Result; +} + +CCallableDownloadAdd :: ~CCallableDownloadAdd( ) +{ + +} + +CCallableScoreCheck :: ~CCallableScoreCheck( ) +{ + +} + +CCallableW3MMDPlayerAdd :: ~CCallableW3MMDPlayerAdd( ) +{ + +} + +CCallableW3MMDVarAdd :: ~CCallableW3MMDVarAdd( ) +{ + +} + +// +// CDBBan +// + +CDBBan :: CDBBan( QString nServer, QString nName, QString nIP, QString nDate, QString nGameName, QString nAdmin, QString nReason ) +{ + m_Server = nServer; + m_Name = nName; + m_IP = nIP; + m_Date = nDate; + m_GameName = nGameName; + m_Admin = nAdmin; + m_Reason = nReason; +} + +CDBBan :: ~CDBBan( ) +{ + +} + +// +// CDBGame +// + +CDBGame :: CDBGame( quint32 nID, QString nServer, QString nMap, QString nDateTime, QString nGameName, QString nOwnerName, quint32 nDuration ) +{ + m_ID = nID; + m_Server = nServer; + m_Map = nMap; + m_DateTime = nDateTime; + m_GameName = nGameName; + m_OwnerName = nOwnerName; + m_Duration = nDuration; +} + +CDBGame :: ~CDBGame( ) +{ + +} + +// +// CDBGamePlayer +// + +CDBGamePlayer :: CDBGamePlayer( quint32 nID, quint32 nGameID, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nReserved, quint32 nLoadingTime, quint32 nLeft, QString nLeftReason, quint32 nTeam, quint32 nColour ) +{ + m_ID = nID; + m_GameID = nGameID; + m_Name = nName; + m_IP = nIP; + m_Spoofed = nSpoofed; + m_SpoofedRealm = nSpoofedRealm; + m_Reserved = nReserved; + m_LoadingTime = nLoadingTime; + m_Left = nLeft; + m_LeftReason = nLeftReason; + m_Team = nTeam; + m_Colour = nColour; +} + +CDBGamePlayer :: ~CDBGamePlayer( ) +{ + +} + +// +// CDBGamePlayerSummary +// + +CDBGamePlayerSummary :: CDBGamePlayerSummary( QString nServer, QString nName, QString nFirstGameDateTime, QString nLastGameDateTime, quint32 nTotalGames, quint32 nMinLoadingTime, quint32 nAvgLoadingTime, quint32 nMaxLoadingTime, quint32 nMinLeftPercent, quint32 nAvgLeftPercent, quint32 nMaxLeftPercent, quint32 nMinDuration, quint32 nAvgDuration, quint32 nMaxDuration ) +{ + m_Server = nServer; + m_Name = nName; + m_FirstGameDateTime = nFirstGameDateTime; + m_LastGameDateTime = nLastGameDateTime; + m_TotalGames = nTotalGames; + m_MinLoadingTime = nMinLoadingTime; + m_AvgLoadingTime = nAvgLoadingTime; + m_MaxLoadingTime = nMaxLoadingTime; + m_MinLeftPercent = nMinLeftPercent; + m_AvgLeftPercent = nAvgLeftPercent; + m_MaxLeftPercent = nMaxLeftPercent; + m_MinDuration = nMinDuration; + m_AvgDuration = nAvgDuration; + m_MaxDuration = nMaxDuration; +} + +CDBGamePlayerSummary :: ~CDBGamePlayerSummary( ) +{ + +} + +// +// CDBDotAGame +// + +CDBDotAGame :: CDBDotAGame( quint32 nID, quint32 nGameID, quint32 nWinner, quint32 nMin, quint32 nSec ) +{ + m_ID = nID; + m_GameID = nGameID; + m_Winner = nWinner; + m_Min = nMin; + m_Sec = nSec; +} + +CDBDotAGame :: ~CDBDotAGame( ) +{ + +} + +// +// CDBDotAPlayer +// + +CDBDotAPlayer :: CDBDotAPlayer( ) +{ + m_ID = 0; + m_GameID = 0; + m_Colour = 0; + m_Kills = 0; + m_Deaths = 0; + m_CreepKills = 0; + m_CreepDenies = 0; + m_Assists = 0; + m_Gold = 0; + m_NeutralKills = 0; + m_NewColour = 0; + m_TowerKills = 0; + m_RaxKills = 0; + m_CourierKills = 0; +} + +CDBDotAPlayer :: CDBDotAPlayer( quint32 nID, quint32 nGameID, quint32 nColour, quint32 nKills, quint32 nDeaths, quint32 nCreepKills, quint32 nCreepDenies, quint32 nAssists, quint32 nGold, quint32 nNeutralKills, QString nItem1, QString nItem2, QString nItem3, QString nItem4, QString nItem5, QString nItem6, QString nHero, quint32 nNewColour, quint32 nTowerKills, quint32 nRaxKills, quint32 nCourierKills ) +{ + m_ID = nID; + m_GameID = nGameID; + m_Colour = nColour; + m_Kills = nKills; + m_Deaths = nDeaths; + m_CreepKills = nCreepKills; + m_CreepDenies = nCreepDenies; + m_Assists = nAssists; + m_Gold = nGold; + m_NeutralKills = nNeutralKills; + m_Items[0] = nItem1; + m_Items[1] = nItem2; + m_Items[2] = nItem3; + m_Items[3] = nItem4; + m_Items[4] = nItem5; + m_Items[5] = nItem6; + m_Hero = nHero; + m_NewColour = nNewColour; + m_TowerKills = nTowerKills; + m_RaxKills = nRaxKills; + m_CourierKills = nCourierKills; +} + +CDBDotAPlayer :: ~CDBDotAPlayer( ) +{ + +} + +QString CDBDotAPlayer :: GetItem( unsigned int i ) +{ + if( i < 6 ) + return m_Items[i]; + + return QString( ); +} + +void CDBDotAPlayer :: SetItem( unsigned int i, QString item ) +{ + if( i < 6 ) + m_Items[i] = item; +} + +// +// CDBDotAPlayerSummary +// + +CDBDotAPlayerSummary :: CDBDotAPlayerSummary( QString nServer, QString nName, quint32 nTotalGames, quint32 nTotalWins, quint32 nTotalLosses, quint32 nTotalKills, quint32 nTotalDeaths, quint32 nTotalCreepKills, quint32 nTotalCreepDenies, quint32 nTotalAssists, quint32 nTotalNeutralKills, quint32 nTotalTowerKills, quint32 nTotalRaxKills, quint32 nTotalCourierKills ) +{ + m_Server = nServer; + m_Name = nName; + m_TotalGames = nTotalGames; + m_TotalWins = nTotalWins; + m_TotalLosses = nTotalLosses; + m_TotalKills = nTotalKills; + m_TotalDeaths = nTotalDeaths; + m_TotalCreepKills = nTotalCreepKills; + m_TotalCreepDenies = nTotalCreepDenies; + m_TotalAssists = nTotalAssists; + m_TotalNeutralKills = nTotalNeutralKills; + m_TotalTowerKills = nTotalTowerKills; + m_TotalRaxKills = nTotalRaxKills; + m_TotalCourierKills = nTotalCourierKills; +} + +CDBDotAPlayerSummary :: ~CDBDotAPlayerSummary( ) +{ + +} diff --git a/src/libghost/ghostdb.h b/src/libghost/ghostdb.h new file mode 100644 index 0000000..440b621 --- /dev/null +++ b/src/libghost/ghostdb.h @@ -0,0 +1,857 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GHOSTDB_H +#define GHOSTDB_H + +// +// CGHostDB +// + + +class CBaseCallable; +class CCallableAdminCount; +class CCallableAdminCheck; +class CCallableAdminAdd; +class CCallableAdminRemove; +class CCallableAdminList; +class CCallableBanCount; +class CCallableBanCheck; +class CCallableBanAdd; +class CCallableBanRemove; +class CCallableBanList; +class CCallableGameAdd; +class CCallableGamePlayerAdd; +class CCallableGamePlayerSummaryCheck; +class CCallableDotAGameAdd; +class CCallableDotAPlayerAdd; +class CCallableDotAPlayerSummaryCheck; +class CCallableDownloadAdd; +class CCallableScoreCheck; +class CCallableW3MMDPlayerAdd; +class CCallableW3MMDVarAdd; +class CDBBan; +class CDBGame; +class CDBGamePlayer; +class CDBGamePlayerSummary; +class CDBDotAPlayerSummary; +class CConfig; + +#include "includes.h" +#include + +typedef QPair VarP; + +class CGHostDB : public QObject +{ + Q_OBJECT + +signals: + void error(const QString& message); + +private: + bool m_HasError; + QString m_Error; + +protected: + void SetError(const QString& error); + +public: + CGHostDB( CConfig *CFG ); + virtual ~CGHostDB( ); + + bool HasError( ) { return m_HasError; } + QString GetError( ) { return m_Error; } + virtual QString GetStatus( ) { return "DB STATUS --- OK"; } + + virtual void RecoverCallable( CBaseCallable *callable ); + + // standard (non-threaded) database functions + + virtual bool Begin( ); + virtual bool Commit( ); + virtual quint32 AdminCount( QString server ); + virtual bool AdminCheck( QString server, QString user ); + virtual bool AdminAdd( QString server, QString user ); + virtual bool AdminRemove( QString server, QString user ); + virtual QList AdminList( QString server ); + virtual quint32 BanCount( QString server ); + virtual CDBBan *BanCheck( QString server, QString user, QString ip ); + virtual bool BanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); + virtual bool BanRemove( QString server, QString user ); + virtual bool BanRemove( QString user ); + virtual QList BanList( QString server ); + virtual quint32 GameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); + virtual quint32 GamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); + virtual quint32 GamePlayerCount( QString name ); + virtual CDBGamePlayerSummary *GamePlayerSummaryCheck( QString name ); + virtual quint32 DotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ); + virtual quint32 DotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); + virtual quint32 DotAPlayerCount( QString name ); + virtual CDBDotAPlayerSummary *DotAPlayerSummaryCheck( QString name ); + virtual QString FromCheck( quint32 ip ); + virtual bool FromAdd( quint32 ip1, quint32 ip2, QString country ); + virtual bool DownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); + virtual quint32 W3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_ints ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_reals ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_strings ); + + // threaded database functions + + virtual void CreateThread( CBaseCallable *callable ); + virtual CCallableAdminCount *ThreadedAdminCount( QString server ); + virtual CCallableAdminCheck *ThreadedAdminCheck( QString server, QString user ); + virtual CCallableAdminAdd *ThreadedAdminAdd( QString server, QString user ); + virtual CCallableAdminRemove *ThreadedAdminRemove( QString server, QString user ); + virtual CCallableAdminList *ThreadedAdminList( QString server ); + virtual CCallableBanCount *ThreadedBanCount( QString server ); + virtual CCallableBanCheck *ThreadedBanCheck( QString server, QString user, QString ip ); + virtual CCallableBanAdd *ThreadedBanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); + virtual CCallableBanRemove *ThreadedBanRemove( QString server, QString user ); + virtual CCallableBanRemove *ThreadedBanRemove( QString user ); + virtual CCallableBanList *ThreadedBanList( QString server ); + virtual CCallableGameAdd *ThreadedGameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); + virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); + virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( QString name ); + virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ); + virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); + virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( QString name ); + virtual CCallableDownloadAdd *ThreadedDownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); + virtual CCallableScoreCheck *ThreadedScoreCheck( QString category, QString name, QString server ); + virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_ints ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_reals ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_strings ); +}; + +// +// Callables +// + +// life cycle of a callable: +// - the callable is created in one of the database's ThreadedXXX functions +// - initially the callable is NOT ready (i.e. m_Ready = false) +// - the ThreadedXXX function normally creates a thread to perform some query and (potentially) store some result in the callable +// - at the time of this writing all threads are immediately detached, the code does not join any threads (the callable's "readiness" is used for this purpose instead) +// - when the thread completes it will set m_Ready = true +// - DO NOT DO *ANYTHING* TO THE CALLABLE UNTIL IT'S READY OR YOU WILL CREATE A CONCURRENCY MESS +// - THE ONLY SAFE FUNCTION IN THE CALLABLE IS GetReady +// - when the callable is ready you may access the callable's result which will have been set within the (now terminated) thread + +// example usage: +// - normally you will call a ThreadedXXX function, store the callable in a vector, and periodically check if the callable is ready +// - when the callable is ready you will consume the result then you will pass the callable back to the database via the RecoverCallable function +// - the RecoverCallable function allows the database to recover some of the callable's resources to be reused later (e.g. MySQL connections) +// - note that this will NOT free the callable's memory, you must do that yourself after calling the RecoverCallable function +// - be careful not to leak any callables, it's NOT safe to delete a callable even if you decide that you don't want the result anymore +// - you should deliver any to-be-orphaned callables to the main vector in CGHost so they can be properly deleted when ready even if you don't care about the result anymore +// - e.g. if a player does a stats check immediately before a game is deleted you can't just delete the callable on game deletion unless it's ready + +class CBaseCallable : public QObject +{ + Q_OBJECT + +signals: + void finished(); + +protected: + QString m_Error; + +private: + volatile bool m_Ready; + quint32 m_StartTicks; + quint32 m_EndTicks; + +public: + CBaseCallable( ) : m_Error( ), m_Ready( false ), m_StartTicks( 0 ), m_EndTicks( 0 ) { } + virtual ~CBaseCallable( ) { } + + virtual void operator( )( ) { } + + virtual void Init( ); + virtual void Close( ); + + virtual const QString &GetError( ) const { return m_Error; } + virtual bool GetReady( ) const { return m_Ready; } + virtual void SetReady( bool nReady ) { m_Ready = nReady; if (nReady) emit finished(); } + virtual quint32 GetElapsed( ) const { return m_Ready ? m_EndTicks - m_StartTicks : 0; } +}; + +class CCallableAdminCount : public CBaseCallable +{ +protected: + QString m_Server; + quint32 m_Result; + +public: + CCallableAdminCount( QString nServer ) : CBaseCallable( ), m_Server( nServer ), m_Result( 0 ) { } + virtual ~CCallableAdminCount( ); + + virtual const QString &GetServer( ) const { return m_Server; } + virtual quint32 GetResult( ) const { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableAdminCheck : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + bool m_Result; + +public: + CCallableAdminCheck( QString nServer, QString nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } + virtual ~CCallableAdminCheck( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableAdminAdd : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + bool m_Result; + +public: + CCallableAdminAdd( QString nServer, QString nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } + virtual ~CCallableAdminAdd( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableAdminRemove : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + bool m_Result; + +public: + CCallableAdminRemove( QString nServer, QString nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } + virtual ~CCallableAdminRemove( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableAdminList : public CBaseCallable +{ +protected: + QString m_Server; + QList m_Result; + +public: + CCallableAdminList( QString nServer ) : CBaseCallable( ), m_Server( nServer ) { } + virtual ~CCallableAdminList( ); + + virtual QList GetResult( ) { return m_Result; } + virtual void SetResult( QList nResult ) { m_Result = nResult; } +}; + +class CCallableBanCount : public CBaseCallable +{ +protected: + QString m_Server; + quint32 m_Result; + +public: + CCallableBanCount( QString nServer ) : CBaseCallable( ), m_Server( nServer ), m_Result( 0 ) { } + virtual ~CCallableBanCount( ); + + virtual QString GetServer( ) { return m_Server; } + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableBanCheck : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + QString m_IP; + CDBBan *m_Result; + +public: + CCallableBanCheck( QString nServer, QString nUser, QString nIP ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_IP( nIP ), m_Result( NULL ) { } + virtual ~CCallableBanCheck( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual QString GetIP( ) { return m_IP; } + virtual CDBBan *GetResult( ) { return m_Result; } + virtual void SetResult( CDBBan *nResult ) { m_Result = nResult; } +}; + +class CCallableBanAdd : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + QString m_IP; + QString m_GameName; + QString m_Admin; + QString m_Reason; + bool m_Result; + +public: + CCallableBanAdd( QString nServer, QString nUser, QString nIP, QString nGameName, QString nAdmin, QString nReason ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_IP( nIP ), m_GameName( nGameName ), m_Admin( nAdmin ), m_Reason( nReason ), m_Result( false ) { } + virtual ~CCallableBanAdd( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual QString GetIP( ) { return m_IP; } + virtual QString GetGameName( ) { return m_GameName; } + virtual QString GetAdmin( ) { return m_Admin; } + virtual QString GetReason( ) { return m_Reason; } + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableBanRemove : public CBaseCallable +{ +protected: + QString m_Server; + QString m_User; + bool m_Result; + +public: + CCallableBanRemove( QString nServer, QString nUser ) : CBaseCallable( ), m_Server( nServer ), m_User( nUser ), m_Result( false ) { } + virtual ~CCallableBanRemove( ); + + virtual QString GetServer( ) { return m_Server; } + virtual QString GetUser( ) { return m_User; } + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableBanList : public CBaseCallable +{ +protected: + QString m_Server; + QList m_Result; + +public: + CCallableBanList( QString nServer ) : CBaseCallable( ), m_Server( nServer ) { } + virtual ~CCallableBanList( ); + + virtual QList GetResult( ) { return m_Result; } + virtual void SetResult( QList nResult ) { m_Result = nResult; } +}; + +class CCallableGameAdd : public CBaseCallable +{ +protected: + QString m_Server; + QString m_Map; + QString m_GameName; + QString m_OwnerName; + quint32 m_Duration; + quint32 m_GameState; + QString m_CreatorName; + QString m_CreatorServer; + quint32 m_Result; + +public: + CCallableGameAdd( QString nServer, QString nMap, QString nGameName, QString nOwnerName, quint32 nDuration, quint32 nGameState, QString nCreatorName, QString nCreatorServer ) : CBaseCallable( ), m_Server( nServer ), m_Map( nMap ), m_GameName( nGameName ), m_OwnerName( nOwnerName ), m_Duration( nDuration ), m_GameState( nGameState ), m_CreatorName( nCreatorName ), m_CreatorServer( nCreatorServer ), m_Result( 0 ) { } + virtual ~CCallableGameAdd( ); + + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableGamePlayerAdd : public CBaseCallable +{ +protected: + quint32 m_GameID; + QString m_Name; + QString m_IP; + quint32 m_Spoofed; + QString m_SpoofedRealm; + quint32 m_Reserved; + quint32 m_LoadingTime; + quint32 m_Left; + QString m_LeftReason; + quint32 m_Team; + quint32 m_Colour; + quint32 m_Result; + +public: + CCallableGamePlayerAdd( quint32 nGameID, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nReserved, quint32 nLoadingTime, quint32 nLeft, QString nLeftReason, quint32 nTeam, quint32 nColour ) : CBaseCallable( ), m_GameID( nGameID ), m_Name( nName ), m_IP( nIP ), m_Spoofed( nSpoofed ), m_SpoofedRealm( nSpoofedRealm ), m_Reserved( nReserved ), m_LoadingTime( nLoadingTime ), m_Left( nLeft ), m_LeftReason( nLeftReason ), m_Team( nTeam ), m_Colour( nColour ), m_Result( 0 ) { } + virtual ~CCallableGamePlayerAdd( ); + + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableGamePlayerSummaryCheck : public CBaseCallable +{ +protected: + QString m_Name; + CDBGamePlayerSummary *m_Result; + +public: + CCallableGamePlayerSummaryCheck( QString nName ) : CBaseCallable( ), m_Name( nName ), m_Result( NULL ) { } + virtual ~CCallableGamePlayerSummaryCheck( ); + + virtual QString GetName( ) { return m_Name; } + virtual CDBGamePlayerSummary *GetResult( ) { return m_Result; } + virtual void SetResult( CDBGamePlayerSummary *nResult ) { m_Result = nResult; } +}; + +class CCallableDotAGameAdd : public CBaseCallable +{ +protected: + quint32 m_GameID; + quint32 m_Winner; + quint32 m_Min; + quint32 m_Sec; + quint32 m_Result; + +public: + CCallableDotAGameAdd( quint32 nGameID, quint32 nWinner, quint32 nMin, quint32 nSec ) : CBaseCallable( ), m_GameID( nGameID ), m_Winner( nWinner ), m_Min( nMin ), m_Sec( nSec ), m_Result( 0 ) { } + virtual ~CCallableDotAGameAdd( ); + + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableDotAPlayerAdd : public CBaseCallable +{ +protected: + quint32 m_GameID; + quint32 m_Colour; + quint32 m_Kills; + quint32 m_Deaths; + quint32 m_CreepKills; + quint32 m_CreepDenies; + quint32 m_Assists; + quint32 m_Gold; + quint32 m_NeutralKills; + QString m_Item1; + QString m_Item2; + QString m_Item3; + QString m_Item4; + QString m_Item5; + QString m_Item6; + QString m_Hero; + quint32 m_NewColour; + quint32 m_TowerKills; + quint32 m_RaxKills; + quint32 m_CourierKills; + quint32 m_Result; + +public: + CCallableDotAPlayerAdd( quint32 nGameID, quint32 nColour, quint32 nKills, quint32 nDeaths, quint32 nCreepKills, quint32 nCreepDenies, quint32 nAssists, quint32 nGold, quint32 nNeutralKills, QString nItem1, QString nItem2, QString nItem3, QString nItem4, QString nItem5, QString nItem6, QString nHero, quint32 nNewColour, quint32 nTowerKills, quint32 nRaxKills, quint32 nCourierKills ) : CBaseCallable( ), m_GameID( nGameID ), m_Colour( nColour ), m_Kills( nKills ), m_Deaths( nDeaths ), m_CreepKills( nCreepKills ), m_CreepDenies( nCreepDenies ), m_Assists( nAssists ), m_Gold( nGold ), m_NeutralKills( nNeutralKills ), m_Item1( nItem1 ), m_Item2( nItem2 ), m_Item3( nItem3 ), m_Item4( nItem4 ), m_Item5( nItem5 ), m_Item6( nItem6 ), m_Hero( nHero ), m_NewColour( nNewColour ), m_TowerKills( nTowerKills ), m_RaxKills( nRaxKills ), m_CourierKills( nCourierKills ), m_Result( 0 ) { } + virtual ~CCallableDotAPlayerAdd( ); + + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableDotAPlayerSummaryCheck : public CBaseCallable +{ +protected: + QString m_Name; + CDBDotAPlayerSummary *m_Result; + +public: + CCallableDotAPlayerSummaryCheck( QString nName ) : CBaseCallable( ), m_Name( nName ), m_Result( NULL ) { } + virtual ~CCallableDotAPlayerSummaryCheck( ); + + virtual QString GetName( ) { return m_Name; } + virtual CDBDotAPlayerSummary *GetResult( ) { return m_Result; } + virtual void SetResult( CDBDotAPlayerSummary *nResult ) { m_Result = nResult; } +}; + +class CCallableDownloadAdd : public CBaseCallable +{ +protected: + QString m_Map; + quint32 m_MapSize; + QString m_Name; + QString m_IP; + quint32 m_Spoofed; + QString m_SpoofedRealm; + quint32 m_DownloadTime; + bool m_Result; + +public: + CCallableDownloadAdd( QString nMap, quint32 nMapSize, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nDownloadTime ) : CBaseCallable( ), m_Map( nMap ), m_MapSize( nMapSize ), m_Name( nName ), m_IP( nIP ), m_Spoofed( nSpoofed ), m_SpoofedRealm( nSpoofedRealm ), m_DownloadTime( nDownloadTime ), m_Result( false ) { } + virtual ~CCallableDownloadAdd( ); + + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +class CCallableScoreCheck : public CBaseCallable +{ +protected: + QString m_Category; + QString m_Name; + QString m_Server; + double m_Result; + +public: + CCallableScoreCheck( QString nCategory, QString nName, QString nServer ) : CBaseCallable( ), m_Category( nCategory ), m_Name( nName ), m_Server( nServer ), m_Result( 0.0 ) { } + virtual ~CCallableScoreCheck( ); + + virtual QString GetName( ) { return m_Name; } + virtual double GetResult( ) { return m_Result; } + virtual void SetResult( double nResult ) { m_Result = nResult; } +}; + +class CCallableW3MMDPlayerAdd : public CBaseCallable +{ +protected: + QString m_Category; + quint32 m_GameID; + quint32 m_PID; + QString m_Name; + QString m_Flag; + quint32 m_Leaver; + quint32 m_Practicing; + quint32 m_Result; + +public: + CCallableW3MMDPlayerAdd( QString nCategory, quint32 nGameID, quint32 nPID, QString nName, QString nFlag, quint32 nLeaver, quint32 nPracticing ) : CBaseCallable( ), m_Category( nCategory ), m_GameID( nGameID ), m_PID( nPID ), m_Name( nName ), m_Flag( nFlag ), m_Leaver( nLeaver ), m_Practicing( nPracticing ), m_Result( 0 ) { } + virtual ~CCallableW3MMDPlayerAdd( ); + + virtual quint32 GetResult( ) { return m_Result; } + virtual void SetResult( quint32 nResult ) { m_Result = nResult; } +}; + +class CCallableW3MMDVarAdd : public CBaseCallable +{ +protected: + quint32 m_GameID; + QMap m_VarInts; + QMap m_VarReals; + QMap m_VarStrings; + + enum ValueType { + VALUETYPE_INT = 1, + VALUETYPE_REAL = 2, + VALUETYPE_STRING = 3 + }; + + ValueType m_ValueType; + bool m_Result; + +public: + CCallableW3MMDVarAdd( quint32 nGameID, QMap nVarInts ) : CBaseCallable( ), m_GameID( nGameID ), m_VarInts( nVarInts ), m_ValueType( VALUETYPE_INT ), m_Result( false ) { } + CCallableW3MMDVarAdd( quint32 nGameID, QMap nVarReals ) : CBaseCallable( ), m_GameID( nGameID ), m_VarReals( nVarReals ), m_ValueType( VALUETYPE_REAL ), m_Result( false ) { } + CCallableW3MMDVarAdd( quint32 nGameID, QMap nVarStrings ) : CBaseCallable( ), m_GameID( nGameID ), m_VarStrings( nVarStrings ), m_ValueType( VALUETYPE_STRING ), m_Result( false ) { } + virtual ~CCallableW3MMDVarAdd( ); + + virtual bool GetResult( ) { return m_Result; } + virtual void SetResult( bool nResult ) { m_Result = nResult; } +}; + +// +// CDBBan +// + +class CDBBan +{ +private: + QString m_Server; + QString m_Name; + QString m_IP; + QString m_Date; + QString m_GameName; + QString m_Admin; + QString m_Reason; + +public: + CDBBan( QString nServer, QString nName, QString nIP, QString nDate, QString nGameName, QString nAdmin, QString nReason ); + ~CDBBan( ); + + QString GetServer( ) { return m_Server; } + QString GetName( ) { return m_Name; } + QString GetIP( ) { return m_IP; } + QString GetDate( ) { return m_Date; } + QString GetGameName( ) { return m_GameName; } + QString GetAdmin( ) { return m_Admin; } + QString GetReason( ) { return m_Reason; } +}; + +// +// CDBGame +// + +class CDBGame +{ +private: + quint32 m_ID; + QString m_Server; + QString m_Map; + QString m_DateTime; + QString m_GameName; + QString m_OwnerName; + quint32 m_Duration; + +public: + CDBGame( quint32 nID, QString nServer, QString nMap, QString nDateTime, QString nGameName, QString nOwnerName, quint32 nDuration ); + ~CDBGame( ); + + quint32 GetID( ) { return m_ID; } + QString GetServer( ) { return m_Server; } + QString GetMap( ) { return m_Map; } + QString GetDateTime( ) { return m_DateTime; } + QString GetGameName( ) { return m_GameName; } + QString GetOwnerName( ) { return m_OwnerName; } + quint32 GetDuration( ) { return m_Duration; } + + void SetDuration( quint32 nDuration ) { m_Duration = nDuration; } +}; + +// +// CDBGamePlayer +// + +class CDBGamePlayer +{ +private: + quint32 m_ID; + quint32 m_GameID; + QString m_Name; + QString m_IP; + quint32 m_Spoofed; + QString m_SpoofedRealm; + quint32 m_Reserved; + quint32 m_LoadingTime; + quint32 m_Left; + QString m_LeftReason; + quint32 m_Team; + quint32 m_Colour; + +public: + CDBGamePlayer( quint32 nID, quint32 nGameID, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nReserved, quint32 nLoadingTime, quint32 nLeft, QString nLeftReason, quint32 nTeam, quint32 nColour ); + ~CDBGamePlayer( ); + + quint32 GetID( ) { return m_ID; } + quint32 GetGameID( ) { return m_GameID; } + QString GetName( ) { return m_Name; } + QString GetIP( ) { return m_IP; } + quint32 GetSpoofed( ) { return m_Spoofed; } + QString GetSpoofedRealm( ) { return m_SpoofedRealm; } + quint32 GetReserved( ) { return m_Reserved; } + quint32 GetLoadingTime( ) { return m_LoadingTime; } + quint32 GetLeft( ) { return m_Left; } + QString GetLeftReason( ) { return m_LeftReason; } + quint32 GetTeam( ) { return m_Team; } + quint32 GetColour( ) { return m_Colour; } + + void SetLoadingTime( quint32 nLoadingTime ) { m_LoadingTime = nLoadingTime; } + void SetLeft( quint32 nLeft ) { m_Left = nLeft; } + void SetLeftReason( QString nLeftReason ) { m_LeftReason = nLeftReason; } +}; + +// +// CDBGamePlayerSummary +// + +class CDBGamePlayerSummary +{ +private: + QString m_Server; + QString m_Name; + QString m_FirstGameDateTime; // datetime of first game played + QString m_LastGameDateTime; // datetime of last game played + quint32 m_TotalGames; // total number of games played + quint32 m_MinLoadingTime; // minimum loading time in milliseconds (this could be skewed because different maps have different load times) + quint32 m_AvgLoadingTime; // average loading time in milliseconds (this could be skewed because different maps have different load times) + quint32 m_MaxLoadingTime; // maximum loading time in milliseconds (this could be skewed because different maps have different load times) + quint32 m_MinLeftPercent; // minimum time at which the player left the game expressed as a percentage of the game duration (0-100) + quint32 m_AvgLeftPercent; // average time at which the player left the game expressed as a percentage of the game duration (0-100) + quint32 m_MaxLeftPercent; // maximum time at which the player left the game expressed as a percentage of the game duration (0-100) + quint32 m_MinDuration; // minimum game duration in seconds + quint32 m_AvgDuration; // average game duration in seconds + quint32 m_MaxDuration; // maximum game duration in seconds + +public: + CDBGamePlayerSummary( QString nServer, QString nName, QString nFirstGameDateTime, QString nLastGameDateTime, quint32 nTotalGames, quint32 nMinLoadingTime, quint32 nAvgLoadingTime, quint32 nMaxLoadingTime, quint32 nMinLeftPercent, quint32 nAvgLeftPercent, quint32 nMaxLeftPercent, quint32 nMinDuration, quint32 nAvgDuration, quint32 nMaxDuration ); + ~CDBGamePlayerSummary( ); + + QString GetServer( ) { return m_Server; } + QString GetName( ) { return m_Name; } + QString GetFirstGameDateTime( ) { return m_FirstGameDateTime; } + QString GetLastGameDateTime( ) { return m_LastGameDateTime; } + quint32 GetTotalGames( ) { return m_TotalGames; } + quint32 GetMinLoadingTime( ) { return m_MinLoadingTime; } + quint32 GetAvgLoadingTime( ) { return m_AvgLoadingTime; } + quint32 GetMaxLoadingTime( ) { return m_MaxLoadingTime; } + quint32 GetMinLeftPercent( ) { return m_MinLeftPercent; } + quint32 GetAvgLeftPercent( ) { return m_AvgLeftPercent; } + quint32 GetMaxLeftPercent( ) { return m_MaxLeftPercent; } + quint32 GetMinDuration( ) { return m_MinDuration; } + quint32 GetAvgDuration( ) { return m_AvgDuration; } + quint32 GetMaxDuration( ) { return m_MaxDuration; } +}; + +// +// CDBDotAGame +// + +class CDBDotAGame +{ +private: + quint32 m_ID; + quint32 m_GameID; + quint32 m_Winner; + quint32 m_Min; + quint32 m_Sec; + +public: + CDBDotAGame( quint32 nID, quint32 nGameID, quint32 nWinner, quint32 nMin, quint32 nSec ); + ~CDBDotAGame( ); + + quint32 GetID( ) { return m_ID; } + quint32 GetGameID( ) { return m_GameID; } + quint32 GetWinner( ) { return m_Winner; } + quint32 GetMin( ) { return m_Min; } + quint32 GetSec( ) { return m_Sec; } +}; + +// +// CDBDotAPlayer +// + +class CDBDotAPlayer +{ +private: + quint32 m_ID; + quint32 m_GameID; + quint32 m_Colour; + quint32 m_Kills; + quint32 m_Deaths; + quint32 m_CreepKills; + quint32 m_CreepDenies; + quint32 m_Assists; + quint32 m_Gold; + quint32 m_NeutralKills; + QString m_Items[6]; + QString m_Hero; + quint32 m_NewColour; + quint32 m_TowerKills; + quint32 m_RaxKills; + quint32 m_CourierKills; + +public: + CDBDotAPlayer( ); + CDBDotAPlayer( quint32 nID, quint32 nGameID, quint32 nColour, quint32 nKills, quint32 nDeaths, quint32 nCreepKills, quint32 nCreepDenies, quint32 nAssists, quint32 nGold, quint32 nNeutralKills, QString nItem1, QString nItem2, QString nItem3, QString nItem4, QString nItem5, QString nItem6, QString nHero, quint32 nNewColour, quint32 nTowerKills, quint32 nRaxKills, quint32 nCourierKills ); + ~CDBDotAPlayer( ); + + quint32 GetID( ) { return m_ID; } + quint32 GetGameID( ) { return m_GameID; } + quint32 GetColour( ) { return m_Colour; } + quint32 GetKills( ) { return m_Kills; } + quint32 GetDeaths( ) { return m_Deaths; } + quint32 GetCreepKills( ) { return m_CreepKills; } + quint32 GetCreepDenies( ) { return m_CreepDenies; } + quint32 GetAssists( ) { return m_Assists; } + quint32 GetGold( ) { return m_Gold; } + quint32 GetNeutralKills( ) { return m_NeutralKills; } + QString GetItem( unsigned int i ); + QString GetHero( ) { return m_Hero; } + quint32 GetNewColour( ) { return m_NewColour; } + quint32 GetTowerKills( ) { return m_TowerKills; } + quint32 GetRaxKills( ) { return m_RaxKills; } + quint32 GetCourierKills( ) { return m_CourierKills; } + + void SetColour( quint32 nColour ) { m_Colour = nColour; } + void SetKills( quint32 nKills ) { m_Kills = nKills; } + void SetDeaths( quint32 nDeaths ) { m_Deaths = nDeaths; } + void SetCreepKills( quint32 nCreepKills ) { m_CreepKills = nCreepKills; } + void SetCreepDenies( quint32 nCreepDenies ) { m_CreepDenies = nCreepDenies; } + void SetAssists( quint32 nAssists ) { m_Assists = nAssists; } + void SetGold( quint32 nGold ) { m_Gold = nGold; } + void SetNeutralKills( quint32 nNeutralKills ) { m_NeutralKills = nNeutralKills; } + void SetItem( unsigned int i, QString item ); + void SetHero( QString nHero ) { m_Hero = nHero; } + void SetNewColour( quint32 nNewColour ) { m_NewColour = nNewColour; } + void SetTowerKills( quint32 nTowerKills ) { m_TowerKills = nTowerKills; } + void SetRaxKills( quint32 nRaxKills ) { m_RaxKills = nRaxKills; } + void SetCourierKills( quint32 nCourierKills ) { m_CourierKills = nCourierKills; } +}; + +// +// CDBDotAPlayerSummary +// + +class CDBDotAPlayerSummary +{ +private: + QString m_Server; + QString m_Name; + quint32 m_TotalGames; // total number of dota games played + quint32 m_TotalWins; // total number of dota games won + quint32 m_TotalLosses; // total number of dota games lost + quint32 m_TotalKills; // total number of hero kills + quint32 m_TotalDeaths; // total number of deaths + quint32 m_TotalCreepKills; // total number of creep kills + quint32 m_TotalCreepDenies; // total number of creep denies + quint32 m_TotalAssists; // total number of assists + quint32 m_TotalNeutralKills; // total number of neutral kills + quint32 m_TotalTowerKills; // total number of tower kills + quint32 m_TotalRaxKills; // total number of rax kills + quint32 m_TotalCourierKills; // total number of courier kills + +public: + CDBDotAPlayerSummary( QString nServer, QString nName, quint32 nTotalGames, quint32 nTotalWins, quint32 nTotalLosses, quint32 nTotalKills, quint32 nTotalDeaths, quint32 nTotalCreepKills, quint32 nTotalCreepDenies, quint32 nTotalAssists, quint32 nTotalNeutralKills, quint32 nTotalTowerKills, quint32 nTotalRaxKills, quint32 nTotalCourierKills ); + ~CDBDotAPlayerSummary( ); + + QString GetServer( ) { return m_Server; } + QString GetName( ) { return m_Name; } + quint32 GetTotalGames( ) { return m_TotalGames; } + quint32 GetTotalWins( ) { return m_TotalWins; } + quint32 GetTotalLosses( ) { return m_TotalLosses; } + quint32 GetTotalKills( ) { return m_TotalKills; } + quint32 GetTotalDeaths( ) { return m_TotalDeaths; } + quint32 GetTotalCreepKills( ) { return m_TotalCreepKills; } + quint32 GetTotalCreepDenies( ) { return m_TotalCreepDenies; } + quint32 GetTotalAssists( ) { return m_TotalAssists; } + quint32 GetTotalNeutralKills( ) { return m_TotalNeutralKills; } + quint32 GetTotalTowerKills( ) { return m_TotalTowerKills; } + quint32 GetTotalRaxKills( ) { return m_TotalRaxKills; } + quint32 GetTotalCourierKills( ) { return m_TotalCourierKills; } + + float GetAvgKills( ) { return m_TotalGames > 0 ? (float)m_TotalKills / m_TotalGames : 0; } + float GetAvgDeaths( ) { return m_TotalGames > 0 ? (float)m_TotalDeaths / m_TotalGames : 0; } + float GetAvgCreepKills( ) { return m_TotalGames > 0 ? (float)m_TotalCreepKills / m_TotalGames : 0; } + float GetAvgCreepDenies( ) { return m_TotalGames > 0 ? (float)m_TotalCreepDenies / m_TotalGames : 0; } + float GetAvgAssists( ) { return m_TotalGames > 0 ? (float)m_TotalAssists / m_TotalGames : 0; } + float GetAvgNeutralKills( ) { return m_TotalGames > 0 ? (float)m_TotalNeutralKills / m_TotalGames : 0; } + float GetAvgTowerKills( ) { return m_TotalGames > 0 ? (float)m_TotalTowerKills / m_TotalGames : 0; } + float GetAvgRaxKills( ) { return m_TotalGames > 0 ? (float)m_TotalRaxKills / m_TotalGames : 0; } + float GetAvgCourierKills( ) { return m_TotalGames > 0 ? (float)m_TotalCourierKills / m_TotalGames : 0; } +}; + +#endif diff --git a/ghost/ghostdbmysql.cpp b/src/libghost/ghostdbmysql.cpp similarity index 56% rename from ghost/ghostdbmysql.cpp rename to src/libghost/ghostdbmysql.cpp index ae7b7bf..3a03ce6 100644 --- a/ghost/ghostdbmysql.cpp +++ b/src/libghost/ghostdbmysql.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -41,10 +41,10 @@ CGHostDBMySQL :: CGHostDBMySQL( CConfig *CFG ) : CGHostDB( CFG ) { - m_Server = CFG->GetString( "db_mysql_server", string( ) ); + m_Server = CFG->GetString( "db_mysql_server", QString( ) ); m_Database = CFG->GetString( "db_mysql_database", "ghost" ); - m_User = CFG->GetString( "db_mysql_user", string( ) ); - m_Password = CFG->GetString( "db_mysql_password", string( ) ); + m_User = CFG->GetString( "db_mysql_user", QString( ) ); + m_Password = CFG->GetString( "db_mysql_password", QString( ) ); m_Port = CFG->GetInt( "db_mysql_port", 0 ); m_BotID = CFG->GetInt( "db_mysql_botid", 0 ); m_NumConnections = 1; @@ -59,9 +59,8 @@ CGHostDBMySQL :: CGHostDBMySQL( CConfig *CFG ) : CGHostDB( CFG ) if( !( Connection = mysql_init( NULL ) ) ) { - CONSOLE_Print( string( "[MYSQL] " ) + mysql_error( Connection ) ); - m_HasError = true; - m_Error = "error initializing MySQL connection"; + CONSOLE_Print( QString( "[MYSQL] " ) + mysql_error( Connection ) ); + SetError("error initializing MySQL connection"); return; } @@ -70,23 +69,22 @@ CGHostDBMySQL :: CGHostDBMySQL( CConfig *CFG ) : CGHostDB( CFG ) if( !( mysql_real_connect( Connection, m_Server.c_str( ), m_User.c_str( ), m_Password.c_str( ), m_Database.c_str( ), m_Port, NULL, 0 ) ) ) { - CONSOLE_Print( string( "[MYSQL] " ) + mysql_error( Connection ) ); - m_HasError = true; - m_Error = "error connecting to MySQL server"; + CONSOLE_Print( QString( "[MYSQL] " ) + mysql_error( Connection ) ); + SetError("error connecting to MySQL server"); return; } - m_IdleConnections.push( Connection ); + m_IdleConnections.enqueue( Connection ); } CGHostDBMySQL :: ~CGHostDBMySQL( ) { CONSOLE_Print( "[MYSQL] closing " + UTIL_ToString( m_IdleConnections.size( ) ) + "/" + UTIL_ToString( m_NumConnections ) + " idle MySQL connections" ); - while( !m_IdleConnections.empty( ) ) + while( !m_IdleConnections.isEmpty( ) ) { mysql_close( (MYSQL *)m_IdleConnections.front( ) ); - m_IdleConnections.pop( ); + m_IdleConnections.dequeue( ); } if( m_OutstandingCallables > 0 ) @@ -95,7 +93,7 @@ CGHostDBMySQL :: ~CGHostDBMySQL( ) mysql_library_end( ); } -string CGHostDBMySQL :: GetStatus( ) +QString CGHostDBMySQL :: GetStatus( ) { return "DB STATUS --- Connections: " + UTIL_ToString( m_IdleConnections.size( ) ) + "/" + UTIL_ToString( m_NumConnections ) + " idle. Outstanding callables: " + UTIL_ToString( m_OutstandingCallables ) + "."; } @@ -112,14 +110,14 @@ void CGHostDBMySQL :: RecoverCallable( CBaseCallable *callable ) m_NumConnections--; } else - m_IdleConnections.push( MySQLCallable->GetConnection( ) ); + m_IdleConnections.enqueue( MySQLCallable->GetConnection( ) ); if( m_OutstandingCallables == 0 ) CONSOLE_Print( "[MYSQL] recovered a mysql callable with zero outstanding" ); else m_OutstandingCallables--; - if( !MySQLCallable->GetError( ).empty( ) ) + if( !MySQLCallable->GetError( ).isEmpty( ) ) CONSOLE_Print( "[MYSQL] error --- " + MySQLCallable->GetError( ) ); } else @@ -134,7 +132,7 @@ void CGHostDBMySQL :: CreateThread( CBaseCallable *callable ) } catch( boost :: thread_resource_error tre ) { - CONSOLE_Print( "[MYSQL] error spawning thread on attempt #1 [" + string( tre.what( ) ) + "], pausing execution and trying again in 50ms" ); + CONSOLE_Print( "[MYSQL] error spawning thread on attempt #1 [" + QString( tre.what( ) ) + "], pausing execution and trying again in 50ms" ); MILLISLEEP( 50 ); try @@ -143,13 +141,13 @@ void CGHostDBMySQL :: CreateThread( CBaseCallable *callable ) } catch( boost :: thread_resource_error tre2 ) { - CONSOLE_Print( "[MYSQL] error spawning thread on attempt #2 [" + string( tre2.what( ) ) + "], giving up" ); + CONSOLE_Print( "[MYSQL] error spawning thread on attempt #2 [" + QString( tre2.what( ) ) + "], giving up" ); callable->SetReady( true ); } } } -CCallableAdminCount *CGHostDBMySQL :: ThreadedAdminCount( string server ) +CCallableAdminCount *CGHostDBMySQL :: ThreadedAdminCount( QString server ) { void *Connection = GetIdleConnection( ); @@ -162,7 +160,7 @@ CCallableAdminCount *CGHostDBMySQL :: ThreadedAdminCount( string server ) return Callable; } -CCallableAdminCheck *CGHostDBMySQL :: ThreadedAdminCheck( string server, string user ) +CCallableAdminCheck *CGHostDBMySQL :: ThreadedAdminCheck( QString server, QString user ) { void *Connection = GetIdleConnection( ); @@ -175,7 +173,7 @@ CCallableAdminCheck *CGHostDBMySQL :: ThreadedAdminCheck( string server, string return Callable; } -CCallableAdminAdd *CGHostDBMySQL :: ThreadedAdminAdd( string server, string user ) +CCallableAdminAdd *CGHostDBMySQL :: ThreadedAdminAdd( QString server, QString user ) { void *Connection = GetIdleConnection( ); @@ -188,7 +186,7 @@ CCallableAdminAdd *CGHostDBMySQL :: ThreadedAdminAdd( string server, string user return Callable; } -CCallableAdminRemove *CGHostDBMySQL :: ThreadedAdminRemove( string server, string user ) +CCallableAdminRemove *CGHostDBMySQL :: ThreadedAdminRemove( QString server, QString user ) { void *Connection = GetIdleConnection( ); @@ -201,7 +199,7 @@ CCallableAdminRemove *CGHostDBMySQL :: ThreadedAdminRemove( string server, strin return Callable; } -CCallableAdminList *CGHostDBMySQL :: ThreadedAdminList( string server ) +CCallableAdminList *CGHostDBMySQL :: ThreadedAdminList( QString server ) { void *Connection = GetIdleConnection( ); @@ -214,7 +212,7 @@ CCallableAdminList *CGHostDBMySQL :: ThreadedAdminList( string server ) return Callable; } -CCallableBanCount *CGHostDBMySQL :: ThreadedBanCount( string server ) +CCallableBanCount *CGHostDBMySQL :: ThreadedBanCount( QString server ) { void *Connection = GetIdleConnection( ); @@ -227,7 +225,7 @@ CCallableBanCount *CGHostDBMySQL :: ThreadedBanCount( string server ) return Callable; } -CCallableBanCheck *CGHostDBMySQL :: ThreadedBanCheck( string server, string user, string ip ) +CCallableBanCheck *CGHostDBMySQL :: ThreadedBanCheck( QString server, QString user, QString ip ) { void *Connection = GetIdleConnection( ); @@ -240,7 +238,7 @@ CCallableBanCheck *CGHostDBMySQL :: ThreadedBanCheck( string server, string user return Callable; } -CCallableBanAdd *CGHostDBMySQL :: ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ) +CCallableBanAdd *CGHostDBMySQL :: ThreadedBanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ) { void *Connection = GetIdleConnection( ); @@ -253,7 +251,7 @@ CCallableBanAdd *CGHostDBMySQL :: ThreadedBanAdd( string server, string user, st return Callable; } -CCallableBanRemove *CGHostDBMySQL :: ThreadedBanRemove( string server, string user ) +CCallableBanRemove *CGHostDBMySQL :: ThreadedBanRemove( QString server, QString user ) { void *Connection = GetIdleConnection( ); @@ -266,20 +264,20 @@ CCallableBanRemove *CGHostDBMySQL :: ThreadedBanRemove( string server, string us return Callable; } -CCallableBanRemove *CGHostDBMySQL :: ThreadedBanRemove( string user ) +CCallableBanRemove *CGHostDBMySQL :: ThreadedBanRemove( QString user ) { void *Connection = GetIdleConnection( ); if( !Connection ) m_NumConnections++; - CCallableBanRemove *Callable = new CMySQLCallableBanRemove( string( ), user, Connection, m_BotID, m_Server, m_Database, m_User, m_Password, m_Port ); + CCallableBanRemove *Callable = new CMySQLCallableBanRemove( QString( ), user, Connection, m_BotID, m_Server, m_Database, m_User, m_Password, m_Port ); CreateThread( Callable ); m_OutstandingCallables++; return Callable; } -CCallableBanList *CGHostDBMySQL :: ThreadedBanList( string server ) +CCallableBanList *CGHostDBMySQL :: ThreadedBanList( QString server ) { void *Connection = GetIdleConnection( ); @@ -292,7 +290,7 @@ CCallableBanList *CGHostDBMySQL :: ThreadedBanList( string server ) return Callable; } -CCallableGameAdd *CGHostDBMySQL :: ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) +CCallableGameAdd *CGHostDBMySQL :: ThreadedGameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ) { void *Connection = GetIdleConnection( ); @@ -305,7 +303,7 @@ CCallableGameAdd *CGHostDBMySQL :: ThreadedGameAdd( string server, string map, s return Callable; } -CCallableGamePlayerAdd *CGHostDBMySQL :: ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) +CCallableGamePlayerAdd *CGHostDBMySQL :: ThreadedGamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ) { void *Connection = GetIdleConnection( ); @@ -318,7 +316,7 @@ CCallableGamePlayerAdd *CGHostDBMySQL :: ThreadedGamePlayerAdd( uint32_t gameid, return Callable; } -CCallableGamePlayerSummaryCheck *CGHostDBMySQL :: ThreadedGamePlayerSummaryCheck( string name ) +CCallableGamePlayerSummaryCheck *CGHostDBMySQL :: ThreadedGamePlayerSummaryCheck( QString name ) { void *Connection = GetIdleConnection( ); @@ -331,7 +329,7 @@ CCallableGamePlayerSummaryCheck *CGHostDBMySQL :: ThreadedGamePlayerSummaryCheck return Callable; } -CCallableDotAGameAdd *CGHostDBMySQL :: ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) +CCallableDotAGameAdd *CGHostDBMySQL :: ThreadedDotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ) { void *Connection = GetIdleConnection( ); @@ -344,7 +342,7 @@ CCallableDotAGameAdd *CGHostDBMySQL :: ThreadedDotAGameAdd( uint32_t gameid, uin return Callable; } -CCallableDotAPlayerAdd *CGHostDBMySQL :: ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) +CCallableDotAPlayerAdd *CGHostDBMySQL :: ThreadedDotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ) { void *Connection = GetIdleConnection( ); @@ -357,7 +355,7 @@ CCallableDotAPlayerAdd *CGHostDBMySQL :: ThreadedDotAPlayerAdd( uint32_t gameid, return Callable; } -CCallableDotAPlayerSummaryCheck *CGHostDBMySQL :: ThreadedDotAPlayerSummaryCheck( string name ) +CCallableDotAPlayerSummaryCheck *CGHostDBMySQL :: ThreadedDotAPlayerSummaryCheck( QString name ) { void *Connection = GetIdleConnection( ); @@ -370,7 +368,7 @@ CCallableDotAPlayerSummaryCheck *CGHostDBMySQL :: ThreadedDotAPlayerSummaryCheck return Callable; } -CCallableDownloadAdd *CGHostDBMySQL :: ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) +CCallableDownloadAdd *CGHostDBMySQL :: ThreadedDownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ) { void *Connection = GetIdleConnection( ); @@ -383,7 +381,7 @@ CCallableDownloadAdd *CGHostDBMySQL :: ThreadedDownloadAdd( string map, uint32_t return Callable; } -CCallableScoreCheck *CGHostDBMySQL :: ThreadedScoreCheck( string category, string name, string server ) +CCallableScoreCheck *CGHostDBMySQL :: ThreadedScoreCheck( QString category, QString name, QString server ) { void *Connection = GetIdleConnection( ); @@ -396,7 +394,7 @@ CCallableScoreCheck *CGHostDBMySQL :: ThreadedScoreCheck( string category, strin return Callable; } -CCallableW3MMDPlayerAdd *CGHostDBMySQL :: ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) +CCallableW3MMDPlayerAdd *CGHostDBMySQL :: ThreadedW3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ) { void *Connection = GetIdleConnection( ); @@ -409,7 +407,7 @@ CCallableW3MMDPlayerAdd *CGHostDBMySQL :: ThreadedW3MMDPlayerAdd( string categor return Callable; } -CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ) +CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_ints ) { void *Connection = GetIdleConnection( ); @@ -422,7 +420,7 @@ CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( uint32_t gameid, map return Callable; } -CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ) +CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_reals ) { void *Connection = GetIdleConnection( ); @@ -435,7 +433,7 @@ CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( uint32_t gameid, map return Callable; } -CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ) +CCallableW3MMDVarAdd *CGHostDBMySQL :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_strings ) { void *Connection = GetIdleConnection( ); @@ -452,10 +450,10 @@ void *CGHostDBMySQL :: GetIdleConnection( ) { void *Connection = NULL; - if( !m_IdleConnections.empty( ) ) + if( !m_IdleConnections.isEmpty( ) ) { Connection = m_IdleConnections.front( ); - m_IdleConnections.pop( ); + m_IdleConnections.dequeue( ); } return Connection; @@ -465,18 +463,18 @@ void *CGHostDBMySQL :: GetIdleConnection( ) // unprototyped global helper functions // -string MySQLEscapeString( void *conn, string str ) +QString MySQLEscapeString( void *conn, QString str ) { char *to = new char[str.size( ) * 2 + 1]; - unsigned long size = mysql_real_escape_string( (MYSQL *)conn, to, str.c_str( ), str.size( ) ); - string result( to, size ); + unsigned long size = mysql_real_escape_QString( (MYSQL *)conn, to, str.c_str( ), str.size( ) ); + QString result( to, size ); delete [] to; return result; } -vector MySQLFetchRow( MYSQL_RES *res ) +QList MySQLFetchRow( MYSQL_RES *res ) { - vector Result; + QList Result; MYSQL_ROW Row = mysql_fetch_row( res ); @@ -488,9 +486,9 @@ vector MySQLFetchRow( MYSQL_RES *res ) for( unsigned int i = 0; i < mysql_num_fields( res ); i++ ) { if( Row[i] ) - Result.push_back( string( Row[i], Lengths[i] ) ); + Result.push_back( QString( Row[i], Lengths[i] ) ); else - Result.push_back( string( ) ); + Result.push_back( QString( ) ); } } @@ -501,11 +499,11 @@ vector MySQLFetchRow( MYSQL_RES *res ) // global helper functions // -uint32_t MySQLAdminCount( void *conn, string *error, uint32_t botid, string server ) +quint32 MySQLAdminCount( void *conn, QString *error, quint32 botid, QString server ) { - string EscServer = MySQLEscapeString( conn, server ); - uint32_t Count = 0; - string Query = "SELECT COUNT(*) FROM admins WHERE server='" + EscServer + "'"; + QString EscServer = MySQLEscapeString( conn, server ); + quint32 Count = 0; + QString Query = "SELECT COUNT(*) FROM admins WHERE server='" + EscServer + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -515,7 +513,7 @@ uint32_t MySQLAdminCount( void *conn, string *error, uint32_t botid, string serv if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 1 ) Count = UTIL_ToUInt32( Row[0] ); @@ -531,13 +529,13 @@ uint32_t MySQLAdminCount( void *conn, string *error, uint32_t botid, string serv return Count; } -bool MySQLAdminCheck( void *conn, string *error, uint32_t botid, string server, string user ) +bool MySQLAdminCheck( void *conn, QString *error, quint32 botid, QString server, QString user ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); bool IsAdmin = false; - string Query = "SELECT * FROM admins WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; + QString Query = "SELECT * FROM admins WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -547,9 +545,9 @@ bool MySQLAdminCheck( void *conn, string *error, uint32_t botid, string server, if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); - if( !Row.empty( ) ) + if( !Row.isEmpty( ) ) IsAdmin = true; mysql_free_result( Result ); @@ -561,13 +559,13 @@ bool MySQLAdminCheck( void *conn, string *error, uint32_t botid, string server, return IsAdmin; } -bool MySQLAdminAdd( void *conn, string *error, uint32_t botid, string server, string user ) +bool MySQLAdminAdd( void *conn, QString *error, quint32 botid, QString server, QString user ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); bool Success = false; - string Query = "INSERT INTO admins ( botid, server, name ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscUser + "' )"; + QString Query = "INSERT INTO admins ( botid, server, name ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscUser + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -577,13 +575,13 @@ bool MySQLAdminAdd( void *conn, string *error, uint32_t botid, string server, st return Success; } -bool MySQLAdminRemove( void *conn, string *error, uint32_t botid, string server, string user ) +bool MySQLAdminRemove( void *conn, QString *error, quint32 botid, QString server, QString user ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); bool Success = false; - string Query = "DELETE FROM admins WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; + QString Query = "DELETE FROM admins WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -593,11 +591,11 @@ bool MySQLAdminRemove( void *conn, string *error, uint32_t botid, string server, return Success; } -vector MySQLAdminList( void *conn, string *error, uint32_t botid, string server ) +QList MySQLAdminList( void *conn, QString *error, quint32 botid, QString server ) { - string EscServer = MySQLEscapeString( conn, server ); - vector AdminList; - string Query = "SELECT name FROM admins WHERE server='" + EscServer + "'"; + QString EscServer = MySQLEscapeString( conn, server ); + QList AdminList; + QString Query = "SELECT name FROM admins WHERE server='" + EscServer + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -607,9 +605,9 @@ vector MySQLAdminList( void *conn, string *error, uint32_t botid, string if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); - while( !Row.empty( ) ) + while( !Row.isEmpty( ) ) { AdminList.push_back( Row[0] ); Row = MySQLFetchRow( Result ); @@ -624,11 +622,11 @@ vector MySQLAdminList( void *conn, string *error, uint32_t botid, string return AdminList; } -uint32_t MySQLBanCount( void *conn, string *error, uint32_t botid, string server ) +quint32 MySQLBanCount( void *conn, QString *error, quint32 botid, QString server ) { - string EscServer = MySQLEscapeString( conn, server ); - uint32_t Count = 0; - string Query = "SELECT COUNT(*) FROM bans WHERE server='" + EscServer + "'"; + QString EscServer = MySQLEscapeString( conn, server ); + quint32 Count = 0; + QString Query = "SELECT COUNT(*) FROM bans WHERE server='" + EscServer + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -638,7 +636,7 @@ uint32_t MySQLBanCount( void *conn, string *error, uint32_t botid, string server if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 1 ) Count = UTIL_ToUInt32( Row[0] ); @@ -654,16 +652,16 @@ uint32_t MySQLBanCount( void *conn, string *error, uint32_t botid, string server return Count; } -CDBBan *MySQLBanCheck( void *conn, string *error, uint32_t botid, string server, string user, string ip ) +CDBBan *MySQLBanCheck( void *conn, QString *error, quint32 botid, QString server, QString user, QString ip ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); - string EscIP = MySQLEscapeString( conn, ip ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); + QString EscIP = MySQLEscapeString( conn, ip ); CDBBan *Ban = NULL; - string Query; + QString Query; - if( ip.empty( ) ) + if( ip.isEmpty( ) ) Query = "SELECT name, ip, DATE(date), gamename, admin, reason FROM bans WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; else Query = "SELECT name, ip, DATE(date), gamename, admin, reason FROM bans WHERE (server='" + EscServer + "' AND name='" + EscUser + "') OR ip='" + EscIP + "'"; @@ -676,7 +674,7 @@ CDBBan *MySQLBanCheck( void *conn, string *error, uint32_t botid, string server, if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 6 ) Ban = new CDBBan( server, Row[0], Row[1], Row[2], Row[3], Row[4], Row[5] ); @@ -692,17 +690,17 @@ CDBBan *MySQLBanCheck( void *conn, string *error, uint32_t botid, string server, return Ban; } -bool MySQLBanAdd( void *conn, string *error, uint32_t botid, string server, string user, string ip, string gamename, string admin, string reason ) +bool MySQLBanAdd( void *conn, QString *error, quint32 botid, QString server, QString user, QString ip, QString gamename, QString admin, QString reason ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); - string EscIP = MySQLEscapeString( conn, ip ); - string EscGameName = MySQLEscapeString( conn, gamename ); - string EscAdmin = MySQLEscapeString( conn, admin ); - string EscReason = MySQLEscapeString( conn, reason ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); + QString EscIP = MySQLEscapeString( conn, ip ); + QString EscGameName = MySQLEscapeString( conn, gamename ); + QString EscAdmin = MySQLEscapeString( conn, admin ); + QString EscReason = MySQLEscapeString( conn, reason ); bool Success = false; - string Query = "INSERT INTO bans ( botid, server, name, ip, date, gamename, admin, reason ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscUser + "', '" + EscIP + "', CURDATE( ), '" + EscGameName + "', '" + EscAdmin + "', '" + EscReason + "' )"; + QString Query = "INSERT INTO bans ( botid, server, name, ip, date, gamename, admin, reason ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscUser + "', '" + EscIP + "', CURDATE( ), '" + EscGameName + "', '" + EscAdmin + "', '" + EscReason + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -712,13 +710,13 @@ bool MySQLBanAdd( void *conn, string *error, uint32_t botid, string server, stri return Success; } -bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string server, string user ) +bool MySQLBanRemove( void *conn, QString *error, quint32 botid, QString server, QString user ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscServer = MySQLEscapeString( conn, server ); - string EscUser = MySQLEscapeString( conn, user ); + QString EscServer = MySQLEscapeString( conn, server ); + QString EscUser = MySQLEscapeString( conn, user ); bool Success = false; - string Query = "DELETE FROM bans WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; + QString Query = "DELETE FROM bans WHERE server='" + EscServer + "' AND name='" + EscUser + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -728,12 +726,12 @@ bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string server, s return Success; } -bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string user ) +bool MySQLBanRemove( void *conn, QString *error, quint32 botid, QString user ) { transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); - string EscUser = MySQLEscapeString( conn, user ); + QString EscUser = MySQLEscapeString( conn, user ); bool Success = false; - string Query = "DELETE FROM bans WHERE name='" + EscUser + "'"; + QString Query = "DELETE FROM bans WHERE name='" + EscUser + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -743,11 +741,11 @@ bool MySQLBanRemove( void *conn, string *error, uint32_t botid, string user ) return Success; } -vector MySQLBanList( void *conn, string *error, uint32_t botid, string server ) +QList MySQLBanList( void *conn, QString *error, quint32 botid, QString server ) { - string EscServer = MySQLEscapeString( conn, server ); - vector BanList; - string Query = "SELECT name, ip, DATE(date), gamename, admin, reason FROM bans WHERE server='" + EscServer + "'"; + QString EscServer = MySQLEscapeString( conn, server ); + QList BanList; + QString Query = "SELECT name, ip, DATE(date), gamename, admin, reason FROM bans WHERE server='" + EscServer + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -757,7 +755,7 @@ vector MySQLBanList( void *conn, string *error, uint32_t botid, string if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); while( Row.size( ) == 6 ) { @@ -774,16 +772,16 @@ vector MySQLBanList( void *conn, string *error, uint32_t botid, string return BanList; } -uint32_t MySQLGameAdd( void *conn, string *error, uint32_t botid, string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) +quint32 MySQLGameAdd( void *conn, QString *error, quint32 botid, QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ) { - uint32_t RowID = 0; - string EscServer = MySQLEscapeString( conn, server ); - string EscMap = MySQLEscapeString( conn, map ); - string EscGameName = MySQLEscapeString( conn, gamename ); - string EscOwnerName = MySQLEscapeString( conn, ownername ); - string EscCreatorName = MySQLEscapeString( conn, creatorname ); - string EscCreatorServer = MySQLEscapeString( conn, creatorserver ); - string Query = "INSERT INTO games ( botid, server, map, datetime, gamename, ownername, duration, gamestate, creatorname, creatorserver ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscMap + "', NOW( ), '" + EscGameName + "', '" + EscOwnerName + "', " + UTIL_ToString( duration ) + ", " + UTIL_ToString( gamestate ) + ", '" + EscCreatorName + "', '" + EscCreatorServer + "' )"; + quint32 RowID = 0; + QString EscServer = MySQLEscapeString( conn, server ); + QString EscMap = MySQLEscapeString( conn, map ); + QString EscGameName = MySQLEscapeString( conn, gamename ); + QString EscOwnerName = MySQLEscapeString( conn, ownername ); + QString EscCreatorName = MySQLEscapeString( conn, creatorname ); + QString EscCreatorServer = MySQLEscapeString( conn, creatorserver ); + QString Query = "INSERT INTO games ( botid, server, map, datetime, gamename, ownername, duration, gamestate, creatorname, creatorserver ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscServer + "', '" + EscMap + "', NOW( ), '" + EscGameName + "', '" + EscOwnerName + "', " + UTIL_ToString( duration ) + ", " + UTIL_ToString( gamestate ) + ", '" + EscCreatorName + "', '" + EscCreatorServer + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -793,15 +791,15 @@ uint32_t MySQLGameAdd( void *conn, string *error, uint32_t botid, string server, return RowID; } -uint32_t MySQLGamePlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) +quint32 MySQLGamePlayerAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t RowID = 0; - string EscName = MySQLEscapeString( conn, name ); - string EscIP = MySQLEscapeString( conn, ip ); - string EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); - string EscLeftReason = MySQLEscapeString( conn, leftreason ); - string Query = "INSERT INTO gameplayers ( botid, gameid, name, ip, spoofed, reserved, loadingtime, `left`, leftreason, team, colour, spoofedrealm ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", " + UTIL_ToString( reserved ) + ", " + UTIL_ToString( loadingtime ) + ", " + UTIL_ToString( left ) + ", '" + EscLeftReason + "', " + UTIL_ToString( team ) + ", " + UTIL_ToString( colour ) + ", '" + EscSpoofedRealm + "' )"; + quint32 RowID = 0; + QString EscName = MySQLEscapeString( conn, name ); + QString EscIP = MySQLEscapeString( conn, ip ); + QString EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); + QString EscLeftReason = MySQLEscapeString( conn, leftreason ); + QString Query = "INSERT INTO gameplayers ( botid, gameid, name, ip, spoofed, reserved, loadingtime, `left`, leftreason, team, colour, spoofedrealm ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", " + UTIL_ToString( reserved ) + ", " + UTIL_ToString( loadingtime ) + ", " + UTIL_ToString( left ) + ", '" + EscLeftReason + "', " + UTIL_ToString( team ) + ", " + UTIL_ToString( colour ) + ", '" + EscSpoofedRealm + "' )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -811,12 +809,12 @@ uint32_t MySQLGamePlayerAdd( void *conn, string *error, uint32_t botid, uint32_t return RowID; } -CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, string *error, uint32_t botid, string name ) +CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, QString *error, quint32 botid, QString name ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - string EscName = MySQLEscapeString( conn, name ); + QString EscName = MySQLEscapeString( conn, name ); CDBGamePlayerSummary *GamePlayerSummary = NULL; - string Query = "SELECT MIN(DATE(datetime)), MAX(DATE(datetime)), COUNT(*), MIN(loadingtime), AVG(loadingtime), MAX(loadingtime), MIN(`left`/duration)*100, AVG(`left`/duration)*100, MAX(`left`/duration)*100, MIN(duration), AVG(duration), MAX(duration) FROM gameplayers LEFT JOIN games ON games.id=gameid WHERE LOWER(name)='" + EscName + "'"; + QString Query = "SELECT MIN(DATE(datetime)), MAX(DATE(datetime)), COUNT(*), MIN(loadingtime), AVG(loadingtime), MAX(loadingtime), MIN(`left`/duration)*100, AVG(`left`/duration)*100, MAX(`left`/duration)*100, MIN(duration), AVG(duration), MAX(duration) FROM gameplayers LEFT JOIN games ON games.id=gameid WHERE LOWER(name)='" + EscName + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -826,23 +824,23 @@ CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, string *error, ui if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 12 ) { - string FirstGameDateTime = Row[0]; - string LastGameDateTime = Row[1]; - uint32_t TotalGames = UTIL_ToUInt32( Row[2] ); - uint32_t MinLoadingTime = UTIL_ToUInt32( Row[3] ); - uint32_t AvgLoadingTime = UTIL_ToUInt32( Row[4] ); - uint32_t MaxLoadingTime = UTIL_ToUInt32( Row[5] ); - uint32_t MinLeftPercent = UTIL_ToUInt32( Row[6] ); - uint32_t AvgLeftPercent = UTIL_ToUInt32( Row[7] ); - uint32_t MaxLeftPercent = UTIL_ToUInt32( Row[8] ); - uint32_t MinDuration = UTIL_ToUInt32( Row[9] ); - uint32_t AvgDuration = UTIL_ToUInt32( Row[10] ); - uint32_t MaxDuration = UTIL_ToUInt32( Row[11] ); - GamePlayerSummary = new CDBGamePlayerSummary( string( ), name, FirstGameDateTime, LastGameDateTime, TotalGames, MinLoadingTime, AvgLoadingTime, MaxLoadingTime, MinLeftPercent, AvgLeftPercent, MaxLeftPercent, MinDuration, AvgDuration, MaxDuration ); + QString FirstGameDateTime = Row[0]; + QString LastGameDateTime = Row[1]; + quint32 TotalGames = UTIL_ToUInt32( Row[2] ); + quint32 MinLoadingTime = UTIL_ToUInt32( Row[3] ); + quint32 AvgLoadingTime = UTIL_ToUInt32( Row[4] ); + quint32 MaxLoadingTime = UTIL_ToUInt32( Row[5] ); + quint32 MinLeftPercent = UTIL_ToUInt32( Row[6] ); + quint32 AvgLeftPercent = UTIL_ToUInt32( Row[7] ); + quint32 MaxLeftPercent = UTIL_ToUInt32( Row[8] ); + quint32 MinDuration = UTIL_ToUInt32( Row[9] ); + quint32 AvgDuration = UTIL_ToUInt32( Row[10] ); + quint32 MaxDuration = UTIL_ToUInt32( Row[11] ); + GamePlayerSummary = new CDBGamePlayerSummary( QString( ), name, FirstGameDateTime, LastGameDateTime, TotalGames, MinLoadingTime, AvgLoadingTime, MaxLoadingTime, MinLeftPercent, AvgLeftPercent, MaxLeftPercent, MinDuration, AvgDuration, MaxDuration ); } else *error = "error checking gameplayersummary [" + name + "] - row doesn't have 12 columns"; @@ -856,10 +854,10 @@ CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, string *error, ui return GamePlayerSummary; } -uint32_t MySQLDotAGameAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) +quint32 MySQLDotAGameAdd( void *conn, QString *error, quint32 botid, quint32 gameid, quint32 winner, quint32 min, quint32 sec ) { - uint32_t RowID = 0; - string Query = "INSERT INTO dotagames ( botid, gameid, winner, min, sec ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( winner ) + ", " + UTIL_ToString( min ) + ", " + UTIL_ToString( sec ) + " )"; + quint32 RowID = 0; + QString Query = "INSERT INTO dotagames ( botid, gameid, winner, min, sec ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( winner ) + ", " + UTIL_ToString( min ) + ", " + UTIL_ToString( sec ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -869,17 +867,17 @@ uint32_t MySQLDotAGameAdd( void *conn, string *error, uint32_t botid, uint32_t g return RowID; } -uint32_t MySQLDotAPlayerAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) +quint32 MySQLDotAPlayerAdd( void *conn, QString *error, quint32 botid, quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ) { - uint32_t RowID = 0; - string EscItem1 = MySQLEscapeString( conn, item1 ); - string EscItem2 = MySQLEscapeString( conn, item2 ); - string EscItem3 = MySQLEscapeString( conn, item3 ); - string EscItem4 = MySQLEscapeString( conn, item4 ); - string EscItem5 = MySQLEscapeString( conn, item5 ); - string EscItem6 = MySQLEscapeString( conn, item6 ); - string EscHero = MySQLEscapeString( conn, hero ); - string Query = "INSERT INTO dotaplayers ( botid, gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( colour ) + ", " + UTIL_ToString( kills ) + ", " + UTIL_ToString( deaths ) + ", " + UTIL_ToString( creepkills ) + ", " + UTIL_ToString( creepdenies ) + ", " + UTIL_ToString( assists ) + ", " + UTIL_ToString( gold ) + ", " + UTIL_ToString( neutralkills ) + ", '" + EscItem1 + "', '" + EscItem2 + "', '" + EscItem3 + "', '" + EscItem4 + "', '" + EscItem5 + "', '" + EscItem6 + "', '" + EscHero + "', " + UTIL_ToString( newcolour ) + ", " + UTIL_ToString( towerkills ) + ", " + UTIL_ToString( raxkills ) + ", " + UTIL_ToString( courierkills ) + " )"; + quint32 RowID = 0; + QString EscItem1 = MySQLEscapeString( conn, item1 ); + QString EscItem2 = MySQLEscapeString( conn, item2 ); + QString EscItem3 = MySQLEscapeString( conn, item3 ); + QString EscItem4 = MySQLEscapeString( conn, item4 ); + QString EscItem5 = MySQLEscapeString( conn, item5 ); + QString EscItem6 = MySQLEscapeString( conn, item6 ); + QString EscHero = MySQLEscapeString( conn, hero ); + QString Query = "INSERT INTO dotaplayers ( botid, gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( colour ) + ", " + UTIL_ToString( kills ) + ", " + UTIL_ToString( deaths ) + ", " + UTIL_ToString( creepkills ) + ", " + UTIL_ToString( creepdenies ) + ", " + UTIL_ToString( assists ) + ", " + UTIL_ToString( gold ) + ", " + UTIL_ToString( neutralkills ) + ", '" + EscItem1 + "', '" + EscItem2 + "', '" + EscItem3 + "', '" + EscItem4 + "', '" + EscItem5 + "', '" + EscItem6 + "', '" + EscHero + "', " + UTIL_ToString( newcolour ) + ", " + UTIL_ToString( towerkills ) + ", " + UTIL_ToString( raxkills ) + ", " + UTIL_ToString( courierkills ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -889,12 +887,12 @@ uint32_t MySQLDotAPlayerAdd( void *conn, string *error, uint32_t botid, uint32_t return RowID; } -CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, uint32_t botid, string name ) +CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, QString *error, quint32 botid, QString name ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - string EscName = MySQLEscapeString( conn, name ); + QString EscName = MySQLEscapeString( conn, name ); CDBDotAPlayerSummary *DotAPlayerSummary = NULL; - string Query = "SELECT COUNT(dotaplayers.id), SUM(kills), SUM(deaths), SUM(creepkills), SUM(creepdenies), SUM(assists), SUM(neutralkills), SUM(towerkills), SUM(raxkills), SUM(courierkills) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour WHERE LOWER(name)='" + EscName + "'"; + QString Query = "SELECT COUNT(dotaplayers.id), SUM(kills), SUM(deaths), SUM(creepkills), SUM(creepdenies), SUM(assists), SUM(neutralkills), SUM(towerkills), SUM(raxkills), SUM(courierkills) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour WHERE LOWER(name)='" + EscName + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -904,29 +902,29 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 10 ) { - uint32_t TotalGames = UTIL_ToUInt32( Row[0] ); + quint32 TotalGames = UTIL_ToUInt32( Row[0] ); if( TotalGames > 0 ) { - uint32_t TotalWins = 0; - uint32_t TotalLosses = 0; - uint32_t TotalKills = UTIL_ToUInt32( Row[1] ); - uint32_t TotalDeaths = UTIL_ToUInt32( Row[2] ); - uint32_t TotalCreepKills = UTIL_ToUInt32( Row[3] ); - uint32_t TotalCreepDenies = UTIL_ToUInt32( Row[4] ); - uint32_t TotalAssists = UTIL_ToUInt32( Row[5] ); - uint32_t TotalNeutralKills = UTIL_ToUInt32( Row[6] ); - uint32_t TotalTowerKills = UTIL_ToUInt32( Row[7] ); - uint32_t TotalRaxKills = UTIL_ToUInt32( Row[8] ); - uint32_t TotalCourierKills = UTIL_ToUInt32( Row[9] ); + quint32 TotalWins = 0; + quint32 TotalLosses = 0; + quint32 TotalKills = UTIL_ToUInt32( Row[1] ); + quint32 TotalDeaths = UTIL_ToUInt32( Row[2] ); + quint32 TotalCreepKills = UTIL_ToUInt32( Row[3] ); + quint32 TotalCreepDenies = UTIL_ToUInt32( Row[4] ); + quint32 TotalAssists = UTIL_ToUInt32( Row[5] ); + quint32 TotalNeutralKills = UTIL_ToUInt32( Row[6] ); + quint32 TotalTowerKills = UTIL_ToUInt32( Row[7] ); + quint32 TotalRaxKills = UTIL_ToUInt32( Row[8] ); + quint32 TotalCourierKills = UTIL_ToUInt32( Row[9] ); // calculate total wins - string Query2 = "SELECT COUNT(*) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour LEFT JOIN dotagames ON games.id=dotagames.gameid WHERE name='" + EscName + "' AND ((winner=1 AND dotaplayers.newcolour>=1 AND dotaplayers.newcolour<=5) OR (winner=2 AND dotaplayers.newcolour>=7 AND dotaplayers.newcolour<=11))"; + QString Query2 = "SELECT COUNT(*) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour LEFT JOIN dotagames ON games.id=dotagames.gameid WHERE name='" + EscName + "' AND ((winner=1 AND dotaplayers.newcolour>=1 AND dotaplayers.newcolour<=5) OR (winner=2 AND dotaplayers.newcolour>=7 AND dotaplayers.newcolour<=11))"; if( mysql_real_query( (MYSQL *)conn, Query2.c_str( ), Query2.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -936,7 +934,7 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui if( Result2 ) { - vector Row2 = MySQLFetchRow( Result2 ); + QList Row2 = MySQLFetchRow( Result2 ); if( Row2.size( ) == 1 ) TotalWins = UTIL_ToUInt32( Row2[0] ); @@ -951,7 +949,7 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui // calculate total losses - string Query3 = "SELECT COUNT(*) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour LEFT JOIN dotagames ON games.id=dotagames.gameid WHERE name='" + EscName + "' AND ((winner=2 AND dotaplayers.newcolour>=1 AND dotaplayers.newcolour<=5) OR (winner=1 AND dotaplayers.newcolour>=7 AND dotaplayers.newcolour<=11))"; + QString Query3 = "SELECT COUNT(*) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour LEFT JOIN dotagames ON games.id=dotagames.gameid WHERE name='" + EscName + "' AND ((winner=2 AND dotaplayers.newcolour>=1 AND dotaplayers.newcolour<=5) OR (winner=1 AND dotaplayers.newcolour>=7 AND dotaplayers.newcolour<=11))"; if( mysql_real_query( (MYSQL *)conn, Query3.c_str( ), Query3.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -961,7 +959,7 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui if( Result3 ) { - vector Row3 = MySQLFetchRow( Result3 ); + QList Row3 = MySQLFetchRow( Result3 ); if( Row3.size( ) == 1 ) TotalLosses = UTIL_ToUInt32( Row3[0] ); @@ -976,7 +974,7 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui // done - DotAPlayerSummary = new CDBDotAPlayerSummary( string( ), name, TotalGames, TotalWins, TotalLosses, TotalKills, TotalDeaths, TotalCreepKills, TotalCreepDenies, TotalAssists, TotalNeutralKills, TotalTowerKills, TotalRaxKills, TotalCourierKills ); + DotAPlayerSummary = new CDBDotAPlayerSummary( QString( ), name, TotalGames, TotalWins, TotalLosses, TotalKills, TotalDeaths, TotalCreepKills, TotalCreepDenies, TotalAssists, TotalNeutralKills, TotalTowerKills, TotalRaxKills, TotalCourierKills ); } } else @@ -991,14 +989,14 @@ CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, string *error, ui return DotAPlayerSummary; } -bool MySQLDownloadAdd( void *conn, string *error, uint32_t botid, string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) +bool MySQLDownloadAdd( void *conn, QString *error, quint32 botid, QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ) { bool Success = false; - string EscMap = MySQLEscapeString( conn, map ); - string EscName = MySQLEscapeString( conn, name ); - string EscIP = MySQLEscapeString( conn, ip ); - string EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); - string Query = "INSERT INTO downloads ( botid, map, mapsize, datetime, name, ip, spoofed, spoofedrealm, downloadtime ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscMap + "', " + UTIL_ToString( mapsize ) + ", NOW( ), '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", '" + EscSpoofedRealm + "', " + UTIL_ToString( downloadtime ) + " )"; + QString EscMap = MySQLEscapeString( conn, map ); + QString EscName = MySQLEscapeString( conn, name ); + QString EscIP = MySQLEscapeString( conn, ip ); + QString EscSpoofedRealm = MySQLEscapeString( conn, spoofedrealm ); + QString Query = "INSERT INTO downloads ( botid, map, mapsize, datetime, name, ip, spoofed, spoofedrealm, downloadtime ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscMap + "', " + UTIL_ToString( mapsize ) + ", NOW( ), '" + EscName + "', '" + EscIP + "', " + UTIL_ToString( spoofed ) + ", '" + EscSpoofedRealm + "', " + UTIL_ToString( downloadtime ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -1008,14 +1006,14 @@ bool MySQLDownloadAdd( void *conn, string *error, uint32_t botid, string map, ui return Success; } -double MySQLScoreCheck( void *conn, string *error, uint32_t botid, string category, string name, string server ) +double MySQLScoreCheck( void *conn, QString *error, quint32 botid, QString category, QString name, QString server ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - string EscCategory = MySQLEscapeString( conn, category ); - string EscName = MySQLEscapeString( conn, name ); - string EscServer = MySQLEscapeString( conn, server ); + QString EscCategory = MySQLEscapeString( conn, category ); + QString EscName = MySQLEscapeString( conn, name ); + QString EscServer = MySQLEscapeString( conn, server ); double Score = -100000.0; - string Query = "SELECT score FROM scores WHERE category='" + EscCategory + "' AND name='" + EscName + "' AND server='" + EscServer + "'"; + QString Query = "SELECT score FROM scores WHERE category='" + EscCategory + "' AND name='" + EscName + "' AND server='" + EscServer + "'"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -1025,7 +1023,7 @@ double MySQLScoreCheck( void *conn, string *error, uint32_t botid, string catego if( Result ) { - vector Row = MySQLFetchRow( Result ); + QList Row = MySQLFetchRow( Result ); if( Row.size( ) == 1 ) Score = UTIL_ToDouble( Row[0] ); @@ -1041,14 +1039,14 @@ double MySQLScoreCheck( void *conn, string *error, uint32_t botid, string catego return Score; } -uint32_t MySQLW3MMDPlayerAdd( void *conn, string *error, uint32_t botid, string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) +quint32 MySQLW3MMDPlayerAdd( void *conn, QString *error, quint32 botid, QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ) { transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t RowID = 0; - string EscCategory = MySQLEscapeString( conn, category ); - string EscName = MySQLEscapeString( conn, name ); - string EscFlag = MySQLEscapeString( conn, flag ); - string Query = "INSERT INTO w3mmdplayers ( botid, category, gameid, pid, name, flag, leaver, practicing ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscCategory + "', " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( pid ) + ", '" + EscName + "', '" + EscFlag + "', " + UTIL_ToString( leaver ) + ", " + UTIL_ToString( practicing ) + " )"; + quint32 RowID = 0; + QString EscCategory = MySQLEscapeString( conn, category ); + QString EscName = MySQLEscapeString( conn, name ); + QString EscFlag = MySQLEscapeString( conn, flag ); + QString Query = "INSERT INTO w3mmdplayers ( botid, category, gameid, pid, name, flag, leaver, practicing ) VALUES ( " + UTIL_ToString( botid ) + ", '" + EscCategory + "', " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( pid ) + ", '" + EscName + "', '" + EscFlag + "', " + UTIL_ToString( leaver ) + ", " + UTIL_ToString( practicing ) + " )"; if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 ) *error = mysql_error( (MYSQL *)conn ); @@ -1058,19 +1056,19 @@ uint32_t MySQLW3MMDPlayerAdd( void *conn, string *error, uint32_t botid, string return RowID; } -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_ints ) +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_ints ) { - if( var_ints.empty( ) ) + if( var_ints.isEmpty( ) ) return false; bool Success = false; - string Query; + QString Query; - for( map :: iterator i = var_ints.begin( ); i != var_ints.end( ); i++ ) + for( QMap :: const_iterator i = var_ints.begin( ); i != var_ints.end( ); i++ ) { - string EscVarName = MySQLEscapeString( conn, i->first.second ); + QString EscVarName = MySQLEscapeString( conn, i->first.second ); - if( Query.empty( ) ) + if( Query.isEmpty( ) ) Query = "INSERT INTO w3mmdvars ( botid, gameid, pid, varname, value_int ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', " + UTIL_ToString( i->second ) + " )"; else Query += ", ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', " + UTIL_ToString( i->second ) + " )"; @@ -1084,19 +1082,19 @@ bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gamei return Success; } -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_reals ) +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_reals ) { - if( var_reals.empty( ) ) + if( var_reals.isEmpty( ) ) return false; bool Success = false; - string Query; + QString Query; - for( map :: iterator i = var_reals.begin( ); i != var_reals.end( ); i++ ) + for( QMap :: const_iterator i = var_reals.begin( ); i != var_reals.end( ); i++ ) { - string EscVarName = MySQLEscapeString( conn, i->first.second ); + QString EscVarName = MySQLEscapeString( conn, i->first.second ); - if( Query.empty( ) ) + if( Query.isEmpty( ) ) Query = "INSERT INTO w3mmdvars ( botid, gameid, pid, varname, value_real ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', " + UTIL_ToString( i->second, 10 ) + " )"; else Query += ", ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', " + UTIL_ToString( i->second, 10 ) + " )"; @@ -1110,21 +1108,21 @@ bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gamei return Success; } -bool MySQLW3MMDVarAdd( void *conn, string *error, uint32_t botid, uint32_t gameid, map var_strings ) +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_strings ) { - if( var_strings.empty( ) ) + if( var_strings.isEmpty( ) ) return false; bool Success = false; - string Query; + QString Query; - for( map :: iterator i = var_strings.begin( ); i != var_strings.end( ); i++ ) + for( QMap :: const_iterator i = var_strings.begin( ); i != var_strings.end( ); i++ ) { - string EscVarName = MySQLEscapeString( conn, i->first.second ); - string EscValueString = MySQLEscapeString( conn, i->second ); + QString EscVarName = MySQLEscapeString( conn, i->first.second ); + QString EscValueString = MySQLEscapeString( conn, i->second ); - if( Query.empty( ) ) - Query = "INSERT INTO w3mmdvars ( botid, gameid, pid, varname, value_string ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', '" + EscValueString + "' )"; + if( Query.isEmpty( ) ) + Query = "INSERT INTO w3mmdvars ( botid, gameid, pid, varname, value_QString ) VALUES ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', '" + EscValueString + "' )"; else Query += ", ( " + UTIL_ToString( botid ) + ", " + UTIL_ToString( gameid ) + ", " + UTIL_ToString( i->first.first ) + ", '" + EscVarName + "', '" + EscValueString + "' )"; } @@ -1180,7 +1178,7 @@ void CMySQLCallableAdminCount :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLAdminCount( m_Connection, &m_Error, m_SQLBotID, m_Server ); Close( ); @@ -1190,7 +1188,7 @@ void CMySQLCallableAdminCheck :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLAdminCheck( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User ); Close( ); @@ -1200,7 +1198,7 @@ void CMySQLCallableAdminAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLAdminAdd( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User ); Close( ); @@ -1210,7 +1208,7 @@ void CMySQLCallableAdminRemove :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLAdminRemove( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User ); Close( ); @@ -1220,7 +1218,7 @@ void CMySQLCallableAdminList :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLAdminList( m_Connection, &m_Error, m_SQLBotID, m_Server ); Close( ); @@ -1230,7 +1228,7 @@ void CMySQLCallableBanCount :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLBanCount( m_Connection, &m_Error, m_SQLBotID, m_Server ); Close( ); @@ -1240,7 +1238,7 @@ void CMySQLCallableBanCheck :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLBanCheck( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User, m_IP ); Close( ); @@ -1250,7 +1248,7 @@ void CMySQLCallableBanAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLBanAdd( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User, m_IP, m_GameName, m_Admin, m_Reason ); Close( ); @@ -1260,9 +1258,9 @@ void CMySQLCallableBanRemove :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) { - if( m_Server.empty( ) ) + if( m_Server.isEmpty( ) ) m_Result = MySQLBanRemove( m_Connection, &m_Error, m_SQLBotID, m_User ); else m_Result = MySQLBanRemove( m_Connection, &m_Error, m_SQLBotID, m_Server, m_User ); @@ -1275,7 +1273,7 @@ void CMySQLCallableBanList :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLBanList( m_Connection, &m_Error, m_SQLBotID, m_Server ); Close( ); @@ -1285,7 +1283,7 @@ void CMySQLCallableGameAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLGameAdd( m_Connection, &m_Error, m_SQLBotID, m_Server, m_Map, m_GameName, m_OwnerName, m_Duration, m_GameState, m_CreatorName, m_CreatorServer ); Close( ); @@ -1295,7 +1293,7 @@ void CMySQLCallableGamePlayerAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLGamePlayerAdd( m_Connection, &m_Error, m_SQLBotID, m_GameID, m_Name, m_IP, m_Spoofed, m_SpoofedRealm, m_Reserved, m_LoadingTime, m_Left, m_LeftReason, m_Team, m_Colour ); Close( ); @@ -1305,7 +1303,7 @@ void CMySQLCallableGamePlayerSummaryCheck :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLGamePlayerSummaryCheck( m_Connection, &m_Error, m_SQLBotID, m_Name ); Close( ); @@ -1315,7 +1313,7 @@ void CMySQLCallableDotAGameAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLDotAGameAdd( m_Connection, &m_Error, m_SQLBotID, m_GameID, m_Winner, m_Min, m_Sec ); Close( ); @@ -1325,7 +1323,7 @@ void CMySQLCallableDotAPlayerAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLDotAPlayerAdd( m_Connection, &m_Error, m_SQLBotID, m_GameID, m_Colour, m_Kills, m_Deaths, m_CreepKills, m_CreepDenies, m_Assists, m_Gold, m_NeutralKills, m_Item1, m_Item2, m_Item3, m_Item4, m_Item5, m_Item6, m_Hero, m_NewColour, m_TowerKills, m_RaxKills, m_CourierKills ); Close( ); @@ -1335,7 +1333,7 @@ void CMySQLCallableDotAPlayerSummaryCheck :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLDotAPlayerSummaryCheck( m_Connection, &m_Error, m_SQLBotID, m_Name ); Close( ); @@ -1345,7 +1343,7 @@ void CMySQLCallableDownloadAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLDownloadAdd( m_Connection, &m_Error, m_SQLBotID, m_Map, m_MapSize, m_Name, m_IP, m_Spoofed, m_SpoofedRealm, m_DownloadTime ); Close( ); @@ -1355,7 +1353,7 @@ void CMySQLCallableScoreCheck :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLScoreCheck( m_Connection, &m_Error, m_SQLBotID, m_Category, m_Name, m_Server ); Close( ); @@ -1365,7 +1363,7 @@ void CMySQLCallableW3MMDPlayerAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) m_Result = MySQLW3MMDPlayerAdd( m_Connection, &m_Error, m_SQLBotID, m_Category, m_GameID, m_PID, m_Name, m_Flag, m_Leaver, m_Practicing ); Close( ); @@ -1375,7 +1373,7 @@ void CMySQLCallableW3MMDVarAdd :: operator( )( ) { Init( ); - if( m_Error.empty( ) ) + if( m_Error.isEmpty( ) ) { if( m_ValueType == VALUETYPE_INT ) m_Result = MySQLW3MMDVarAdd( m_Connection, &m_Error, m_SQLBotID, m_GameID, m_VarInts ); diff --git a/src/libghost/ghostdbmysql.h b/src/libghost/ghostdbmysql.h new file mode 100644 index 0000000..d798545 --- /dev/null +++ b/src/libghost/ghostdbmysql.h @@ -0,0 +1,497 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifdef GHOST_MYSQL + +#ifndef GHOSTDBMYSQL_H +#define GHOSTDBMYSQL_H + +/************** + *** SCHEMA *** + ************** + +CREATE TABLE admins ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + name VARCHAR(15) NOT NULL, + server VARCHAR(100) NOT NULL +) + +CREATE TABLE bans ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + server VARCHAR(100) NOT NULL, + name VARCHAR(15) NOT NULL, + ip VARCHAR(15) NOT NULL, + date DATETIME NOT NULL, + gamename VARCHAR(31) NOT NULL, + admin VARCHAR(15) NOT NULL, + reason VARCHAR(255) NOT NULL +) + +CREATE TABLE games ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + server VARCHAR(100) NOT NULL, + map VARCHAR(100) NOT NULL, + datetime DATETIME NOT NULL, + gamename VARCHAR(31) NOT NULL, + ownername VARCHAR(15) NOT NULL, + duration INT NOT NULL, + gamestate INT NOT NULL, + creatorname VARCHAR(15) NOT NULL, + creatorserver VARCHAR(100) NOT NULL +) + +CREATE TABLE gameplayers ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + gameid INT NOT NULL, + name VARCHAR(15) NOT NULL, + ip VARCHAR(15) NOT NULL, + spoofed INT NOT NULL, + reserved INT NOT NULL, + loadingtime INT NOT NULL, + `left` INT NOT NULL, + leftreason VARCHAR(100) NOT NULL, + team INT NOT NULL, + colour INT NOT NULL, + spoofedrealm VARCHAR(100) NOT NULL, + INDEX( gameid ) +) + +CREATE TABLE dotagames ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + gameid INT NOT NULL, + winner INT NOT NULL, + min INT NOT NULL, + sec INT NOT NULL +) + +CREATE TABLE dotaplayers ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + gameid INT NOT NULL, + colour INT NOT NULL, + kills INT NOT NULL, + deaths INT NOT NULL, + creepkills INT NOT NULL, + creepdenies INT NOT NULL, + assists INT NOT NULL, + gold INT NOT NULL, + neutralkills INT NOT NULL, + item1 CHAR(4) NOT NULL, + item2 CHAR(4) NOT NULL, + item3 CHAR(4) NOT NULL, + item4 CHAR(4) NOT NULL, + item5 CHAR(4) NOT NULL, + item6 CHAR(4) NOT NULL, + hero CHAR(4) NOT NULL, + newcolour INT NOT NULL, + towerkills INT NOT NULL, + raxkills INT NOT NULL, + courierkills INT NOT NULL, + INDEX( gameid, colour ) +) + +CREATE TABLE downloads ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + map VARCHAR(100) NOT NULL, + mapsize INT NOT NULL, + datetime DATETIME NOT NULL, + name VARCHAR(15) NOT NULL, + ip VARCHAR(15) NOT NULL, + spoofed INT NOT NULL, + spoofedrealm VARCHAR(100) NOT NULL, + downloadtime INT NOT NULL +) + +CREATE TABLE scores ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + category VARCHAR(25) NOT NULL, + name VARCHAR(15) NOT NULL, + server VARCHAR(100) NOT NULL, + score REAL NOT NULL +) + +CREATE TABLE w3mmdplayers ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + category VARCHAR(25) NOT NULL, + gameid INT NOT NULL, + pid INT NOT NULL, + name VARCHAR(15) NOT NULL, + flag VARCHAR(32) NOT NULL, + leaver INT NOT NULL, + practicing INT NOT NULL +) + +CREATE TABLE w3mmdvars ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + botid INT NOT NULL, + gameid INT NOT NULL, + pid INT NOT NULL, + varname VARCHAR(25) NOT NULL, + value_int INT DEFAULT NULL, + value_real REAL DEFAULT NULL, + value_string VARCHAR(100) DEFAULT NULL +) + + ************** + *** SCHEMA *** + **************/ + +// +// CGHostDBMySQL +// + +class CGHostDBMySQL : public CGHostDB +{ +private: + QString m_Server; + QString m_Database; + QString m_User; + QString m_Password; + quint16 m_Port; + quint32 m_BotID; + QQueue m_IdleConnections; + quint32 m_NumConnections; + quint32 m_OutstandingCallables; + +public: + CGHostDBMySQL( CConfig *CFG ); + virtual ~CGHostDBMySQL( ); + + virtual QString GetStatus( ); + + virtual void RecoverCallable( CBaseCallable *callable ); + + // threaded database functions + + virtual void CreateThread( CBaseCallable *callable ); + virtual CCallableAdminCount *ThreadedAdminCount( QString server ); + virtual CCallableAdminCheck *ThreadedAdminCheck( QString server, QString user ); + virtual CCallableAdminAdd *ThreadedAdminAdd( QString server, QString user ); + virtual CCallableAdminRemove *ThreadedAdminRemove( QString server, QString user ); + virtual CCallableAdminList *ThreadedAdminList( QString server ); + virtual CCallableBanCount *ThreadedBanCount( QString server ); + virtual CCallableBanCheck *ThreadedBanCheck( QString server, QString user, QString ip ); + virtual CCallableBanAdd *ThreadedBanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); + virtual CCallableBanRemove *ThreadedBanRemove( QString server, QString user ); + virtual CCallableBanRemove *ThreadedBanRemove( QString user ); + virtual CCallableBanList *ThreadedBanList( QString server ); + virtual CCallableGameAdd *ThreadedGameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); + virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); + virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( QString name ); + virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ); + virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); + virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( QString name ); + virtual CCallableDownloadAdd *ThreadedDownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); + virtual CCallableScoreCheck *ThreadedScoreCheck( QString category, QString name, QString server ); + virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_ints ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_reals ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_strings ); + + // other database functions + + virtual void *GetIdleConnection( ); +}; + +// +// global helper functions +// + +quint32 MySQLAdminCount( void *conn, QString *error, quint32 botid, QString server ); +bool MySQLAdminCheck( void *conn, QString *error, quint32 botid, QString server, QString user ); +bool MySQLAdminAdd( void *conn, QString *error, quint32 botid, QString server, QString user ); +bool MySQLAdminRemove( void *conn, QString *error, quint32 botid, QString server, QString user ); +QList MySQLAdminList( void *conn, QString *error, quint32 botid, QString server ); +quint32 MySQLBanCount( void *conn, QString *error, quint32 botid, QString server ); +CDBBan *MySQLBanCheck( void *conn, QString *error, quint32 botid, QString server, QString user, QString ip ); +bool MySQLBanAdd( void *conn, QString *error, quint32 botid, QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); +bool MySQLBanRemove( void *conn, QString *error, quint32 botid, QString server, QString user ); +bool MySQLBanRemove( void *conn, QString *error, quint32 botid, QString user ); +QList MySQLBanList( void *conn, QString *error, quint32 botid, QString server ); +quint32 MySQLGameAdd( void *conn, QString *error, quint32 botid, QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); +quint32 MySQLGamePlayerAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); +CDBGamePlayerSummary *MySQLGamePlayerSummaryCheck( void *conn, QString *error, quint32 botid, QString name ); +quint32 MySQLDotAGameAdd( void *conn, QString *error, quint32 botid, quint32 gameid, quint32 winner, quint32 min, quint32 sec ); +quint32 MySQLDotAPlayerAdd( void *conn, QString *error, quint32 botid, quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); +CDBDotAPlayerSummary *MySQLDotAPlayerSummaryCheck( void *conn, QString *error, quint32 botid, QString name ); +bool MySQLDownloadAdd( void *conn, QString *error, quint32 botid, QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); +double MySQLScoreCheck( void *conn, QString *error, quint32 botid, QString category, QString name, QString server ); +quint32 MySQLW3MMDPlayerAdd( void *conn, QString *error, quint32 botid, QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_ints ); +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_reals ); +bool MySQLW3MMDVarAdd( void *conn, QString *error, quint32 botid, quint32 gameid, QMap var_strings ); + +// +// MySQL Callables +// + +class CMySQLCallable : virtual public CBaseCallable +{ +protected: + void *m_Connection; + QString m_SQLServer; + QString m_SQLDatabase; + QString m_SQLUser; + QString m_SQLPassword; + quint16 m_SQLPort; + quint32 m_SQLBotID; + +public: + CMySQLCallable( void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), m_Connection( nConnection ), m_SQLBotID( nSQLBotID ), m_SQLServer( nSQLServer ), m_SQLDatabase( nSQLDatabase ), m_SQLUser( nSQLUser ), m_SQLPassword( nSQLPassword ), m_SQLPort( nSQLPort ) { } + virtual ~CMySQLCallable( ) { } + + virtual void *GetConnection( ) { return m_Connection; } + + virtual void Init( ); + virtual void Close( ); +}; + +class CMySQLCallableAdminCount : public CCallableAdminCount, public CMySQLCallable +{ +public: + CMySQLCallableAdminCount( QString nServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableAdminCount( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableAdminCount( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableAdminCheck : public CCallableAdminCheck, public CMySQLCallable +{ +public: + CMySQLCallableAdminCheck( QString nServer, QString nUser, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableAdminCheck( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableAdminCheck( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableAdminAdd : public CCallableAdminAdd, public CMySQLCallable +{ +public: + CMySQLCallableAdminAdd( QString nServer, QString nUser, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableAdminAdd( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableAdminAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableAdminRemove : public CCallableAdminRemove, public CMySQLCallable +{ +public: + CMySQLCallableAdminRemove( QString nServer, QString nUser, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableAdminRemove( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableAdminRemove( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableAdminList : public CCallableAdminList, public CMySQLCallable +{ +public: + CMySQLCallableAdminList( QString nServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableAdminList( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableAdminList( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableBanCount : public CCallableBanCount, public CMySQLCallable +{ +public: + CMySQLCallableBanCount( QString nServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableBanCount( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableBanCount( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableBanCheck : public CCallableBanCheck, public CMySQLCallable +{ +public: + CMySQLCallableBanCheck( QString nServer, QString nUser, QString nIP, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableBanCheck( nServer, nUser, nIP ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableBanCheck( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableBanAdd : public CCallableBanAdd, public CMySQLCallable +{ +public: + CMySQLCallableBanAdd( QString nServer, QString nUser, QString nIP, QString nGameName, QString nAdmin, QString nReason, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableBanAdd( nServer, nUser, nIP, nGameName, nAdmin, nReason ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableBanAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableBanRemove : public CCallableBanRemove, public CMySQLCallable +{ +public: + CMySQLCallableBanRemove( QString nServer, QString nUser, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableBanRemove( nServer, nUser ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableBanRemove( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableBanList : public CCallableBanList, public CMySQLCallable +{ +public: + CMySQLCallableBanList( QString nServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableBanList( nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableBanList( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableGameAdd : public CCallableGameAdd, public CMySQLCallable +{ +public: + CMySQLCallableGameAdd( QString nServer, QString nMap, QString nGameName, QString nOwnerName, quint32 nDuration, quint32 nGameState, QString nCreatorName, QString nCreatorServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableGameAdd( nServer, nMap, nGameName, nOwnerName, nDuration, nGameState, nCreatorName, nCreatorServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableGameAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableGamePlayerAdd : public CCallableGamePlayerAdd, public CMySQLCallable +{ +public: + CMySQLCallableGamePlayerAdd( quint32 nGameID, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nReserved, quint32 nLoadingTime, quint32 nLeft, QString nLeftReason, quint32 nTeam, quint32 nColour, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableGamePlayerAdd( nGameID, nName, nIP, nSpoofed, nSpoofedRealm, nReserved, nLoadingTime, nLeft, nLeftReason, nTeam, nColour ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableGamePlayerAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableGamePlayerSummaryCheck : public CCallableGamePlayerSummaryCheck, public CMySQLCallable +{ +public: + CMySQLCallableGamePlayerSummaryCheck( QString nName, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableGamePlayerSummaryCheck( nName ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableGamePlayerSummaryCheck( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableDotAGameAdd : public CCallableDotAGameAdd, public CMySQLCallable +{ +public: + CMySQLCallableDotAGameAdd( quint32 nGameID, quint32 nWinner, quint32 nMin, quint32 nSec, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableDotAGameAdd( nGameID, nWinner, nMin, nSec ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableDotAGameAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableDotAPlayerAdd : public CCallableDotAPlayerAdd, public CMySQLCallable +{ +public: + CMySQLCallableDotAPlayerAdd( quint32 nGameID, quint32 nColour, quint32 nKills, quint32 nDeaths, quint32 nCreepKills, quint32 nCreepDenies, quint32 nAssists, quint32 nGold, quint32 nNeutralKills, QString nItem1, QString nItem2, QString nItem3, QString nItem4, QString nItem5, QString nItem6, QString nHero, quint32 nNewColour, quint32 nTowerKills, quint32 nRaxKills, quint32 nCourierKills, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableDotAPlayerAdd( nGameID, nColour, nKills, nDeaths, nCreepKills, nCreepDenies, nAssists, nGold, nNeutralKills, nItem1, nItem2, nItem3, nItem4, nItem5, nItem6, nHero, nNewColour, nTowerKills, nRaxKills, nCourierKills ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableDotAPlayerAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableDotAPlayerSummaryCheck : public CCallableDotAPlayerSummaryCheck, public CMySQLCallable +{ +public: + CMySQLCallableDotAPlayerSummaryCheck( QString nName, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableDotAPlayerSummaryCheck( nName ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableDotAPlayerSummaryCheck( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableDownloadAdd : public CCallableDownloadAdd, public CMySQLCallable +{ +public: + CMySQLCallableDownloadAdd( QString nMap, quint32 nMapSize, QString nName, QString nIP, quint32 nSpoofed, QString nSpoofedRealm, quint32 nDownloadTime, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableDownloadAdd( nMap, nMapSize, nName, nIP, nSpoofed, nSpoofedRealm, nDownloadTime ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableDownloadAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableScoreCheck : public CCallableScoreCheck, public CMySQLCallable +{ +public: + CMySQLCallableScoreCheck( QString nCategory, QString nName, QString nServer, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableScoreCheck( nCategory, nName, nServer ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableScoreCheck( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableW3MMDPlayerAdd : public CCallableW3MMDPlayerAdd, public CMySQLCallable +{ +public: + CMySQLCallableW3MMDPlayerAdd( QString nCategory, quint32 nGameID, quint32 nPID, QString nName, QString nFlag, quint32 nLeaver, quint32 nPracticing, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableW3MMDPlayerAdd( nCategory, nGameID, nPID, nName, nFlag, nLeaver, nPracticing ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableW3MMDPlayerAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +class CMySQLCallableW3MMDVarAdd : public CCallableW3MMDVarAdd, public CMySQLCallable +{ +public: + CMySQLCallableW3MMDVarAdd( quint32 nGameID, QMap nVarInts, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarInts ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + CMySQLCallableW3MMDVarAdd( quint32 nGameID, QMap nVarReals, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarReals ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + CMySQLCallableW3MMDVarAdd( quint32 nGameID, QMap nVarStrings, void *nConnection, quint32 nSQLBotID, QString nSQLServer, QString nSQLDatabase, QString nSQLUser, QString nSQLPassword, quint16 nSQLPort ) : CBaseCallable( ), CCallableW3MMDVarAdd( nGameID, nVarStrings ), CMySQLCallable( nConnection, nSQLBotID, nSQLServer, nSQLDatabase, nSQLUser, nSQLPassword, nSQLPort ) { } + virtual ~CMySQLCallableW3MMDVarAdd( ) { } + + virtual void operator( )( ); + virtual void Init( ) { CMySQLCallable :: Init( ); } + virtual void Close( ) { CMySQLCallable :: Close( ); } +}; + +#endif + +#endif diff --git a/ghost/ghostdbsqlite.cpp b/src/libghost/ghostdbsqlite.cpp similarity index 68% rename from ghost/ghostdbsqlite.cpp rename to src/libghost/ghostdbsqlite.cpp index 2c08443..2c15190 100644 --- a/ghost/ghostdbsqlite.cpp +++ b/src/libghost/ghostdbsqlite.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -29,11 +29,11 @@ // CQSLITE3 (wrapper class) // -CSQLITE3 :: CSQLITE3( string filename ) +CSQLITE3 :: CSQLITE3( QString filename ) { m_Ready = true; - if( sqlite3_open_v2( filename.c_str( ), (sqlite3 **)&m_DB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL ) != SQLITE_OK ) + if( sqlite3_open_v2( filename.toUtf8().data(), (sqlite3 **)&m_DB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL ) != SQLITE_OK ) m_Ready = false; } @@ -42,14 +42,14 @@ CSQLITE3 :: ~CSQLITE3( ) sqlite3_close( (sqlite3 *)m_DB ); } -string CSQLITE3 :: GetError( ) +QString CSQLITE3 :: GetError( ) { return sqlite3_errmsg( (sqlite3 *)m_DB ); } -int CSQLITE3 :: Prepare( string query, void **Statement ) +int CSQLITE3 :: Prepare( QString query, void **Statement ) { - return sqlite3_prepare_v2( (sqlite3 *)m_DB, query.c_str( ), -1, (sqlite3_stmt **)Statement, NULL ); + return sqlite3_prepare_v2( (sqlite3 *)m_DB, query.toUtf8().data( ), -1, (sqlite3_stmt **)Statement, NULL ); } int CSQLITE3 :: Step( void *Statement ) @@ -67,7 +67,7 @@ int CSQLITE3 :: Step( void *Statement ) if( ColumnText ) m_Row.push_back( ColumnText ); else - m_Row.push_back( string( ) ); + m_Row.push_back( QString( ) ); } } @@ -89,14 +89,14 @@ int CSQLITE3 :: ClearBindings( void *Statement ) return sqlite3_clear_bindings( (sqlite3_stmt *)Statement ); } -int CSQLITE3 :: Exec( string query ) +int CSQLITE3 :: Exec( QString query ) { - return sqlite3_exec( (sqlite3 *)m_DB, query.c_str( ), NULL, NULL, NULL ); + return sqlite3_exec( (sqlite3 *)m_DB, query.toUtf8().data( ), NULL, NULL, NULL ); } -uint32_t CSQLITE3 :: LastRowID( ) +quint32 CSQLITE3 :: LastRowID( ) { - return (uint32_t)sqlite3_last_insert_rowid( (sqlite3 *)m_DB ); + return (quint32)sqlite3_last_insert_rowid( (sqlite3 *)m_DB ); } // @@ -106,7 +106,7 @@ uint32_t CSQLITE3 :: LastRowID( ) CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) { m_File = CFG->GetString( "db_sqlite3_file", "ghost.dbs" ); - CONSOLE_Print( "[SQLITE3] version " + string( SQLITE_VERSION ) ); + CONSOLE_Print( "[SQLITE3] version " + QString( SQLITE_VERSION ) ); CONSOLE_Print( "[SQLITE3] opening database [" + m_File + "]" ); m_DB = new CSQLITE3( m_File ); @@ -115,15 +115,14 @@ CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) // setting m_HasError to true indicates there's been a critical error and we want GHost to shutdown // this is okay here because we're in the constructor so we're not dropping any games or players - CONSOLE_Print( string( "[SQLITE3] error opening database [" + m_File + "] - " ) + m_DB->GetError( ) ); - m_HasError = true; - m_Error = "error opening database"; + CONSOLE_Print( QString( "[SQLITE3] error opening database [" + m_File + "] - " ) + m_DB->GetError( ) ); + SetError("error opening database"); return; } // find the schema number so we can determine whether we need to upgrade or not - string SchemaNumber; + QString SchemaNumber; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT value FROM config WHERE name=\"schema_number\"", (void **)&Statement ); @@ -133,7 +132,7 @@ CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) if( RC == SQLITE_ROW ) { - vector *Row = m_DB->GetRow( ); + QList *Row = m_DB->GetRow( ); if( Row->size( ) == 1 ) SchemaNumber = (*Row)[0]; @@ -148,7 +147,7 @@ CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) else CONSOLE_Print( "[SQLITE3] prepare error getting schema number - " + m_DB->GetError( ) ); - if( SchemaNumber.empty( ) ) + if( SchemaNumber.isEmpty( ) ) { // couldn't find the schema number // unfortunately the very first schema didn't have a config table @@ -215,7 +214,7 @@ CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) if( Statement ) { - sqlite3_bind_text( Statement, 1, SchemaNumber.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, SchemaNumber.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ERROR ) @@ -232,7 +231,7 @@ CGHostDBSQLite :: CGHostDBSQLite( CConfig *CFG ) : CGHostDB( CFG ) if( m_DB->Exec( "CREATE TABLE w3mmdplayers ( id INTEGER PRIMARY KEY, category TEXT NOT NULL, gameid INTEGER NOT NULL, pid INTEGER NOT NULL, name TEXT NOT NULL, flag TEXT NOT NULL, leaver INTEGER NOT NULL, practicing INTEGER NOT NULL )" ) != SQLITE_OK ) CONSOLE_Print( "[SQLITE3] error creating w3mmdplayers table - " + m_DB->GetError( ) ); - if( m_DB->Exec( "CREATE TABLE w3mmdvars ( id INTEGER PRIMARY KEY, gameid INTEGER NOT NULL, pid INTEGER NOT NULL, varname TEXT NOT NULL, value_int INTEGER DEFAULT NULL, value_real REAL DEFAULT NULL, value_string TEXT DEFAULT NULL )" ) != SQLITE_OK ) + if( m_DB->Exec( "CREATE TABLE w3mmdvars ( id INTEGER PRIMARY KEY, gameid INTEGER NOT NULL, pid INTEGER NOT NULL, varname TEXT NOT NULL, value_int INTEGER DEFAULT NULL, value_real REAL DEFAULT NULL, value_QString TEXT DEFAULT NULL )" ) != SQLITE_OK ) CONSOLE_Print( "[SQLITE3] error creating w3mmdvars table - " + m_DB->GetError( ) ); if( m_DB->Exec( "CREATE INDEX idx_gameid ON gameplayers ( gameid )" ) != SQLITE_OK ) @@ -530,7 +529,7 @@ void CGHostDBSQLite :: Upgrade7_8( ) else CONSOLE_Print( "[SQLITE3] created w3mmdplayers table" ); - if( m_DB->Exec( "CREATE TABLE w3mmdvars ( id INTEGER PRIMARY KEY, gameid INTEGER NOT NULL, pid INTEGER NOT NULL, varname TEXT NOT NULL, value_int INTEGER DEFAULT NULL, value_real REAL DEFAULT NULL, value_string TEXT DEFAULT NULL )" ) != SQLITE_OK ) + if( m_DB->Exec( "CREATE TABLE w3mmdvars ( id INTEGER PRIMARY KEY, gameid INTEGER NOT NULL, pid INTEGER NOT NULL, varname TEXT NOT NULL, value_int INTEGER DEFAULT NULL, value_real REAL DEFAULT NULL, value_QString TEXT DEFAULT NULL )" ) != SQLITE_OK ) CONSOLE_Print( "[SQLITE3] error creating w3mmdvars table - " + m_DB->GetError( ) ); else CONSOLE_Print( "[SQLITE3] created w3mmdvars table" ); @@ -555,15 +554,15 @@ bool CGHostDBSQLite :: Commit( ) return m_DB->Exec( "COMMIT TRANSACTION" ) == SQLITE_OK; } -uint32_t CGHostDBSQLite :: AdminCount( string server ) +quint32 CGHostDBSQLite :: AdminCount( QString server ) { - uint32_t Count = 0; + quint32 Count = 0; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT COUNT(*) FROM admins WHERE server=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) @@ -579,17 +578,17 @@ uint32_t CGHostDBSQLite :: AdminCount( string server ) return Count; } -bool CGHostDBSQLite :: AdminCheck( string server, string user ) +bool CGHostDBSQLite :: AdminCheck( QString server, QString user ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool IsAdmin = false; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT * FROM admins WHERE server=? AND name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); // we're just checking to see if the query returned a row, we don't need to check the row data itself @@ -607,17 +606,17 @@ bool CGHostDBSQLite :: AdminCheck( string server, string user ) return IsAdmin; } -bool CGHostDBSQLite :: AdminAdd( string server, string user ) +bool CGHostDBSQLite :: AdminAdd( QString server, QString user ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool Success = false; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO admins ( server, name ) VALUES ( ?, ? )", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) @@ -633,17 +632,17 @@ bool CGHostDBSQLite :: AdminAdd( string server, string user ) return Success; } -bool CGHostDBSQLite :: AdminRemove( string server, string user ) +bool CGHostDBSQLite :: AdminRemove( QString server, QString user ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool Success = false; sqlite3_stmt *Statement; m_DB->Prepare( "DELETE FROM admins WHERE server=? AND name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) @@ -659,20 +658,20 @@ bool CGHostDBSQLite :: AdminRemove( string server, string user ) return Success; } -vector CGHostDBSQLite :: AdminList( string server ) +QList CGHostDBSQLite :: AdminList( QString server ) { - vector AdminList; + QList AdminList; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT name FROM admins WHERE server=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); while( RC == SQLITE_ROW ) { - vector *Row = m_DB->GetRow( ); + QList *Row = m_DB->GetRow( ); if( Row->size( ) == 1 ) AdminList.push_back( (*Row)[0] ); @@ -691,15 +690,15 @@ vector CGHostDBSQLite :: AdminList( string server ) return AdminList; } -uint32_t CGHostDBSQLite :: BanCount( string server ) +quint32 CGHostDBSQLite :: BanCount( QString server ) { - uint32_t Count = 0; + quint32 Count = 0; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT COUNT(*) FROM bans WHERE server=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) @@ -715,30 +714,30 @@ uint32_t CGHostDBSQLite :: BanCount( string server ) return Count; } -CDBBan *CGHostDBSQLite :: BanCheck( string server, string user, string ip ) +CDBBan *CGHostDBSQLite :: BanCheck( QString server, QString user, QString ip ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); CDBBan *Ban = NULL; sqlite3_stmt *Statement; - if( ip.empty( ) ) + if( ip.isEmpty( ) ) m_DB->Prepare( "SELECT name, ip, date, gamename, admin, reason FROM bans WHERE server=? AND name=?", (void **)&Statement ); else m_DB->Prepare( "SELECT name, ip, date, gamename, admin, reason FROM bans WHERE (server=? AND name=?) OR ip=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); - if( !ip.empty( ) ) - sqlite3_bind_text( Statement, 3, ip.c_str( ), -1, SQLITE_TRANSIENT ); + if( !ip.isEmpty( ) ) + sqlite3_bind_text( Statement, 3, ip.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) { - vector *Row = m_DB->GetRow( ); + QList *Row = m_DB->GetRow( ); if( Row->size( ) == 6 ) Ban = new CDBBan( server, (*Row)[0], (*Row)[1], (*Row)[2], (*Row)[3], (*Row)[4], (*Row)[5] ); @@ -756,21 +755,21 @@ CDBBan *CGHostDBSQLite :: BanCheck( string server, string user, string ip ) return Ban; } -bool CGHostDBSQLite :: BanAdd( string server, string user, string ip, string gamename, string admin, string reason ) +bool CGHostDBSQLite :: BanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool Success = false; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO bans ( server, name, ip, date, gamename, admin, reason ) VALUES ( ?, ?, ?, date('now'), ?, ?, ? )", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 3, ip.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 4, gamename.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 5, admin.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 6, reason.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 3, ip.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 4, gamename.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 5, admin.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 6, reason.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); @@ -787,17 +786,17 @@ bool CGHostDBSQLite :: BanAdd( string server, string user, string ip, string gam return Success; } -bool CGHostDBSQLite :: BanRemove( string server, string user ) +bool CGHostDBSQLite :: BanRemove( QString server, QString user ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool Success = false; sqlite3_stmt *Statement; m_DB->Prepare( "DELETE FROM bans WHERE server=? AND name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) @@ -813,16 +812,16 @@ bool CGHostDBSQLite :: BanRemove( string server, string user ) return Success; } -bool CGHostDBSQLite :: BanRemove( string user ) +bool CGHostDBSQLite :: BanRemove( QString user ) { - transform( user.begin( ), user.end( ), user.begin( ), (int(*)(int))tolower ); + user = user.toLower(); bool Success = false; sqlite3_stmt *Statement; m_DB->Prepare( "DELETE FROM bans WHERE name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, user.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, user.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) @@ -838,20 +837,20 @@ bool CGHostDBSQLite :: BanRemove( string user ) return Success; } -vector CGHostDBSQLite :: BanList( string server ) +QList CGHostDBSQLite :: BanList( QString server ) { - vector BanList; + QList BanList; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT name, ip, date, gamename, admin, reason FROM bans WHERE server=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); while( RC == SQLITE_ROW ) { - vector *Row = m_DB->GetRow( ); + QList *Row = m_DB->GetRow( ); if( Row->size( ) == 6 ) BanList.push_back( new CDBBan( server, (*Row)[0], (*Row)[1], (*Row)[2], (*Row)[3], (*Row)[4], (*Row)[5] ) ); @@ -870,84 +869,84 @@ vector CGHostDBSQLite :: BanList( string server ) return BanList; } -uint32_t CGHostDBSQLite :: GameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) +quint32 CGHostDBSQLite :: GameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ) { - uint32_t RowID = 0; + quint32 RowID = 0; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO games ( server, map, datetime, gamename, ownername, duration, gamestate, creatorname, creatorserver ) VALUES ( ?, ?, datetime('now'), ?, ?, ?, ?, ?, ? )", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, server.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 2, map.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 3, gamename.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 4, ownername.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, server.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, map.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 3, gamename.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 4, ownername.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 5, duration ); sqlite3_bind_int( Statement, 6, gamestate ); - sqlite3_bind_text( Statement, 7, creatorname.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 8, creatorserver.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 7, creatorname.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 8, creatorserver.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) RowID = m_DB->LastRowID( ); else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding game [" + server + " : " + map + " : " + gamename + " : " + ownername + " : " + UTIL_ToString( duration ) + " : " + UTIL_ToString( gamestate ) + " : " + creatorname + " : " + creatorserver + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding game [" + server + " : " + map + " : " + gamename + " : " + ownername + " : " + QString::number( duration ) + " : " + QString::number( gamestate ) + " : " + creatorname + " : " + creatorserver + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding game [" + server + " : " + map + " : " + gamename + " : " + ownername + " : " + UTIL_ToString( duration ) + " : " + UTIL_ToString( gamestate ) + " : " + creatorname + " : " + creatorserver + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding game [" + server + " : " + map + " : " + gamename + " : " + ownername + " : " + QString::number( duration ) + " : " + QString::number( gamestate ) + " : " + creatorname + " : " + creatorserver + "] - " + m_DB->GetError( ) ); return RowID; } -uint32_t CGHostDBSQLite :: GamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) +quint32 CGHostDBSQLite :: GamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t RowID = 0; + name = name.toLower(); + quint32 RowID = 0; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO gameplayers ( gameid, name, ip, spoofed, reserved, loadingtime, left, leftreason, team, colour, spoofedrealm ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )", (void **)&Statement ); if( Statement ) { sqlite3_bind_int( Statement, 1, gameid ); - sqlite3_bind_text( Statement, 2, name.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 3, ip.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 2, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 3, ip.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 4, spoofed ); sqlite3_bind_int( Statement, 5, reserved ); sqlite3_bind_int( Statement, 6, loadingtime ); sqlite3_bind_int( Statement, 7, left ); - sqlite3_bind_text( Statement, 8, leftreason.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 8, leftreason.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 9, team ); sqlite3_bind_int( Statement, 10, colour ); - sqlite3_bind_text( Statement, 11, spoofedrealm.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 11, spoofedrealm.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_DONE ) RowID = m_DB->LastRowID( ); else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding gameplayer [" + UTIL_ToString( gameid ) + " : " + name + " : " + ip + " : " + UTIL_ToString( spoofed ) + " : " + spoofedrealm + " : " + UTIL_ToString( reserved ) + " : " + UTIL_ToString( loadingtime ) + " : " + UTIL_ToString( left ) + " : " + leftreason + " : " + UTIL_ToString( team ) + " : " + UTIL_ToString( colour ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding gameplayer [" + QString::number( gameid ) + " : " + name + " : " + ip + " : " + QString::number( spoofed ) + " : " + spoofedrealm + " : " + QString::number( reserved ) + " : " + QString::number( loadingtime ) + " : " + QString::number( left ) + " : " + leftreason + " : " + QString::number( team ) + " : " + QString::number( colour ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding gameplayer [" + UTIL_ToString( gameid ) + " : " + name + " : " + ip + " : " + UTIL_ToString( spoofed ) + " : " + spoofedrealm + " : " + UTIL_ToString( reserved ) + " : " + UTIL_ToString( loadingtime ) + " : " + UTIL_ToString( left ) + " : " + leftreason + " : " + UTIL_ToString( team ) + " : " + UTIL_ToString( colour ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding gameplayer [" + QString::number( gameid ) + " : " + name + " : " + ip + " : " + QString::number( spoofed ) + " : " + spoofedrealm + " : " + QString::number( reserved ) + " : " + QString::number( loadingtime ) + " : " + QString::number( left ) + " : " + leftreason + " : " + QString::number( team ) + " : " + QString::number( colour ) + "] - " + m_DB->GetError( ) ); return RowID; } -uint32_t CGHostDBSQLite :: GamePlayerCount( string name ) +quint32 CGHostDBSQLite :: GamePlayerCount( QString name ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t Count = 0; + name = name.toLower(); + quint32 Count = 0; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT COUNT(*) FROM gameplayers LEFT JOIN games ON games.id=gameid WHERE name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) @@ -963,19 +962,19 @@ uint32_t CGHostDBSQLite :: GamePlayerCount( string name ) return Count; } -CDBGamePlayerSummary *CGHostDBSQLite :: GamePlayerSummaryCheck( string name ) +CDBGamePlayerSummary *CGHostDBSQLite :: GamePlayerSummaryCheck( QString name ) { if( GamePlayerCount( name ) == 0 ) return NULL; - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); + name = name.toLower(); CDBGamePlayerSummary *GamePlayerSummary = NULL; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT MIN(datetime), MAX(datetime), COUNT(*), MIN(loadingtime), AVG(loadingtime), MAX(loadingtime), MIN(left/CAST(duration AS REAL))*100, AVG(left/CAST(duration AS REAL))*100, MAX(left/CAST(duration AS REAL))*100, MIN(duration), AVG(duration), MAX(duration) FROM gameplayers LEFT JOIN games ON games.id=gameid WHERE name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) @@ -984,8 +983,8 @@ CDBGamePlayerSummary *CGHostDBSQLite :: GamePlayerSummaryCheck( string name ) { char *First = (char *)sqlite3_column_text( (sqlite3_stmt *)Statement, 0 ); char *Last = (char *)sqlite3_column_text( (sqlite3_stmt *)Statement, 1 ); - string FirstGameDateTime; - string LastGameDateTime; + QString FirstGameDateTime; + QString LastGameDateTime; if( First ) FirstGameDateTime = First; @@ -993,17 +992,17 @@ CDBGamePlayerSummary *CGHostDBSQLite :: GamePlayerSummaryCheck( string name ) if( Last ) LastGameDateTime = Last; - uint32_t TotalGames = sqlite3_column_int( (sqlite3_stmt *)Statement, 2 ); - uint32_t MinLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 3 ); - uint32_t AvgLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 4 ); - uint32_t MaxLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 5 ); - uint32_t MinLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 6 ); - uint32_t AvgLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 7 ); - uint32_t MaxLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 8 ); - uint32_t MinDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 9 ); - uint32_t AvgDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 10 ); - uint32_t MaxDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 11 ); - GamePlayerSummary = new CDBGamePlayerSummary( string( ), name, FirstGameDateTime, LastGameDateTime, TotalGames, MinLoadingTime, AvgLoadingTime, MaxLoadingTime, MinLeftPercent, AvgLeftPercent, MaxLeftPercent, MinDuration, AvgDuration, MaxDuration ); + quint32 TotalGames = sqlite3_column_int( (sqlite3_stmt *)Statement, 2 ); + quint32 MinLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 3 ); + quint32 AvgLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 4 ); + quint32 MaxLoadingTime = sqlite3_column_int( (sqlite3_stmt *)Statement, 5 ); + quint32 MinLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 6 ); + quint32 AvgLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 7 ); + quint32 MaxLeftPercent = sqlite3_column_int( (sqlite3_stmt *)Statement, 8 ); + quint32 MinDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 9 ); + quint32 AvgDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 10 ); + quint32 MaxDuration = sqlite3_column_int( (sqlite3_stmt *)Statement, 11 ); + GamePlayerSummary = new CDBGamePlayerSummary( QString( ), name, FirstGameDateTime, LastGameDateTime, TotalGames, MinLoadingTime, AvgLoadingTime, MaxLoadingTime, MinLeftPercent, AvgLeftPercent, MaxLeftPercent, MinDuration, AvgDuration, MaxDuration ); } else CONSOLE_Print( "[SQLITE3] error checking gameplayersummary [" + name + "] - row doesn't have 12 columns" ); @@ -1019,9 +1018,9 @@ CDBGamePlayerSummary *CGHostDBSQLite :: GamePlayerSummaryCheck( string name ) return GamePlayerSummary; } -uint32_t CGHostDBSQLite :: DotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) +quint32 CGHostDBSQLite :: DotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ) { - uint32_t RowID = 0; + quint32 RowID = 0; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO dotagames ( gameid, winner, min, sec ) VALUES ( ?, ?, ?, ? )", (void **)&Statement ); @@ -1037,19 +1036,19 @@ uint32_t CGHostDBSQLite :: DotAGameAdd( uint32_t gameid, uint32_t winner, uint32 if( RC == SQLITE_DONE ) RowID = m_DB->LastRowID( ); else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding dotagame [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( winner ) + " : " + UTIL_ToString( min ) + " : " + UTIL_ToString( sec ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding dotagame [" + QString::number( gameid ) + " : " + QString::number( winner ) + " : " + QString::number( min ) + " : " + QString::number( sec ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding dotagame [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( winner ) + " : " + UTIL_ToString( min ) + " : " + UTIL_ToString( sec ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding dotagame [" + QString::number( gameid ) + " : " + QString::number( winner ) + " : " + QString::number( min ) + " : " + QString::number( sec ) + "] - " + m_DB->GetError( ) ); return RowID; } -uint32_t CGHostDBSQLite :: DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) +quint32 CGHostDBSQLite :: DotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ) { - uint32_t RowID = 0; + quint32 RowID = 0; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO dotaplayers ( gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )", (void **)&Statement ); @@ -1064,13 +1063,13 @@ uint32_t CGHostDBSQLite :: DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint sqlite3_bind_int( Statement, 7, assists ); sqlite3_bind_int( Statement, 8, gold ); sqlite3_bind_int( Statement, 9, neutralkills ); - sqlite3_bind_text( Statement, 10, item1.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 11, item2.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 12, item3.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 13, item4.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 14, item5.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 15, item6.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 16, hero.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 10, item1.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 11, item2.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 12, item3.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 13, item4.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 14, item5.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 15, item6.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 16, hero.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 17, newcolour ); sqlite3_bind_int( Statement, 18, towerkills ); sqlite3_bind_int( Statement, 19, raxkills ); @@ -1081,26 +1080,26 @@ uint32_t CGHostDBSQLite :: DotAPlayerAdd( uint32_t gameid, uint32_t colour, uint if( RC == SQLITE_DONE ) RowID = m_DB->LastRowID( ); else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding dotaplayer [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( colour ) + " : " + UTIL_ToString( kills ) + " : " + UTIL_ToString( deaths ) + " : " + UTIL_ToString( creepkills ) + " : " + UTIL_ToString( creepdenies ) + " : " + UTIL_ToString( assists ) + " : " + UTIL_ToString( gold ) + " : " + UTIL_ToString( neutralkills ) + " : " + item1 + " : " + item2 + " : " + item3 + " : " + item4 + " : " + item5 + " : " + item6 + " : " + hero + " : " + UTIL_ToString( newcolour ) + " : " + UTIL_ToString( towerkills ) + " : " + UTIL_ToString( raxkills ) + " : " + UTIL_ToString( courierkills ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding dotaplayer [" + QString::number( gameid ) + " : " + QString::number( colour ) + " : " + QString::number( kills ) + " : " + QString::number( deaths ) + " : " + QString::number( creepkills ) + " : " + QString::number( creepdenies ) + " : " + QString::number( assists ) + " : " + QString::number( gold ) + " : " + QString::number( neutralkills ) + " : " + item1 + " : " + item2 + " : " + item3 + " : " + item4 + " : " + item5 + " : " + item6 + " : " + hero + " : " + QString::number( newcolour ) + " : " + QString::number( towerkills ) + " : " + QString::number( raxkills ) + " : " + QString::number( courierkills ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding dotaplayer [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( colour ) + " : " + UTIL_ToString( kills ) + " : " + UTIL_ToString( deaths ) + " : " + UTIL_ToString( creepkills ) + " : " + UTIL_ToString( creepdenies ) + " : " + UTIL_ToString( assists ) + " : " + UTIL_ToString( gold ) + " : " + UTIL_ToString( neutralkills ) + " : " + item1 + " : " + item2 + " : " + item3 + " : " + item4 + " : " + item5 + " : " + item6 + " : " + hero + " : " + UTIL_ToString( newcolour ) + " : " + UTIL_ToString( towerkills ) + " : " + UTIL_ToString( raxkills ) + " : " + UTIL_ToString( courierkills ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding dotaplayer [" + QString::number( gameid ) + " : " + QString::number( colour ) + " : " + QString::number( kills ) + " : " + QString::number( deaths ) + " : " + QString::number( creepkills ) + " : " + QString::number( creepdenies ) + " : " + QString::number( assists ) + " : " + QString::number( gold ) + " : " + QString::number( neutralkills ) + " : " + item1 + " : " + item2 + " : " + item3 + " : " + item4 + " : " + item5 + " : " + item6 + " : " + hero + " : " + QString::number( newcolour ) + " : " + QString::number( towerkills ) + " : " + QString::number( raxkills ) + " : " + QString::number( courierkills ) + "] - " + m_DB->GetError( ) ); return RowID; } -uint32_t CGHostDBSQLite :: DotAPlayerCount( string name ) +quint32 CGHostDBSQLite :: DotAPlayerCount( QString name ) { - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); - uint32_t Count = 0; + name = name.toLower(); + quint32 Count = 0; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT COUNT(dotaplayers.id) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour WHERE name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) @@ -1116,37 +1115,37 @@ uint32_t CGHostDBSQLite :: DotAPlayerCount( string name ) return Count; } -CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( string name ) +CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( QString name ) { if( DotAPlayerCount( name ) == 0 ) return NULL; - transform( name.begin( ), name.end( ), name.begin( ), (int(*)(int))tolower ); + name = name.toLower(); CDBDotAPlayerSummary *DotAPlayerSummary = NULL; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT COUNT(dotaplayers.id), SUM(kills), SUM(deaths), SUM(creepkills), SUM(creepdenies), SUM(assists), SUM(neutralkills), SUM(towerkills), SUM(raxkills), SUM(courierkills) FROM gameplayers LEFT JOIN games ON games.id=gameplayers.gameid LEFT JOIN dotaplayers ON dotaplayers.gameid=games.id AND dotaplayers.colour=gameplayers.colour WHERE name=?", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ROW ) { if( sqlite3_column_count( (sqlite3_stmt *)Statement ) == 10 ) { - uint32_t TotalGames = sqlite3_column_int( (sqlite3_stmt *)Statement, 0 ); - uint32_t TotalWins = 0; - uint32_t TotalLosses = 0; - uint32_t TotalKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 1 ); - uint32_t TotalDeaths = sqlite3_column_int( (sqlite3_stmt *)Statement, 2 ); - uint32_t TotalCreepKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 3 ); - uint32_t TotalCreepDenies = sqlite3_column_int( (sqlite3_stmt *)Statement, 4 ); - uint32_t TotalAssists = sqlite3_column_int( (sqlite3_stmt *)Statement, 5 ); - uint32_t TotalNeutralKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 6 ); - uint32_t TotalTowerKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 7 ); - uint32_t TotalRaxKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 8 ); - uint32_t TotalCourierKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 9 ); + quint32 TotalGames = sqlite3_column_int( (sqlite3_stmt *)Statement, 0 ); + quint32 TotalWins = 0; + quint32 TotalLosses = 0; + quint32 TotalKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 1 ); + quint32 TotalDeaths = sqlite3_column_int( (sqlite3_stmt *)Statement, 2 ); + quint32 TotalCreepKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 3 ); + quint32 TotalCreepDenies = sqlite3_column_int( (sqlite3_stmt *)Statement, 4 ); + quint32 TotalAssists = sqlite3_column_int( (sqlite3_stmt *)Statement, 5 ); + quint32 TotalNeutralKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 6 ); + quint32 TotalTowerKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 7 ); + quint32 TotalRaxKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 8 ); + quint32 TotalCourierKills = sqlite3_column_int( (sqlite3_stmt *)Statement, 9 ); // calculate total wins @@ -1155,7 +1154,7 @@ CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( string name ) if( Statement2 ) { - sqlite3_bind_text( Statement2, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement2, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC2 = m_DB->Step( Statement2 ); if( RC2 == SQLITE_ROW ) @@ -1175,7 +1174,7 @@ CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( string name ) if( Statement3 ) { - sqlite3_bind_text( Statement3, 1, name.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement3, 1, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC3 = m_DB->Step( Statement3 ); if( RC3 == SQLITE_ROW ) @@ -1190,7 +1189,7 @@ CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( string name ) // done - DotAPlayerSummary = new CDBDotAPlayerSummary( string( ), name, TotalGames, TotalWins, TotalLosses, TotalKills, TotalDeaths, TotalCreepKills, TotalCreepDenies, TotalAssists, TotalNeutralKills, TotalTowerKills, TotalRaxKills, TotalCourierKills ); + DotAPlayerSummary = new CDBDotAPlayerSummary( QString( ), name, TotalGames, TotalWins, TotalLosses, TotalKills, TotalDeaths, TotalCreepKills, TotalCreepDenies, TotalAssists, TotalNeutralKills, TotalTowerKills, TotalRaxKills, TotalCourierKills ); } else CONSOLE_Print( "[SQLITE3] error checking dotaplayersummary [" + name + "] - row doesn't have 7 columns" ); @@ -1206,11 +1205,11 @@ CDBDotAPlayerSummary *CGHostDBSQLite :: DotAPlayerSummaryCheck( string name ) return DotAPlayerSummary; } -string CGHostDBSQLite :: FromCheck( uint32_t ip ) +QString CGHostDBSQLite :: FromCheck( quint32 ip ) { // a big thank you to tjado for help with the iptocountry feature - string From = "??"; + QString From = "??"; sqlite3_stmt *Statement; m_DB->Prepare( "SELECT country FROM iptocountry WHERE ip1<=? AND ip2>=?", (void **)&Statement ); @@ -1224,25 +1223,25 @@ string CGHostDBSQLite :: FromCheck( uint32_t ip ) if( RC == SQLITE_ROW ) { - vector *Row = m_DB->GetRow( ); + QList *Row = m_DB->GetRow( ); if( Row->size( ) == 1 ) From = (*Row)[0]; else - CONSOLE_Print( "[SQLITE3] error checking iptocountry [" + UTIL_ToString( ip ) + "] - row doesn't have 1 column" ); + CONSOLE_Print( "[SQLITE3] error checking iptocountry [" + QString::number( ip ) + "] - row doesn't have 1 column" ); } else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error checking iptocountry [" + UTIL_ToString( ip ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error checking iptocountry [" + QString::number( ip ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error checking iptocountry [" + UTIL_ToString( ip ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error checking iptocountry [" + QString::number( ip ) + "] - " + m_DB->GetError( ) ); return From; } -bool CGHostDBSQLite :: FromAdd( uint32_t ip1, uint32_t ip2, string country ) +bool CGHostDBSQLite :: FromAdd( quint32 ip1, quint32 ip2, QString country ) { // a big thank you to tjado for help with the iptocountry feature @@ -1257,24 +1256,24 @@ bool CGHostDBSQLite :: FromAdd( uint32_t ip1, uint32_t ip2, string country ) sqlite3_bind_int64( (sqlite3_stmt *)FromAddStmt, 1, ip1 ); sqlite3_bind_int64( (sqlite3_stmt *)FromAddStmt, 2, ip2 ); - sqlite3_bind_text( (sqlite3_stmt *)FromAddStmt, 3, country.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( (sqlite3_stmt *)FromAddStmt, 3, country.toUtf8().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( FromAddStmt ); if( RC == SQLITE_DONE ) Success = true; else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding iptocountry [" + UTIL_ToString( ip1 ) + " : " + UTIL_ToString( ip2 ) + " : " + country + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding iptocountry [" + QString::number( ip1 ) + " : " + QString::number( ip2 ) + " : " + country + "] - " + m_DB->GetError( ) ); m_DB->Reset( FromAddStmt ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding iptocountry [" + UTIL_ToString( ip1 ) + " : " + UTIL_ToString( ip2 ) + " : " + country + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding iptocountry [" + QString::number( ip1 ) + " : " + QString::number( ip2 ) + " : " + country + "] - " + m_DB->GetError( ) ); return Success; } -bool CGHostDBSQLite :: DownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) +bool CGHostDBSQLite :: DownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ) { bool Success = false; sqlite3_stmt *Statement; @@ -1282,12 +1281,12 @@ bool CGHostDBSQLite :: DownloadAdd( string map, uint32_t mapsize, string name, s if( Statement ) { - sqlite3_bind_text( Statement, 1, map.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, map.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 2, mapsize ); - sqlite3_bind_text( Statement, 3, name.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 4, ip.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 3, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 4, ip.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 5, spoofed ); - sqlite3_bind_text( Statement, 6, spoofedrealm.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 6, spoofedrealm.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 7, downloadtime ); int RC = m_DB->Step( Statement ); @@ -1295,29 +1294,29 @@ bool CGHostDBSQLite :: DownloadAdd( string map, uint32_t mapsize, string name, s if( RC == SQLITE_DONE ) Success = true; else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding download [" + map + " : " + UTIL_ToString( mapsize ) + " : " + name + " : " + ip + " : " + UTIL_ToString( spoofed ) + " : " + spoofedrealm + " : " + UTIL_ToString( downloadtime ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding download [" + map + " : " + QString::number( mapsize ) + " : " + name + " : " + ip + " : " + QString::number( spoofed ) + " : " + spoofedrealm + " : " + QString::number( downloadtime ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding download [" + map + " : " + UTIL_ToString( mapsize ) + " : " + name + " : " + ip + " : " + UTIL_ToString( spoofed ) + " : " + spoofedrealm + " : " + UTIL_ToString( downloadtime ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding download [" + map + " : " + QString::number( mapsize ) + " : " + name + " : " + ip + " : " + QString::number( spoofed ) + " : " + spoofedrealm + " : " + QString::number( downloadtime ) + "] - " + m_DB->GetError( ) ); return Success; } -uint32_t CGHostDBSQLite :: W3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) +quint32 CGHostDBSQLite :: W3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ) { - uint32_t RowID = 0; + quint32 RowID = 0; sqlite3_stmt *Statement; m_DB->Prepare( "INSERT INTO w3mmdplayers ( category, gameid, pid, name, flag, leaver, practicing ) VALUES ( ?, ?, ?, ?, ?, ?, ? )", (void **)&Statement ); if( Statement ) { - sqlite3_bind_text( Statement, 1, category.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 1, category.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 2, gameid ); sqlite3_bind_int( Statement, 3, pid ); - sqlite3_bind_text( Statement, 4, name.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 5, flag.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 4, name.toUtf8().data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 5, flag.toUtf8().data( ), -1, SQLITE_TRANSIENT ); sqlite3_bind_int( Statement, 6, leaver ); sqlite3_bind_int( Statement, 7, practicing ); @@ -1326,25 +1325,25 @@ uint32_t CGHostDBSQLite :: W3MMDPlayerAdd( string category, uint32_t gameid, uin if( RC == SQLITE_DONE ) RowID = m_DB->LastRowID( ); else if( RC == SQLITE_ERROR ) - CONSOLE_Print( "[SQLITE3] error adding w3mmdplayer [" + category + " : " + UTIL_ToString( gameid ) + " : " + UTIL_ToString( pid ) + " : " + name + " : " + flag + " : " + UTIL_ToString( leaver ) + " : " + UTIL_ToString( practicing ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding w3mmdplayer [" + category + " : " + QString::number( gameid ) + " : " + QString::number( pid ) + " : " + name + " : " + flag + " : " + QString::number( leaver ) + " : " + QString::number( practicing ) + "] - " + m_DB->GetError( ) ); m_DB->Finalize( Statement ); } else - CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdplayer [" + category + " : " + UTIL_ToString( gameid ) + " : " + UTIL_ToString( pid ) + " : " + name + " : " + flag + " : " + UTIL_ToString( leaver ) + " : " + UTIL_ToString( practicing ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdplayer [" + category + " : " + QString::number( gameid ) + " : " + QString::number( pid ) + " : " + name + " : " + flag + " : " + QString::number( leaver ) + " : " + QString::number( practicing ) + "] - " + m_DB->GetError( ) ); return RowID; } -bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_ints ) +bool CGHostDBSQLite :: W3MMDVarAdd( quint32 gameid, QMap var_ints ) { - if( var_ints.empty( ) ) + if( var_ints.isEmpty( ) ) return false; bool Success = true; sqlite3_stmt *Statement = NULL; - for( map :: iterator i = var_ints.begin( ); i != var_ints.end( ); i++ ) + for( QMap :: const_iterator i = var_ints.begin( ); i != var_ints.end( ); i++ ) { if( !Statement ) m_DB->Prepare( "INSERT INTO w3mmdvars ( gameid, pid, varname, value_int ) VALUES ( ?, ?, ?, ? )", (void **)&Statement ); @@ -1352,16 +1351,16 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_ints if( Statement ) { sqlite3_bind_int( Statement, 1, gameid ); - sqlite3_bind_int( Statement, 2, i->first.first ); - sqlite3_bind_text( Statement, 3, i->first.second.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_int( Statement, 4, i->second ); + sqlite3_bind_int( Statement, 2, i.key().first ); + sqlite3_bind_text( Statement, 3, (char*)i.key().second.data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_int( Statement, 4, i.value() ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ERROR ) { Success = false; - CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-int [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + UTIL_ToString( i->second ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-int [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + QString::number( i.value() ) + "] - " + m_DB->GetError( ) ); break; } @@ -1370,7 +1369,7 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_ints else { Success = false; - CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-int [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + UTIL_ToString( i->second ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-int [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + QString::number( i.value() ) + "] - " + m_DB->GetError( ) ); break; } } @@ -1381,15 +1380,15 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_ints return Success; } -bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_reals ) +bool CGHostDBSQLite :: W3MMDVarAdd( quint32 gameid, QMap var_reals ) { - if( var_reals.empty( ) ) + if( var_reals.isEmpty( ) ) return false; bool Success = true; sqlite3_stmt *Statement = NULL; - for( map :: iterator i = var_reals.begin( ); i != var_reals.end( ); i++ ) + for( QMap :: const_iterator i = var_reals.begin( ); i != var_reals.end( ); i++ ) { if( !Statement ) m_DB->Prepare( "INSERT INTO w3mmdvars ( gameid, pid, varname, value_real ) VALUES ( ?, ?, ?, ? )", (void **)&Statement ); @@ -1397,16 +1396,16 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_reals if( Statement ) { sqlite3_bind_int( Statement, 1, gameid ); - sqlite3_bind_int( Statement, 2, i->first.first ); - sqlite3_bind_text( Statement, 3, i->first.second.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_double( Statement, 4, i->second ); + sqlite3_bind_int( Statement, 2, i.key().first ); + sqlite3_bind_text( Statement, 3, (char*)i.key().second.data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_double( Statement, 4, i.value() ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ERROR ) { Success = false; - CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-real [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + UTIL_ToString( i->second, 10 ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-real [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + QString::number( i.value(), 'g', 10 ) + "] - " + m_DB->GetError( ) ); break; } @@ -1415,7 +1414,7 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_reals else { Success = false; - CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-real [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + UTIL_ToString( i->second, 10 ) + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-real [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + QString::number( i.value(), 'g', 10 ) + "] - " + m_DB->GetError( ) ); break; } } @@ -1426,32 +1425,32 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_reals return Success; } -bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_strings ) +bool CGHostDBSQLite :: W3MMDVarAdd( quint32 gameid, QMap var_strings ) { - if( var_strings.empty( ) ) + if( var_strings.isEmpty( ) ) return false; bool Success = true; sqlite3_stmt *Statement = NULL; - for( map :: iterator i = var_strings.begin( ); i != var_strings.end( ); i++ ) + for( QMap :: const_iterator i = var_strings.begin( ); i != var_strings.end( ); i++ ) { if( !Statement ) - m_DB->Prepare( "INSERT INTO w3mmdvars ( gameid, pid, varname, value_string ) VALUES ( ?, ?, ?, ? )", (void **)&Statement ); + m_DB->Prepare( "INSERT INTO w3mmdvars ( gameid, pid, varname, value_QString ) VALUES ( ?, ?, ?, ? )", (void **)&Statement ); if( Statement ) { sqlite3_bind_int( Statement, 1, gameid ); - sqlite3_bind_int( Statement, 2, i->first.first ); - sqlite3_bind_text( Statement, 3, i->first.second.c_str( ), -1, SQLITE_TRANSIENT ); - sqlite3_bind_text( Statement, 4, i->second.c_str( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_int( Statement, 2, i.key().first ); + sqlite3_bind_text( Statement, 3, (char*)i.key().second.data( ), -1, SQLITE_TRANSIENT ); + sqlite3_bind_text( Statement, 4, (char*)i.value().data( ), -1, SQLITE_TRANSIENT ); int RC = m_DB->Step( Statement ); if( RC == SQLITE_ERROR ) { Success = false; - CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-string [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + i->second + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] error adding w3mmdvar-QString [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + i.value() + "] - " + m_DB->GetError( ) ); break; } @@ -1460,7 +1459,7 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_string else { Success = false; - CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-string [" + UTIL_ToString( gameid ) + " : " + UTIL_ToString( i->first.first ) + " : " + i->first.second + " : " + i->second + "] - " + m_DB->GetError( ) ); + CONSOLE_Print( "[SQLITE3] prepare error adding w3mmdvar-QString [" + QString::number( gameid ) + " : " + QString::number( i.key().first ) + " : " + i.key().second + " : " + i.value() + "] - " + m_DB->GetError( ) ); break; } } @@ -1471,7 +1470,7 @@ bool CGHostDBSQLite :: W3MMDVarAdd( uint32_t gameid, map var_string return Success; } -CCallableAdminCount *CGHostDBSQLite :: ThreadedAdminCount( string server ) +CCallableAdminCount *CGHostDBSQLite :: ThreadedAdminCount( QString server ) { CCallableAdminCount *Callable = new CCallableAdminCount( server ); Callable->SetResult( AdminCount( server ) ); @@ -1479,7 +1478,7 @@ CCallableAdminCount *CGHostDBSQLite :: ThreadedAdminCount( string server ) return Callable; } -CCallableAdminCheck *CGHostDBSQLite :: ThreadedAdminCheck( string server, string user ) +CCallableAdminCheck *CGHostDBSQLite :: ThreadedAdminCheck( QString server, QString user ) { CCallableAdminCheck *Callable = new CCallableAdminCheck( server, user ); Callable->SetResult( AdminCheck( server, user ) ); @@ -1487,7 +1486,7 @@ CCallableAdminCheck *CGHostDBSQLite :: ThreadedAdminCheck( string server, string return Callable; } -CCallableAdminAdd *CGHostDBSQLite :: ThreadedAdminAdd( string server, string user ) +CCallableAdminAdd *CGHostDBSQLite :: ThreadedAdminAdd( QString server, QString user ) { CCallableAdminAdd *Callable = new CCallableAdminAdd( server, user ); Callable->SetResult( AdminAdd( server, user ) ); @@ -1495,7 +1494,7 @@ CCallableAdminAdd *CGHostDBSQLite :: ThreadedAdminAdd( string server, string use return Callable; } -CCallableAdminRemove *CGHostDBSQLite :: ThreadedAdminRemove( string server, string user ) +CCallableAdminRemove *CGHostDBSQLite :: ThreadedAdminRemove( QString server, QString user ) { CCallableAdminRemove *Callable = new CCallableAdminRemove( server, user ); Callable->SetResult( AdminRemove( server, user ) ); @@ -1503,7 +1502,7 @@ CCallableAdminRemove *CGHostDBSQLite :: ThreadedAdminRemove( string server, stri return Callable; } -CCallableAdminList *CGHostDBSQLite :: ThreadedAdminList( string server ) +CCallableAdminList *CGHostDBSQLite :: ThreadedAdminList( QString server ) { CCallableAdminList *Callable = new CCallableAdminList( server ); Callable->SetResult( AdminList( server ) ); @@ -1511,7 +1510,7 @@ CCallableAdminList *CGHostDBSQLite :: ThreadedAdminList( string server ) return Callable; } -CCallableBanCount *CGHostDBSQLite :: ThreadedBanCount( string server ) +CCallableBanCount *CGHostDBSQLite :: ThreadedBanCount( QString server ) { CCallableBanCount *Callable = new CCallableBanCount( server ); Callable->SetResult( BanCount( server ) ); @@ -1519,7 +1518,7 @@ CCallableBanCount *CGHostDBSQLite :: ThreadedBanCount( string server ) return Callable; } -CCallableBanCheck *CGHostDBSQLite :: ThreadedBanCheck( string server, string user, string ip ) +CCallableBanCheck *CGHostDBSQLite :: ThreadedBanCheck( QString server, QString user, QString ip ) { CCallableBanCheck *Callable = new CCallableBanCheck( server, user, ip ); Callable->SetResult( BanCheck( server, user, ip ) ); @@ -1527,7 +1526,7 @@ CCallableBanCheck *CGHostDBSQLite :: ThreadedBanCheck( string server, string use return Callable; } -CCallableBanAdd *CGHostDBSQLite :: ThreadedBanAdd( string server, string user, string ip, string gamename, string admin, string reason ) +CCallableBanAdd *CGHostDBSQLite :: ThreadedBanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ) { CCallableBanAdd *Callable = new CCallableBanAdd( server, user, ip, gamename, admin, reason ); Callable->SetResult( BanAdd( server, user, ip, gamename, admin, reason ) ); @@ -1535,7 +1534,7 @@ CCallableBanAdd *CGHostDBSQLite :: ThreadedBanAdd( string server, string user, s return Callable; } -CCallableBanRemove *CGHostDBSQLite :: ThreadedBanRemove( string server, string user ) +CCallableBanRemove *CGHostDBSQLite :: ThreadedBanRemove( QString server, QString user ) { CCallableBanRemove *Callable = new CCallableBanRemove( server, user ); Callable->SetResult( BanRemove( server, user ) ); @@ -1543,15 +1542,15 @@ CCallableBanRemove *CGHostDBSQLite :: ThreadedBanRemove( string server, string u return Callable; } -CCallableBanRemove *CGHostDBSQLite :: ThreadedBanRemove( string user ) +CCallableBanRemove *CGHostDBSQLite :: ThreadedBanRemove( QString user ) { - CCallableBanRemove *Callable = new CCallableBanRemove( string( ), user ); + CCallableBanRemove *Callable = new CCallableBanRemove( QString( ), user ); Callable->SetResult( BanRemove( user ) ); Callable->SetReady( true ); return Callable; } -CCallableBanList *CGHostDBSQLite :: ThreadedBanList( string server ) +CCallableBanList *CGHostDBSQLite :: ThreadedBanList( QString server ) { CCallableBanList *Callable = new CCallableBanList( server ); Callable->SetResult( BanList( server ) ); @@ -1559,7 +1558,7 @@ CCallableBanList *CGHostDBSQLite :: ThreadedBanList( string server ) return Callable; } -CCallableGameAdd *CGHostDBSQLite :: ThreadedGameAdd( string server, string map, string gamename, string ownername, uint32_t duration, uint32_t gamestate, string creatorname, string creatorserver ) +CCallableGameAdd *CGHostDBSQLite :: ThreadedGameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ) { CCallableGameAdd *Callable = new CCallableGameAdd( server, map, gamename, ownername, duration, gamestate, creatorname, creatorserver ); Callable->SetResult( GameAdd( server, map, gamename, ownername, duration, gamestate, creatorname, creatorserver ) ); @@ -1567,7 +1566,7 @@ CCallableGameAdd *CGHostDBSQLite :: ThreadedGameAdd( string server, string map, return Callable; } -CCallableGamePlayerAdd *CGHostDBSQLite :: ThreadedGamePlayerAdd( uint32_t gameid, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t reserved, uint32_t loadingtime, uint32_t left, string leftreason, uint32_t team, uint32_t colour ) +CCallableGamePlayerAdd *CGHostDBSQLite :: ThreadedGamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ) { CCallableGamePlayerAdd *Callable = new CCallableGamePlayerAdd( gameid, name, ip, spoofed, spoofedrealm, reserved, loadingtime, left, leftreason, team, colour ); Callable->SetResult( GamePlayerAdd( gameid, name, ip, spoofed, spoofedrealm, reserved, loadingtime, left, leftreason, team, colour ) ); @@ -1575,7 +1574,7 @@ CCallableGamePlayerAdd *CGHostDBSQLite :: ThreadedGamePlayerAdd( uint32_t gameid return Callable; } -CCallableGamePlayerSummaryCheck *CGHostDBSQLite :: ThreadedGamePlayerSummaryCheck( string name ) +CCallableGamePlayerSummaryCheck *CGHostDBSQLite :: ThreadedGamePlayerSummaryCheck( QString name ) { CCallableGamePlayerSummaryCheck *Callable = new CCallableGamePlayerSummaryCheck( name ); Callable->SetResult( GamePlayerSummaryCheck( name ) ); @@ -1583,7 +1582,7 @@ CCallableGamePlayerSummaryCheck *CGHostDBSQLite :: ThreadedGamePlayerSummaryChec return Callable; } -CCallableDotAGameAdd *CGHostDBSQLite :: ThreadedDotAGameAdd( uint32_t gameid, uint32_t winner, uint32_t min, uint32_t sec ) +CCallableDotAGameAdd *CGHostDBSQLite :: ThreadedDotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ) { CCallableDotAGameAdd *Callable = new CCallableDotAGameAdd( gameid, winner, min, sec ); Callable->SetResult( DotAGameAdd( gameid, winner, min, sec ) ); @@ -1591,7 +1590,7 @@ CCallableDotAGameAdd *CGHostDBSQLite :: ThreadedDotAGameAdd( uint32_t gameid, ui return Callable; } -CCallableDotAPlayerAdd *CGHostDBSQLite :: ThreadedDotAPlayerAdd( uint32_t gameid, uint32_t colour, uint32_t kills, uint32_t deaths, uint32_t creepkills, uint32_t creepdenies, uint32_t assists, uint32_t gold, uint32_t neutralkills, string item1, string item2, string item3, string item4, string item5, string item6, string hero, uint32_t newcolour, uint32_t towerkills, uint32_t raxkills, uint32_t courierkills ) +CCallableDotAPlayerAdd *CGHostDBSQLite :: ThreadedDotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ) { CCallableDotAPlayerAdd *Callable = new CCallableDotAPlayerAdd( gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ); Callable->SetResult( DotAPlayerAdd( gameid, colour, kills, deaths, creepkills, creepdenies, assists, gold, neutralkills, item1, item2, item3, item4, item5, item6, hero, newcolour, towerkills, raxkills, courierkills ) ); @@ -1599,7 +1598,7 @@ CCallableDotAPlayerAdd *CGHostDBSQLite :: ThreadedDotAPlayerAdd( uint32_t gameid return Callable; } -CCallableDotAPlayerSummaryCheck *CGHostDBSQLite :: ThreadedDotAPlayerSummaryCheck( string name ) +CCallableDotAPlayerSummaryCheck *CGHostDBSQLite :: ThreadedDotAPlayerSummaryCheck( QString name ) { CCallableDotAPlayerSummaryCheck *Callable = new CCallableDotAPlayerSummaryCheck( name ); Callable->SetResult( DotAPlayerSummaryCheck( name ) ); @@ -1607,7 +1606,7 @@ CCallableDotAPlayerSummaryCheck *CGHostDBSQLite :: ThreadedDotAPlayerSummaryChec return Callable; } -CCallableDownloadAdd *CGHostDBSQLite :: ThreadedDownloadAdd( string map, uint32_t mapsize, string name, string ip, uint32_t spoofed, string spoofedrealm, uint32_t downloadtime ) +CCallableDownloadAdd *CGHostDBSQLite :: ThreadedDownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ) { CCallableDownloadAdd *Callable = new CCallableDownloadAdd( map, mapsize, name, ip, spoofed, spoofedrealm, downloadtime ); Callable->SetResult( DownloadAdd( map, mapsize, name, ip, spoofed, spoofedrealm, downloadtime ) ); @@ -1615,7 +1614,7 @@ CCallableDownloadAdd *CGHostDBSQLite :: ThreadedDownloadAdd( string map, uint32_ return Callable; } -CCallableW3MMDPlayerAdd *CGHostDBSQLite :: ThreadedW3MMDPlayerAdd( string category, uint32_t gameid, uint32_t pid, string name, string flag, uint32_t leaver, uint32_t practicing ) +CCallableW3MMDPlayerAdd *CGHostDBSQLite :: ThreadedW3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ) { CCallableW3MMDPlayerAdd *Callable = new CCallableW3MMDPlayerAdd( category, gameid, pid, name, flag, leaver, practicing ); Callable->SetResult( W3MMDPlayerAdd( category, gameid, pid, name, flag, leaver, practicing ) ); @@ -1623,7 +1622,7 @@ CCallableW3MMDPlayerAdd *CGHostDBSQLite :: ThreadedW3MMDPlayerAdd( string catego return Callable; } -CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_ints ) +CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_ints ) { CCallableW3MMDVarAdd *Callable = new CCallableW3MMDVarAdd( gameid, var_ints ); Callable->SetResult( W3MMDVarAdd( gameid, var_ints ) ); @@ -1631,7 +1630,7 @@ CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( uint32_t gameid, ma return Callable; } -CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_reals ) +CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_reals ) { CCallableW3MMDVarAdd *Callable = new CCallableW3MMDVarAdd( gameid, var_reals ); Callable->SetResult( W3MMDVarAdd( gameid, var_reals ) ); @@ -1639,7 +1638,7 @@ CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( uint32_t gameid, ma return Callable; } -CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( uint32_t gameid, map var_strings ) +CCallableW3MMDVarAdd *CGHostDBSQLite :: ThreadedW3MMDVarAdd( quint32 gameid, QMap var_strings ) { CCallableW3MMDVarAdd *Callable = new CCallableW3MMDVarAdd( gameid, var_strings ); Callable->SetResult( W3MMDVarAdd( gameid, var_strings ) ); diff --git a/src/libghost/ghostdbsqlite.h b/src/libghost/ghostdbsqlite.h new file mode 100644 index 0000000..ecf2bf1 --- /dev/null +++ b/src/libghost/ghostdbsqlite.h @@ -0,0 +1,272 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef GHOSTDBSQLITE_H +#define GHOSTDBSQLITE_H + +/************** + *** SCHEMA *** + ************** + +CREATE TABLE admins ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + server TEXT NOT NULL DEFAULT "" +) + +CREATE TABLE bans ( + id INTEGER PRIMARY KEY, + server TEXT NOT NULL, + name TEXT NOT NULL, + ip TEXT, + date TEXT NOT NULL, + gamename TEXT, + admin TEXT NOT NULL, + reason TEXT +) + +CREATE TABLE games ( + id INTEGER PRIMARY KEY, + server TEXT NOT NULL, + map TEXT NOT NULL, + datetime TEXT NOT NULL, + gamename TEXT NOT NULL, + ownername TEXT NOT NULL, + duration INTEGER NOT NULL, + gamestate INTEGER NOT NULL DEFAULT 0, + creatorname TEXT NOT NULL DEFAULT "", + creatorserver TEXT NOT NULL DEFAULT "" +) + +CREATE TABLE gameplayers ( + id INTEGER PRIMARY KEY, + gameid INTEGER NOT NULL, + name TEXT NOT NULL, + ip TEXT NOT NULL, + spoofed INTEGER NOT NULL, + reserved INTEGER NOT NULL, + loadingtime INTEGER NOT NULL, + left INTEGER NOT NULL, + leftreason TEXT NOT NULL, + team INTEGER NOT NULL, + colour INTEGER NOT NULL, + spoofedrealm TEXT NOT NULL DEFAULT "" +) + +CREATE TABLE dotagames ( + id INTEGER PRIMARY KEY, + gameid INTEGER NOT NULL, + winner INTEGER NOT NULL, + min INTEGER NOT NULL DEFAULT 0, + sec INTEGER NOT NULL DEFAULT 0 +) + +CREATE TABLE dotaplayers ( + id INTEGER PRIMARY KEY, + gameid INTEGER NOT NULL, + colour INTEGER NOT NULL, + kills INTEGER NOT NULL, + deaths INTEGER NOT NULL, + creepkills INTEGER NOT NULL, + creepdenies INTEGER NOT NULL, + assists INTEGER NOT NULL, + gold INTEGER NOT NULL, + neutralkills INTEGER NOT NULL, + item1 TEXT NOT NULL, + item2 TEXT NOT NULL, + item3 TEXT NOT NULL, + item4 TEXT NOT NULL, + item5 TEXT NOT NULL, + item6 TEXT NOT NULL, + hero TEXT NOT NULL DEFAULT "", + newcolour NOT NULL DEFAULT 0, + towerkills NOT NULL DEFAULT 0, + raxkills NOT NULL DEFAULT 0, + courierkills NOT NULL DEFAULT 0 +) + +CREATE TABLE config ( + name TEXT NOT NULL PRIMARY KEY, + value TEXT NOT NULL +) + +CREATE TABLE downloads ( + id INTEGER PRIMARY KEY, + map TEXT NOT NULL, + mapsize INTEGER NOT NULL, + datetime TEXT NOT NULL, + name TEXT NOT NULL, + ip TEXT NOT NULL, + spoofed INTEGER NOT NULL, + spoofedrealm TEXT NOT NULL, + downloadtime INTEGER NOT NULL +) + +CREATE TABLE w3mmdplayers ( + id INTEGER PRIMARY KEY, + category TEXT NOT NULL, + gameid INTEGER NOT NULL, + pid INTEGER NOT NULL, + name TEXT NOT NULL, + flag TEXT NOT NULL, + leaver INTEGER NOT NULL, + practicing INTEGER NOT NULL +) + +CREATE TABLE w3mmdvars ( + id INTEGER PRIMARY KEY, + gameid INTEGER NOT NULL, + pid INTEGER NOT NULL, + varname TEXT NOT NULL, + value_int INTEGER DEFAULT NULL, + value_real REAL DEFAULT NULL, + value_string TEXT DEFAULT NULL +) + +CREATE TEMPORARY TABLE iptocountry ( + ip1 INTEGER NOT NULL, + ip2 INTEGER NOT NULL, + country TEXT NOT NULL, + PRIMARY KEY ( ip1, ip2 ) +) + +CREATE INDEX idx_gameid ON gameplayers ( gameid ) +CREATE INDEX idx_gameid_colour ON dotaplayers ( gameid, colour ) + + ************** + *** SCHEMA *** + **************/ + +// +// CSQLITE3 (wrapper class) +// + +class CSQLITE3 +{ +private: + void *m_DB; + bool m_Ready; + QList m_Row; + +public: + CSQLITE3( QString filename ); + ~CSQLITE3( ); + + bool GetReady( ) { return m_Ready; } + QList *GetRow( ) { return &m_Row; } + QString GetError( ); + + int Prepare( QString query, void **Statement ); + int Step( void *Statement ); + int Finalize( void *Statement ); + int Reset( void *Statement ); + int ClearBindings( void *Statement ); + int Exec( QString query ); + quint32 LastRowID( ); +}; + +// +// CGHostDBSQLite +// + +#include "includes.h" + +class CGHostDBSQLite : public CGHostDB +{ +private: + QString m_File; + CSQLITE3 *m_DB; + + // we keep some prepared statements in memory rather than recreating them each function call + // this is an optimization because preparing statements takes time + // however it only pays off if you're going to be using the statement extremely often + + void *FromAddStmt; + +public: + CGHostDBSQLite( CConfig *CFG ); + virtual ~CGHostDBSQLite( ); + + virtual void Upgrade1_2( ); + virtual void Upgrade2_3( ); + virtual void Upgrade3_4( ); + virtual void Upgrade4_5( ); + virtual void Upgrade5_6( ); + virtual void Upgrade6_7( ); + virtual void Upgrade7_8( ); + + virtual bool Begin( ); + virtual bool Commit( ); + virtual quint32 AdminCount( QString server ); + virtual bool AdminCheck( QString server, QString user ); + virtual bool AdminAdd( QString server, QString user ); + virtual bool AdminRemove( QString server, QString user ); + virtual QList AdminList( QString server ); + virtual quint32 BanCount( QString server ); + virtual CDBBan *BanCheck( QString server, QString user, QString ip ); + virtual bool BanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); + virtual bool BanRemove( QString server, QString user ); + virtual bool BanRemove( QString user ); + virtual QList BanList( QString server ); + virtual quint32 GameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); + virtual quint32 GamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); + virtual quint32 GamePlayerCount( QString name ); + virtual CDBGamePlayerSummary *GamePlayerSummaryCheck( QString name ); + virtual quint32 DotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ); + virtual quint32 DotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); + virtual quint32 DotAPlayerCount( QString name ); + virtual CDBDotAPlayerSummary *DotAPlayerSummaryCheck( QString name ); + virtual QString FromCheck( quint32 ip ); + virtual bool FromAdd( quint32 ip1, quint32 ip2, QString country ); + virtual bool DownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); + virtual quint32 W3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_ints ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_reals ); + virtual bool W3MMDVarAdd( quint32 gameid, QMap var_strings ); + + // threaded database functions + // note: these are not actually implemented with threads at the moment, they WILL block until the query is complete + // todotodo: implement threads here + + virtual CCallableAdminCount *ThreadedAdminCount( QString server ); + virtual CCallableAdminCheck *ThreadedAdminCheck( QString server, QString user ); + virtual CCallableAdminAdd *ThreadedAdminAdd( QString server, QString user ); + virtual CCallableAdminRemove *ThreadedAdminRemove( QString server, QString user ); + virtual CCallableAdminList *ThreadedAdminList( QString server ); + virtual CCallableBanCount *ThreadedBanCount( QString server ); + virtual CCallableBanCheck *ThreadedBanCheck( QString server, QString user, QString ip ); + virtual CCallableBanAdd *ThreadedBanAdd( QString server, QString user, QString ip, QString gamename, QString admin, QString reason ); + virtual CCallableBanRemove *ThreadedBanRemove( QString server, QString user ); + virtual CCallableBanRemove *ThreadedBanRemove( QString user ); + virtual CCallableBanList *ThreadedBanList( QString server ); + virtual CCallableGameAdd *ThreadedGameAdd( QString server, QString map, QString gamename, QString ownername, quint32 duration, quint32 gamestate, QString creatorname, QString creatorserver ); + virtual CCallableGamePlayerAdd *ThreadedGamePlayerAdd( quint32 gameid, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 reserved, quint32 loadingtime, quint32 left, QString leftreason, quint32 team, quint32 colour ); + virtual CCallableGamePlayerSummaryCheck *ThreadedGamePlayerSummaryCheck( QString name ); + virtual CCallableDotAGameAdd *ThreadedDotAGameAdd( quint32 gameid, quint32 winner, quint32 min, quint32 sec ); + virtual CCallableDotAPlayerAdd *ThreadedDotAPlayerAdd( quint32 gameid, quint32 colour, quint32 kills, quint32 deaths, quint32 creepkills, quint32 creepdenies, quint32 assists, quint32 gold, quint32 neutralkills, QString item1, QString item2, QString item3, QString item4, QString item5, QString item6, QString hero, quint32 newcolour, quint32 towerkills, quint32 raxkills, quint32 courierkills ); + virtual CCallableDotAPlayerSummaryCheck *ThreadedDotAPlayerSummaryCheck( QString name ); + virtual CCallableDownloadAdd *ThreadedDownloadAdd( QString map, quint32 mapsize, QString name, QString ip, quint32 spoofed, QString spoofedrealm, quint32 downloadtime ); + virtual CCallableW3MMDPlayerAdd *ThreadedW3MMDPlayerAdd( QString category, quint32 gameid, quint32 pid, QString name, QString flag, quint32 leaver, quint32 practicing ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_ints ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_reals ); + virtual CCallableW3MMDVarAdd *ThreadedW3MMDVarAdd( quint32 gameid, QMap var_strings ); +}; + +#endif diff --git a/ghost/gpsprotocol.cpp b/src/libghost/gpsprotocol.cpp similarity index 53% rename from ghost/gpsprotocol.cpp rename to src/libghost/gpsprotocol.cpp index 60de892..2db14b7 100644 --- a/ghost/gpsprotocol.cpp +++ b/src/libghost/gpsprotocol.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -42,91 +42,91 @@ CGPSProtocol :: ~CGPSProtocol( ) // SEND FUNCTIONS // //////////////////// -BYTEARRAY CGPSProtocol :: SEND_GPSC_INIT( uint32_t version ) +QByteArray CGPSProtocol :: SEND_GPSC_INIT( quint32 version ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_INIT ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, version, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt32(version)); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSC_RECONNECT( unsigned char PID, uint32_t reconnectKey, uint32_t lastPacket ) +QByteArray CGPSProtocol :: SEND_GPSC_RECONNECT( unsigned char PID, quint32 reconnectKey, quint32 lastPacket ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_RECONNECT ); - packet.push_back( 0 ); - packet.push_back( 0 ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); packet.push_back( PID ); - UTIL_AppendByteArray( packet, reconnectKey, false ); - UTIL_AppendByteArray( packet, lastPacket, false ); + packet.append(Util::fromUInt32(reconnectKey)); + packet.append(Util::fromUInt32(lastPacket)); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSC_ACK( uint32_t lastPacket ) +QByteArray CGPSProtocol :: SEND_GPSC_ACK( quint32 lastPacket ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_ACK ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, lastPacket, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt32(lastPacket)); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSS_INIT( uint16_t reconnectPort, unsigned char PID, uint32_t reconnectKey, unsigned char numEmptyActions ) +QByteArray CGPSProtocol :: SEND_GPSS_INIT( quint16 reconnectPort, unsigned char PID, quint32 reconnectKey, unsigned char numEmptyActions ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_INIT ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, reconnectPort, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt16(reconnectPort)); packet.push_back( PID ); - UTIL_AppendByteArray( packet, reconnectKey, false ); + packet.append(Util::fromUInt32(reconnectKey)); packet.push_back( numEmptyActions ); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSS_RECONNECT( uint32_t lastPacket ) +QByteArray CGPSProtocol :: SEND_GPSS_RECONNECT( quint32 lastPacket ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_RECONNECT ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, lastPacket, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt32(lastPacket)); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSS_ACK( uint32_t lastPacket ) +QByteArray CGPSProtocol :: SEND_GPSS_ACK( quint32 lastPacket ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_ACK ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, lastPacket, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt32(lastPacket)); AssignLength( packet ); return packet; } -BYTEARRAY CGPSProtocol :: SEND_GPSS_REJECT( uint32_t reason ) +QByteArray CGPSProtocol :: SEND_GPSS_REJECT( quint32 reason ) const { - BYTEARRAY packet; + QByteArray packet; packet.push_back( GPS_HEADER_CONSTANT ); packet.push_back( GPS_REJECT ); - packet.push_back( 0 ); - packet.push_back( 0 ); - UTIL_AppendByteArray( packet, reason, false ); + packet.push_back( (char)0 ); + packet.push_back( (char)0 ); + packet.append(Util::fromUInt32(reason)); AssignLength( packet ); return packet; } @@ -135,15 +135,15 @@ BYTEARRAY CGPSProtocol :: SEND_GPSS_REJECT( uint32_t reason ) // OTHER FUNCTIONS // ///////////////////// -bool CGPSProtocol :: AssignLength( BYTEARRAY &content ) +bool CGPSProtocol :: AssignLength( QByteArray &content ) const { // insert the actual length of the content array into bytes 3 and 4 (indices 2 and 3) - BYTEARRAY LengthBytes; + QByteArray LengthBytes; if( content.size( ) >= 4 && content.size( ) <= 65535 ) { - LengthBytes = UTIL_CreateByteArray( (uint16_t)content.size( ), false ); + LengthBytes = Util::fromUInt16(content.size( )); content[2] = LengthBytes[0]; content[3] = LengthBytes[1]; return true; @@ -152,18 +152,18 @@ bool CGPSProtocol :: AssignLength( BYTEARRAY &content ) return false; } -bool CGPSProtocol :: ValidateLength( BYTEARRAY &content ) +bool CGPSProtocol :: ValidateLength( QByteArray &content ) const { // verify that bytes 3 and 4 (indices 2 and 3) of the content array describe the length - uint16_t Length; - BYTEARRAY LengthBytes; + quint16 Length; + QByteArray LengthBytes; if( content.size( ) >= 4 && content.size( ) <= 65535 ) { LengthBytes.push_back( content[2] ); LengthBytes.push_back( content[3] ); - Length = UTIL_ByteArrayToUInt16( LengthBytes, false ); + Length = LengthBytes.toUShort(); if( Length == content.size( ) ) return true; diff --git a/ghost/gpsprotocol.h b/src/libghost/gpsprotocol.h similarity index 60% rename from ghost/gpsprotocol.h rename to src/libghost/gpsprotocol.h index 2c38bea..8d32512 100644 --- a/ghost/gpsprotocol.h +++ b/src/libghost/gpsprotocol.h @@ -45,20 +45,20 @@ class CGPSProtocol // send functions - BYTEARRAY SEND_GPSC_INIT( uint32_t version ); - BYTEARRAY SEND_GPSC_RECONNECT( unsigned char PID, uint32_t reconnectKey, uint32_t lastPacket ); - BYTEARRAY SEND_GPSC_ACK( uint32_t lastPacket ); + QByteArray SEND_GPSC_INIT( quint32 version ) const; + QByteArray SEND_GPSC_RECONNECT( unsigned char PID, quint32 reconnectKey, quint32 lastPacket ) const; + QByteArray SEND_GPSC_ACK( quint32 lastPacket ) const; - BYTEARRAY SEND_GPSS_INIT( uint16_t reconnectPort, unsigned char PID, uint32_t reconnectKey, unsigned char numEmptyActions ); - BYTEARRAY SEND_GPSS_RECONNECT( uint32_t lastPacket ); - BYTEARRAY SEND_GPSS_ACK( uint32_t lastPacket ); - BYTEARRAY SEND_GPSS_REJECT( uint32_t reason ); + QByteArray SEND_GPSS_INIT( quint16 reconnectPort, unsigned char PID, quint32 reconnectKey, unsigned char numEmptyActions ) const; + QByteArray SEND_GPSS_RECONNECT( quint32 lastPacket ) const; + QByteArray SEND_GPSS_ACK( quint32 lastPacket ) const; + QByteArray SEND_GPSS_REJECT( quint32 reason ) const; // other functions private: - bool AssignLength( BYTEARRAY &content ); - bool ValidateLength( BYTEARRAY &content ); + bool AssignLength( QByteArray &content ) const; + bool ValidateLength( QByteArray &content ) const; }; #endif diff --git a/src/libghost/includes.h b/src/libghost/includes.h new file mode 100644 index 0000000..6def9e4 --- /dev/null +++ b/src/libghost/includes.h @@ -0,0 +1,49 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef INCLUDES_H +#define INCLUDES_H + +// STL + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +typedef QPair PIDPlayer; + +// time + +quint32 GetTime( ); // seconds +quint32 GetTicks( ); // milliseconds + +// output + +void CONSOLE_Print( QString message ); +void DEBUG_Print( QString message ); + +#endif diff --git a/src/libghost/interfaces.h b/src/libghost/interfaces.h new file mode 100644 index 0000000..836e237 --- /dev/null +++ b/src/libghost/interfaces.h @@ -0,0 +1,112 @@ +/* + + Copyright [2010] [Lucas Romero] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + + */ + +#ifndef INTERFACES_H +#define INTERFACES_H + +#include +#include +#include +#include +#include + +class CBNET; +class CGHost; +class CConfig; +class CBaseGame; +class CGamePlayer; +class CCommandPacket; +//class CommandData; + + + +class IGHostPlugin +{ +protected: + CGHost *m_GHost; +public: + virtual ~IGHostPlugin( ) { } + virtual QString GetName( ) const = 0; + virtual void PluginLoaded( CGHost *ghost, CConfig */*cfg*/ ) { m_GHost = ghost; } + virtual void AllPluginsLoaded( CGHost */*ghost*/, const QList &/*plugins*/ ) { } +}; + +class IPacketHandler : public IGHostPlugin +{ +public: + virtual bool HandlePacket( CCommandPacket* packet, bool wasHandled ) = 0; +}; + +class IOutputListener : public IGHostPlugin +{ +public: + virtual void ConsoleOutput( const QString &message ) = 0; +}; + +class ILogPlugin : public IGHostPlugin +{ +public: + virtual void LogInfo( const QString &message ) = 0; + virtual void LogWarning( const QString &message ) = 0; + virtual void LogError( const QString &message ) = 0; +}; + +class ICommandProvider : public IGHostPlugin +{ +public: + class CommandData + { + public: + CommandData( const QString &cmd, const QString &payload ) : + m_Command( cmd ), + m_Payload( payload ), + m_Admin( false ), + m_RootAdmin( false ) + { /* empty constructor */ } + protected: + QString m_Command; + QString m_Payload; + bool m_Admin; + bool m_RootAdmin; + public: + const QString &GetCommand( ) const { return m_Command; } + const QString &GetPayload( ) const { return m_Payload; } + + bool IsAdmin( ) const { return m_Admin; } + bool IsRootAdmin( ) const { return m_RootAdmin; } + void SetAdmin( bool value ) { m_Admin = value; } + void SetRootAdmin( bool value ) { m_RootAdmin = value; } + }; + virtual ~ICommandProvider() {} + virtual QStringList GetCommands() const = 0; + virtual void OnGameCommand( CBaseGame *game, CGamePlayer *player, const CommandData &data ) = 0; + virtual void OnBNETCommand( CBNET *bnet, const QString &user, bool whisper, const CommandData &data ) = 0; + +}; + + + +Q_DECLARE_INTERFACE(IGHostPlugin, "org.GHost.IGHost/1.0") +//Q_DECLARE_INTERFACE(IOutputListener, "org.GHost.IOutputListener/1.0") +Q_DECLARE_INTERFACE(ILogPlugin, "org.GHost.ILogPlugin/1.0") +Q_DECLARE_INTERFACE(ICommandProvider, "org.GHost.ICommandProvider/1.0") +Q_DECLARE_INTERFACE(IPacketHandler, "org.GHost.IPacketHandler/1.0") + +#endif diff --git a/src/libghost/language.cpp b/src/libghost/language.cpp new file mode 100644 index 0000000..7878e7d --- /dev/null +++ b/src/libghost/language.cpp @@ -0,0 +1,1535 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" +#include "config.h" +#include "language.h" + +// +// CLanguage +// + +CLanguage :: CLanguage( const QString &nCFGFile ) +{ + m_CFG = new CConfig( ); + m_CFG->Read( nCFGFile ); +} + +CLanguage :: ~CLanguage( ) +{ + delete m_CFG; +} + +QString CLanguage :: UnableToCreateGameTryAnotherName( const QString &server, const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0001", "lang_0001" ); + Out.replace("$SERVER$", server); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: UserIsAlreadyAnAdmin( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0002", "lang_0002" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: AddedUserToAdminDatabase( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0003", "lang_0003" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: ErrorAddingUserToAdminDatabase( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0004", "lang_0004" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: YouDontHaveAccessToThatCommand( ) const +{ + return m_CFG->GetString( "lang_0005", "lang_0005" ); +} + +QString CLanguage :: UserIsAlreadyBanned( const QString &server, const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0006", "lang_0006" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: BannedUser( const QString &server, const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0007", "lang_0007" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: ErrorBanningUser( const QString &server, const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0008", "lang_0008" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UserIsAnAdmin( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0009", "lang_0009" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UserIsNotAnAdmin( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0010", "lang_0010" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UserWasBannedOnByBecause( const QString &server, const QString &victim, const QString &date, const QString &admin, const QString &reason ) const +{ + QString Out = m_CFG->GetString( "lang_0011", "lang_0011" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + Out.replace("$DATE$", date); + Out.replace("$ADMIN$", admin); + Out.replace("$REASON$", reason); + return Out; +} + +QString CLanguage :: UserIsNotBanned( const QString &server, const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0012", "lang_0012" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: ThereAreNoAdmins( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0013", "lang_0013" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: ThereIsAdmin( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0014", "lang_0014" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: ThereAreAdmins( const QString &server, const QString &count ) const +{ + QString Out = m_CFG->GetString( "lang_0015", "lang_0015" ); + Out.replace("$SERVER$", server); + Out.replace("$COUNT$", count); + return Out; +} + +QString CLanguage :: ThereAreNoBannedUsers( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0016", "lang_0016" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: ThereIsBannedUser( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0017", "lang_0017" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: ThereAreBannedUsers( const QString &server, const QString &count ) const +{ + QString Out = m_CFG->GetString( "lang_0018", "lang_0018" ); + Out.replace("$SERVER$", server); + Out.replace("$COUNT$", count); + return Out; +} + +QString CLanguage :: YouCantDeleteTheRootAdmin( ) const +{ + return m_CFG->GetString( "lang_0019", "lang_0019" ); +} + +QString CLanguage :: DeletedUserFromAdminDatabase( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0020", "lang_0020" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: ErrorDeletingUserFromAdminDatabase( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0021", "lang_0021" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnbannedUser( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0022", "lang_0022" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: ErrorUnbanningUser( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0023", "lang_0023" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: GameNumberIs( const QString &number, const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0024", "lang_0024" ); + Out.replace("$NUMBER$", number); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: GameNumberDoesntExist( const QString &number ) const +{ + QString Out = m_CFG->GetString( "lang_0025", "lang_0025" ); + Out.replace("$NUMBER$", number); + return Out; +} + +QString CLanguage :: GameIsInTheLobby( const QString &description, const QString ¤t, const QString &max ) const +{ + QString Out = m_CFG->GetString( "lang_0026", "lang_0026" ); + Out.replace("$DESCRIPTION$", description); + Out.replace("$CURRENT$", current); + Out.replace("$MAX$", max); + return Out; +} + +QString CLanguage :: ThereIsNoGameInTheLobby( const QString ¤t, const QString &max ) const +{ + QString Out = m_CFG->GetString( "lang_0027", "lang_0027" ); + Out.replace("$CURRENT$", current); + Out.replace("$MAX$", max); + return Out; +} + +QString CLanguage :: UnableToLoadConfigFilesOutside( ) const +{ + return m_CFG->GetString( "lang_0028", "lang_0028" ); +} + +QString CLanguage :: LoadingConfigFile( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0029", "lang_0029" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: UnableToLoadConfigFileDoesntExist( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0030", "lang_0030" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: CreatingPrivateGame( const QString &gamename, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0031", "lang_0031" ); + Out.replace("$GAMENAME$", gamename); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: CreatingPublicGame( const QString &gamename, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0032", "lang_0032" ); + Out.replace("$GAMENAME$", gamename); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnableToUnhostGameCountdownStarted( const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0033", "lang_0033" ); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: UnhostingGame( const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0034", "lang_0034" ); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: UnableToUnhostGameNoGameInLobby( ) const +{ + return m_CFG->GetString( "lang_0035", "lang_0035" ); +} + +QString CLanguage :: VersionAdmin( const QString &version ) const +{ + QString Out = m_CFG->GetString( "lang_0036", "lang_0036" ); + Out.replace("$VERSION$", version); + return Out; +} + +QString CLanguage :: VersionNotAdmin( const QString &version ) const +{ + QString Out = m_CFG->GetString( "lang_0037", "lang_0037" ); + Out.replace("$VERSION$", version); + return Out; +} + +QString CLanguage :: UnableToCreateGameAnotherGameInLobby( const QString &gamename, const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0038", "lang_0038" ); + Out.replace("$GAMENAME$", gamename); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: UnableToCreateGameMaxGamesReached( const QString &gamename, const QString &max ) const +{ + QString Out = m_CFG->GetString( "lang_0039", "lang_0039" ); + Out.replace("$GAMENAME$", gamename); + Out.replace("$MAX$", max); + return Out; +} + +QString CLanguage :: GameIsOver( const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0040", "lang_0040" ); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: SpoofCheckByReplying( ) const +{ + return m_CFG->GetString( "lang_0041", "lang_0041" ); +} + +QString CLanguage :: GameRefreshed( ) const +{ + return m_CFG->GetString( "lang_0042", "lang_0042" ); +} + +QString CLanguage :: SpoofPossibleIsAway( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0043", "lang_0043" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: SpoofPossibleIsUnavailable( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0044", "lang_0044" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: SpoofPossibleIsRefusingMessages( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0045", "lang_0045" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: SpoofDetectedIsNotInGame( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0046", "lang_0046" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: SpoofDetectedIsInPrivateChannel( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0047", "lang_0047" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: SpoofDetectedIsInAnotherGame( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0048", "lang_0048" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: CountDownAborted( ) const +{ + return m_CFG->GetString( "lang_0049", "lang_0049" ); +} + +QString CLanguage :: TryingToJoinTheGameButBanned( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0050", "lang_0050" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UnableToBanNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0051", "lang_0051" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: PlayerWasBannedByPlayer( const QString &server, const QString &victim, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0052", "lang_0052" ); + Out.replace("$SERVER$", server); + Out.replace("$VICTIM$", victim); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnableToBanFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0053", "lang_0053" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: AddedPlayerToTheHoldList( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0054", "lang_0054" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnableToKickNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0055", "lang_0055" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UnableToKickFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0056", "lang_0056" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: SettingLatencyToMinimum( const QString &min ) const +{ + QString Out = m_CFG->GetString( "lang_0057", "lang_0057" ); + Out.replace("$MIN$", min); + return Out; +} + +QString CLanguage :: SettingLatencyToMaximum( const QString &max ) const +{ + QString Out = m_CFG->GetString( "lang_0058", "lang_0058" ); + Out.replace("$MAX$", max); + return Out; +} + +QString CLanguage :: SettingLatencyTo( const QString &latency ) const +{ + QString Out = m_CFG->GetString( "lang_0059", "lang_0059" ); + Out.replace("$LATENCY$", latency); + return Out; +} + +QString CLanguage :: KickingPlayersWithPingsGreaterThan( const QString &total, const QString &ping ) const +{ + QString Out = m_CFG->GetString( "lang_0060", "lang_0060" ); + Out.replace("$TOTAL$", total); + Out.replace("$PING$", ping); + return Out; +} + +QString CLanguage :: HasPlayedGamesWithThisBot( const QString &user, const QString &firstgame, const QString &lastgame, const QString &totalgames, const QString &avgloadingtime, const QString &avgstay ) const +{ + QString Out = m_CFG->GetString( "lang_0061", "lang_0061" ); + Out.replace("$USER$", user); + Out.replace("$FIRSTGAME$", firstgame); + Out.replace("$LASTGAME$", lastgame); + Out.replace("$TOTALGAMES$", totalgames); + Out.replace("$AVGLOADINGTIME$", avgloadingtime); + Out.replace("$AVGSTAY$", avgstay); + return Out; +} + +QString CLanguage :: HasntPlayedGamesWithThisBot( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0062", "lang_0062" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: AutokickingPlayerForExcessivePing( const QString &victim, const QString &ping ) const +{ + QString Out = m_CFG->GetString( "lang_0063", "lang_0063" ); + Out.replace("$VICTIM$", victim); + Out.replace("$PING$", ping); + return Out; +} + +QString CLanguage :: SpoofCheckAcceptedFor( const QString &server, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0064", "lang_0064" ); + Out.replace("$SERVER$", server); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: PlayersNotYetSpoofChecked( const QString ¬spoofchecked ) const +{ + QString Out = m_CFG->GetString( "lang_0065", "lang_0065" ); + Out.replace("$NOTSPOOFCHECKED$", notspoofchecked); + return Out; +} + +QString CLanguage :: ManuallySpoofCheckByWhispering( const QString &hostname ) const +{ + QString Out = m_CFG->GetString( "lang_0066", "lang_0066" ); + Out.replace("$HOSTNAME$", hostname); + return Out; +} + +QString CLanguage :: SpoofCheckByWhispering( const QString &hostname ) const +{ + QString Out = m_CFG->GetString( "lang_0067", "lang_0067" ); + Out.replace("$HOSTNAME$", hostname); + return Out; +} + +QString CLanguage :: EveryoneHasBeenSpoofChecked( ) const +{ + return m_CFG->GetString( "lang_0068", "lang_0068" ); +} + +QString CLanguage :: PlayersNotYetPinged( const QString ¬pinged ) const +{ + QString Out = m_CFG->GetString( "lang_0069", "lang_0069" ); + Out.replace("$NOTPINGED$", notpinged); + return Out; +} + +QString CLanguage :: EveryoneHasBeenPinged( ) const +{ + return m_CFG->GetString( "lang_0070", "lang_0070" ); +} + +QString CLanguage :: ShortestLoadByPlayer( const QString &user, const QString &loadingtime ) const +{ + QString Out = m_CFG->GetString( "lang_0071", "lang_0071" ); + Out.replace("$USER$", user); + Out.replace("$LOADINGTIME$", loadingtime); + return Out; +} + +QString CLanguage :: LongestLoadByPlayer( const QString &user, const QString &loadingtime ) const +{ + QString Out = m_CFG->GetString( "lang_0072", "lang_0072" ); + Out.replace("$USER$", user); + Out.replace("$LOADINGTIME$", loadingtime); + return Out; +} + +QString CLanguage :: YourLoadingTimeWas( const QString &loadingtime ) const +{ + QString Out = m_CFG->GetString( "lang_0073", "lang_0073" ); + Out.replace("$LOADINGTIME$", loadingtime); + return Out; +} + +QString CLanguage :: HasPlayedDotAGamesWithThisBot( const QString &user, const QString &totalgames, const QString &totalwins, const QString &totallosses, const QString &totalkills, const QString &totaldeaths, const QString &totalcreepkills, const QString &totalcreepdenies, const QString &totalassists, const QString &totalneutralkills, const QString &totaltowerkills, const QString &totalraxkills, const QString &totalcourierkills, const QString &avgkills, const QString &avgdeaths, const QString &avgcreepkills, const QString &avgcreepdenies, const QString &avgassists, const QString &avgneutralkills, const QString &avgtowerkills, const QString &avgraxkills, const QString &avgcourierkills ) const +{ + QString Out = m_CFG->GetString( "lang_0074", "lang_0074" ); + Out.replace("$USER$", user); + Out.replace("$TOTALGAMES$", totalgames); + Out.replace("$TOTALWINS$", totalwins); + Out.replace("$TOTALLOSSES$", totallosses); + Out.replace("$TOTALKILLS$", totalkills); + Out.replace("$TOTALDEATHS$", totaldeaths); + Out.replace("$TOTALCREEPKILLS$", totalcreepkills); + Out.replace("$TOTALCREEPDENIES$", totalcreepdenies); + Out.replace("$TOTALASSISTS$", totalassists); + Out.replace("$TOTALNEUTRALKILLS$", totalneutralkills); + Out.replace("$TOTALTOWERKILLS$", totaltowerkills); + Out.replace("$TOTALRAXKILLS$", totalraxkills); + Out.replace("$TOTALCOURIERKILLS$", totalcourierkills); + Out.replace("$AVGKILLS$", avgkills); + Out.replace("$AVGDEATHS$", avgdeaths); + Out.replace("$AVGCREEPKILLS$", avgcreepkills); + Out.replace("$AVGCREEPDENIES$", avgcreepdenies); + Out.replace("$AVGASSISTS$", avgassists); + Out.replace("$AVGNEUTRALKILLS$", avgneutralkills); + Out.replace("$AVGTOWERKILLS$", avgtowerkills); + Out.replace("$AVGRAXKILLS$", avgraxkills); + Out.replace("$AVGCOURIERKILLS$", avgcourierkills); + return Out; +} + +QString CLanguage :: HasntPlayedDotAGamesWithThisBot( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0075", "lang_0075" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: WasKickedForReservedPlayer( const QString &reserved ) const +{ + QString Out = m_CFG->GetString( "lang_0076", "lang_0076" ); + Out.replace("$RESERVED$", reserved); + return Out; +} + +QString CLanguage :: WasKickedForOwnerPlayer( const QString &owner ) const +{ + QString Out = m_CFG->GetString( "lang_0077", "lang_0077" ); + Out.replace("$OWNER$", owner); + return Out; +} + +QString CLanguage :: WasKickedByPlayer( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0078", "lang_0078" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: HasLostConnectionPlayerError( const QString &error ) const +{ + QString Out = m_CFG->GetString( "lang_0079", "lang_0079" ); + Out.replace("$ERROR$", error); + return Out; +} + +QString CLanguage :: HasLostConnectionSocketError( const QString &error ) const +{ + QString Out = m_CFG->GetString( "lang_0080", "lang_0080" ); + Out.replace("$ERROR$", error); + return Out; +} + +QString CLanguage :: HasLostConnectionClosedByRemoteHost( ) const +{ + return m_CFG->GetString( "lang_0081", "lang_0081" ); +} + +QString CLanguage :: HasLeftVoluntarily( ) const +{ + return m_CFG->GetString( "lang_0082", "lang_0082" ); +} + +QString CLanguage :: EndingGame( const QString &description ) const +{ + QString Out = m_CFG->GetString( "lang_0083", "lang_0083" ); + Out.replace("$DESCRIPTION$", description); + return Out; +} + +QString CLanguage :: HasLostConnectionTimedOut( ) const +{ + return m_CFG->GetString( "lang_0084", "lang_0084" ); +} + +QString CLanguage :: GlobalChatMuted( ) const +{ + return m_CFG->GetString( "lang_0085", "lang_0085" ); +} + +QString CLanguage :: GlobalChatUnmuted( ) const +{ + return m_CFG->GetString( "lang_0086", "lang_0086" ); +} + +QString CLanguage :: ShufflingPlayers( ) const +{ + return m_CFG->GetString( "lang_0087", "lang_0087" ); +} + +QString CLanguage :: UnableToLoadConfigFileGameInLobby( ) const +{ + return m_CFG->GetString( "lang_0088", "lang_0088" ); +} + +QString CLanguage :: PlayersStillDownloading( const QString &stilldownloading ) const +{ + QString Out = m_CFG->GetString( "lang_0089", "lang_0089" ); + Out.replace("$STILLDOWNLOADING$", stilldownloading); + return Out; +} + +QString CLanguage :: RefreshMessagesEnabled( ) const +{ + return m_CFG->GetString( "lang_0090", "lang_0090" ); +} + +QString CLanguage :: RefreshMessagesDisabled( ) const +{ + return m_CFG->GetString( "lang_0091", "lang_0091" ); +} + +QString CLanguage :: AtLeastOneGameActiveUseForceToShutdown( ) const +{ + return m_CFG->GetString( "lang_0092", "lang_0092" ); +} + +QString CLanguage :: CurrentlyLoadedMapCFGIs( const QString &mapcfg ) const +{ + QString Out = m_CFG->GetString( "lang_0093", "lang_0093" ); + Out.replace("$MAPCFG$", mapcfg); + return Out; +} + +QString CLanguage :: LaggedOutDroppedByAdmin( ) const +{ + return m_CFG->GetString( "lang_0094", "lang_0094" ); +} + +QString CLanguage :: LaggedOutDroppedByVote( ) const +{ + return m_CFG->GetString( "lang_0095", "lang_0095" ); +} + +QString CLanguage :: PlayerVotedToDropLaggers( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0096", "lang_0096" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: LatencyIs( const QString &latency ) const +{ + QString Out = m_CFG->GetString( "lang_0097", "lang_0097" ); + Out.replace("$LATENCY$", latency); + return Out; +} + +QString CLanguage :: SyncLimitIs( const QString &synclimit ) const +{ + QString Out = m_CFG->GetString( "lang_0098", "lang_0098" ); + Out.replace("$SYNCLIMIT$", synclimit); + return Out; +} + +QString CLanguage :: SettingSyncLimitToMinimum( const QString &min ) const +{ + QString Out = m_CFG->GetString( "lang_0099", "lang_0099" ); + Out.replace("$MIN$", min); + return Out; +} + +QString CLanguage :: SettingSyncLimitToMaximum( const QString &max ) const +{ + QString Out = m_CFG->GetString( "lang_0100", "lang_0100" ); + Out.replace("$MAX$", max); + return Out; +} + +QString CLanguage :: SettingSyncLimitTo( const QString &synclimit ) const +{ + QString Out = m_CFG->GetString( "lang_0101", "lang_0101" ); + Out.replace("$SYNCLIMIT$", synclimit); + return Out; +} + +QString CLanguage :: UnableToCreateGameNotLoggedIn( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0102", "lang_0102" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: AdminLoggedIn( ) const +{ + return m_CFG->GetString( "lang_0103", "lang_0103" ); +} + +QString CLanguage :: AdminInvalidPassword( const QString &attempt ) const +{ + QString Out = m_CFG->GetString( "lang_0104", "lang_0104" ); + Out.replace("$ATTEMPT$", attempt); + return Out; +} + +QString CLanguage :: ConnectingToBNET( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0105", "lang_0105" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: ConnectedToBNET( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0106", "lang_0106" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: DisconnectedFromBNET( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0107", "lang_0107" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: LoggedInToBNET( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0108", "lang_0108" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: BNETGameHostingSucceeded( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0109", "lang_0109" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: BNETGameHostingFailed( const QString &server, const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0110", "lang_0110" ); + Out.replace("$SERVER$", server); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: ConnectingToBNETTimedOut( const QString &server ) const +{ + QString Out = m_CFG->GetString( "lang_0111", "lang_0111" ); + Out.replace("$SERVER$", server); + return Out; +} + +QString CLanguage :: PlayerDownloadedTheMap( const QString &user, const QString &seconds, const QString &rate ) const +{ + QString Out = m_CFG->GetString( "lang_0112", "lang_0112" ); + Out.replace("$USER$", user); + Out.replace("$SECONDS$", seconds); + Out.replace("$RATE$", rate); + return Out; +} + +QString CLanguage :: UnableToCreateGameNameTooLong( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0113", "lang_0113" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: SettingGameOwnerTo( const QString &owner ) const +{ + QString Out = m_CFG->GetString( "lang_0114", "lang_0114" ); + Out.replace("$OWNER$", owner); + return Out; +} + +QString CLanguage :: TheGameIsLocked( ) const +{ + return m_CFG->GetString( "lang_0115", "lang_0115" ); +} + +QString CLanguage :: GameLocked( ) const +{ + return m_CFG->GetString( "lang_0116", "lang_0116" ); +} + +QString CLanguage :: GameUnlocked( ) const +{ + return m_CFG->GetString( "lang_0117", "lang_0117" ); +} + +QString CLanguage :: UnableToStartDownloadNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0118", "lang_0118" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UnableToStartDownloadFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0119", "lang_0119" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UnableToSetGameOwner( const QString &owner ) const +{ + QString Out = m_CFG->GetString( "lang_0120", "lang_0120" ); + Out.replace("$OWNER$", owner); + return Out; +} + +QString CLanguage :: UnableToCheckPlayerNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0121", "lang_0121" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: CheckedPlayer( const QString &victim, const QString &ping, const QString &from, const QString &admin, const QString &owner, const QString &spoofed, const QString &spoofedrealm, const QString &reserved ) const +{ + QString Out = m_CFG->GetString( "lang_0122", "lang_0122" ); + Out.replace("$VICTIM$", victim); + Out.replace("$PING$", ping); + Out.replace("$FROM$", from); + Out.replace("$ADMIN$", admin); + Out.replace("$OWNER$", owner); + Out.replace("$SPOOFED$", spoofed); + Out.replace("$SPOOFEDREALM$", spoofedrealm); + Out.replace("$RESERVED$", reserved); + return Out; +} + +QString CLanguage :: UnableToCheckPlayerFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0123", "lang_0123" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: TheGameIsLockedBNET( ) const +{ + return m_CFG->GetString( "lang_0124", "lang_0124" ); +} + +QString CLanguage :: UnableToCreateGameDisabled( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0125", "lang_0125" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: BotDisabled( ) const +{ + return m_CFG->GetString( "lang_0126", "lang_0126" ); +} + +QString CLanguage :: BotEnabled( ) const +{ + return m_CFG->GetString( "lang_0127", "lang_0127" ); +} + +QString CLanguage :: UnableToCreateGameInvalidMap( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0128", "lang_0128" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: WaitingForPlayersBeforeAutoStart( const QString &players, const QString &playersleft ) const +{ + QString Out = m_CFG->GetString( "lang_0129", "lang_0129" ); + Out.replace("$PLAYERS$", players); + Out.replace("$PLAYERSLEFT$", playersleft); + return Out; +} + +QString CLanguage :: AutoStartDisabled( ) const +{ + return m_CFG->GetString( "lang_0130", "lang_0130" ); +} + +QString CLanguage :: AutoStartEnabled( const QString &players ) const +{ + QString Out = m_CFG->GetString( "lang_0131", "lang_0131" ); + Out.replace("$PLAYERS$", players); + return Out; +} + +QString CLanguage :: AnnounceMessageEnabled( ) const +{ + return m_CFG->GetString( "lang_0132", "lang_0132" ); +} + +QString CLanguage :: AnnounceMessageDisabled( ) const +{ + return m_CFG->GetString( "lang_0133", "lang_0133" ); +} + +QString CLanguage :: AutoHostEnabled( ) const +{ + return m_CFG->GetString( "lang_0134", "lang_0134" ); +} + +QString CLanguage :: AutoHostDisabled( ) const +{ + return m_CFG->GetString( "lang_0135", "lang_0135" ); +} + +QString CLanguage :: UnableToLoadSaveGamesOutside( ) const +{ + return m_CFG->GetString( "lang_0136", "lang_0136" ); +} + +QString CLanguage :: UnableToLoadSaveGameGameInLobby( ) const +{ + return m_CFG->GetString( "lang_0137", "lang_0137" ); +} + +QString CLanguage :: LoadingSaveGame( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0138", "lang_0138" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: UnableToLoadSaveGameDoesntExist( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0139", "lang_0139" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: UnableToCreateGameInvalidSaveGame( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0140", "lang_0140" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: UnableToCreateGameSaveGameMapMismatch( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0141", "lang_0141" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: AutoSaveEnabled( ) const +{ + return m_CFG->GetString( "lang_0142", "lang_0142" ); +} + +QString CLanguage :: AutoSaveDisabled( ) const +{ + return m_CFG->GetString( "lang_0143", "lang_0143" ); +} + +QString CLanguage :: DesyncDetected( ) const +{ + return m_CFG->GetString( "lang_0144", "lang_0144" ); +} + +QString CLanguage :: UnableToMuteNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0145", "lang_0145" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: MutedPlayer( const QString &victim, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0146", "lang_0146" ); + Out.replace("$VICTIM$", victim); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnmutedPlayer( const QString &victim, const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0147", "lang_0147" ); + Out.replace("$VICTIM$", victim); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: UnableToMuteFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0148", "lang_0148" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: PlayerIsSavingTheGame( const QString &player ) const +{ + QString Out = m_CFG->GetString( "lang_0149", "lang_0149" ); + Out.replace("$PLAYER$", player); + return Out; +} + +QString CLanguage :: UpdatingClanList( ) const +{ + return m_CFG->GetString( "lang_0150", "lang_0150" ); +} + +QString CLanguage :: UpdatingFriendsList( ) const +{ + return m_CFG->GetString( "lang_0151", "lang_0151" ); +} + +QString CLanguage :: MultipleIPAddressUsageDetected( const QString &player, const QString &others ) const +{ + QString Out = m_CFG->GetString( "lang_0152", "lang_0152" ); + Out.replace("$PLAYER$", player); + Out.replace("$OTHERS$", others); + return Out; +} + +QString CLanguage :: UnableToVoteKickAlreadyInProgress( ) const +{ + return m_CFG->GetString( "lang_0153", "lang_0153" ); +} + +QString CLanguage :: UnableToVoteKickNotEnoughPlayers( ) const +{ + return m_CFG->GetString( "lang_0154", "lang_0154" ); +} + +QString CLanguage :: UnableToVoteKickNoMatchesFound( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0155", "lang_0155" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: UnableToVoteKickPlayerIsReserved( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0156", "lang_0156" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: StartedVoteKick( const QString &victim, const QString &user, const QString &votesneeded ) const +{ + QString Out = m_CFG->GetString( "lang_0157", "lang_0157" ); + Out.replace("$VICTIM$", victim); + Out.replace("$USER$", user); + Out.replace("$VOTESNEEDED$", votesneeded); + return Out; +} + +QString CLanguage :: UnableToVoteKickFoundMoreThanOneMatch( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0158", "lang_0158" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: VoteKickPassed( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0159", "lang_0159" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: ErrorVoteKickingPlayer( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0160", "lang_0160" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: VoteKickAcceptedNeedMoreVotes( const QString &victim, const QString &user, const QString &votes ) const +{ + QString Out = m_CFG->GetString( "lang_0161", "lang_0161" ); + Out.replace("$VICTIM$", victim); + Out.replace("$USER$", user); + Out.replace("$VOTES$", votes); + return Out; +} + +QString CLanguage :: VoteKickCancelled( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0162", "lang_0162" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: VoteKickExpired( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0163", "lang_0163" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: WasKickedByVote( ) const +{ + return m_CFG->GetString( "lang_0164", "lang_0164" ); +} + +QString CLanguage :: TypeYesToVote( const QString &commandtrigger ) const +{ + QString Out = m_CFG->GetString( "lang_0165", "lang_0165" ); + Out.replace("$COMMANDTRIGGER$", commandtrigger); + return Out; +} + +QString CLanguage :: PlayersNotYetPingedAutoStart( const QString ¬pinged ) const +{ + QString Out = m_CFG->GetString( "lang_0166", "lang_0166" ); + Out.replace("$NOTPINGED$", notpinged); + return Out; +} + +QString CLanguage :: WasKickedForNotSpoofChecking( ) const +{ + return m_CFG->GetString( "lang_0167", "lang_0167" ); +} + +QString CLanguage :: WasKickedForHavingFurthestScore( const QString &score, const QString &average ) const +{ + QString Out = m_CFG->GetString( "lang_0168", "lang_0168" ); + Out.replace("$SCORE$", score); + Out.replace("$AVERAGE$", average); + return Out; +} + +QString CLanguage :: PlayerHasScore( const QString &player, const QString &score ) const +{ + QString Out = m_CFG->GetString( "lang_0169", "lang_0169" ); + Out.replace("$PLAYER$", player); + Out.replace("$SCORE$", score); + return Out; +} + +QString CLanguage :: RatedPlayersSpread( const QString &rated, const QString &total, const QString &spread ) const +{ + QString Out = m_CFG->GetString( "lang_0170", "lang_0170" ); + Out.replace("$RATED$", rated); + Out.replace("$TOTAL$", total); + Out.replace("$SPREAD$", spread); + return Out; +} + +QString CLanguage :: ErrorListingMaps( ) const +{ + return m_CFG->GetString( "lang_0171", "lang_0171" ); +} + +QString CLanguage :: FoundMaps( const QString &maps ) const +{ + QString Out = m_CFG->GetString( "lang_0172", "lang_0172" ); + Out.replace("$MAPS$", maps); + return Out; +} + +QString CLanguage :: NoMapsFound( ) const +{ + return m_CFG->GetString( "lang_0173", "lang_0173" ); +} + +QString CLanguage :: ErrorListingMapConfigs( ) const +{ + return m_CFG->GetString( "lang_0174", "lang_0174" ); +} + +QString CLanguage :: FoundMapConfigs( const QString &mapconfigs ) const +{ + QString Out = m_CFG->GetString( "lang_0175", "lang_0175" ); + Out.replace("$MAPCONFIGS$", mapconfigs); + return Out; +} + +QString CLanguage :: NoMapConfigsFound( ) const +{ + return m_CFG->GetString( "lang_0176", "lang_0176" ); +} + +QString CLanguage :: PlayerFinishedLoading( const QString &user ) const +{ + QString Out = m_CFG->GetString( "lang_0177", "lang_0177" ); + Out.replace("$USER$", user); + return Out; +} + +QString CLanguage :: PleaseWaitPlayersStillLoading( ) const +{ + return m_CFG->GetString( "lang_0178", "lang_0178" ); +} + +QString CLanguage :: MapDownloadsDisabled( ) const +{ + return m_CFG->GetString( "lang_0179", "lang_0179" ); +} + +QString CLanguage :: MapDownloadsEnabled( ) const +{ + return m_CFG->GetString( "lang_0180", "lang_0180" ); +} + +QString CLanguage :: MapDownloadsConditional( ) const +{ + return m_CFG->GetString( "lang_0181", "lang_0181" ); +} + +QString CLanguage :: SettingHCL( const QString &HCL ) const +{ + QString Out = m_CFG->GetString( "lang_0182", "lang_0182" ); + Out.replace("$HCL$", HCL); + return Out; +} + +QString CLanguage :: UnableToSetHCLInvalid( ) const +{ + return m_CFG->GetString( "lang_0183", "lang_0183" ); +} + +QString CLanguage :: UnableToSetHCLTooLong( ) const +{ + return m_CFG->GetString( "lang_0184", "lang_0184" ); +} + +QString CLanguage :: TheHCLIs( const QString &HCL ) const +{ + QString Out = m_CFG->GetString( "lang_0185", "lang_0185" ); + Out.replace("$HCL$", HCL); + return Out; +} + +QString CLanguage :: TheHCLIsTooLongUseForceToStart( ) const +{ + return m_CFG->GetString( "lang_0186", "lang_0186" ); +} + +QString CLanguage :: ClearingHCL( ) const +{ + return m_CFG->GetString( "lang_0187", "lang_0187" ); +} + +QString CLanguage :: TryingToRehostAsPrivateGame( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0188", "lang_0188" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: TryingToRehostAsPublicGame( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0189", "lang_0189" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: RehostWasSuccessful( ) const +{ + return m_CFG->GetString( "lang_0190", "lang_0190" ); +} + +QString CLanguage :: TryingToJoinTheGameButBannedByName( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0191", "lang_0191" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: TryingToJoinTheGameButBannedByIP( const QString &victim, const QString &ip, const QString &bannedname ) const +{ + QString Out = m_CFG->GetString( "lang_0192", "lang_0192" ); + Out.replace("$VICTIM$", victim); + Out.replace("$IP$", ip); + Out.replace("$BANNEDNAME$", bannedname); + return Out; +} + +QString CLanguage :: HasBannedName( const QString &victim ) const +{ + QString Out = m_CFG->GetString( "lang_0193", "lang_0193" ); + Out.replace("$VICTIM$", victim); + return Out; +} + +QString CLanguage :: HasBannedIP( const QString &victim, const QString &ip, const QString &bannedname ) const +{ + QString Out = m_CFG->GetString( "lang_0194", "lang_0194" ); + Out.replace("$VICTIM$", victim); + Out.replace("$IP$", ip); + Out.replace("$BANNEDNAME$", bannedname); + return Out; +} + +QString CLanguage :: PlayersInGameState( const QString &number, const QString &players ) const +{ + QString Out = m_CFG->GetString( "lang_0195", "lang_0195" ); + Out.replace("$NUMBER$", number); + Out.replace("$PLAYERS$", players); + return Out; +} + +QString CLanguage :: ValidServers( const QString &servers ) const +{ + QString Out = m_CFG->GetString( "lang_0196", "lang_0196" ); + Out.replace("$SERVERS$", servers); + return Out; +} + +QString CLanguage :: TeamCombinedScore( const QString &team, const QString &score ) const +{ + QString Out = m_CFG->GetString( "lang_0197", "lang_0197" ); + Out.replace("$TEAM$", team); + Out.replace("$SCORE$", score); + return Out; +} + +QString CLanguage :: BalancingSlotsCompleted( ) const +{ + return m_CFG->GetString( "lang_0198", "lang_0198" ); +} + +QString CLanguage :: PlayerWasKickedForFurthestScore( const QString &name, const QString &score, const QString &average ) const +{ + QString Out = m_CFG->GetString( "lang_0199", "lang_0199" ); + Out.replace("$NAME$", name); + Out.replace("$SCORE$", score); + Out.replace("$AVERAGE$", average); + return Out; +} + +QString CLanguage :: LocalAdminMessagesEnabled( ) const +{ + return m_CFG->GetString( "lang_0200", "lang_0200" ); +} + +QString CLanguage :: LocalAdminMessagesDisabled( ) const +{ + return m_CFG->GetString( "lang_0201", "lang_0201" ); +} + +QString CLanguage :: WasDroppedDesync( ) const +{ + return m_CFG->GetString( "lang_0202", "lang_0202" ); +} + +QString CLanguage :: WasKickedForHavingLowestScore( const QString &score ) const +{ + QString Out = m_CFG->GetString( "lang_0203", "lang_0203" ); + Out.replace("$SCORE$", score); + return Out; +} + +QString CLanguage :: PlayerWasKickedForLowestScore( const QString &name, const QString &score ) const +{ + QString Out = m_CFG->GetString( "lang_0204", "lang_0204" ); + Out.replace("$NAME$", name); + Out.replace("$SCORE$", score); + return Out; +} + +QString CLanguage :: ReloadingConfigurationFiles( ) const +{ + return m_CFG->GetString( "lang_0205", "lang_0205" ); +} + +QString CLanguage :: CountDownAbortedSomeoneLeftRecently( ) const +{ + return m_CFG->GetString( "lang_0206", "lang_0206" ); +} + +QString CLanguage :: UnableToCreateGameMustEnforceFirst( const QString &gamename ) const +{ + QString Out = m_CFG->GetString( "lang_0207", "lang_0207" ); + Out.replace("$GAMENAME$", gamename); + return Out; +} + +QString CLanguage :: UnableToLoadReplaysOutside( ) const +{ + return m_CFG->GetString( "lang_0208", "lang_0208" ); +} + +QString CLanguage :: LoadingReplay( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0209", "lang_0209" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: UnableToLoadReplayDoesntExist( const QString &file ) const +{ + QString Out = m_CFG->GetString( "lang_0210", "lang_0210" ); + Out.replace("$FILE$", file); + return Out; +} + +QString CLanguage :: CommandTrigger( const QString &trigger ) const +{ + QString Out = m_CFG->GetString( "lang_0211", "lang_0211" ); + Out.replace("$TRIGGER$", trigger); + return Out; +} + +QString CLanguage :: CantEndGameOwnerIsStillPlaying( const QString &owner ) const +{ + QString Out = m_CFG->GetString( "lang_0212", "lang_0212" ); + Out.replace("$OWNER$", owner); + return Out; +} + +QString CLanguage :: CantUnhostGameOwnerIsPresent( const QString &owner ) const +{ + QString Out = m_CFG->GetString( "lang_0213", "lang_0213" ); + Out.replace("$OWNER$", owner); + return Out; +} + +QString CLanguage :: WasAutomaticallyDroppedAfterSeconds( const QString &seconds ) const +{ + QString Out = m_CFG->GetString( "lang_0214", "lang_0214" ); + Out.replace("$SECONDS$", seconds); + return Out; +} + +QString CLanguage :: HasLostConnectionTimedOutGProxy( ) const +{ + return m_CFG->GetString( "lang_0215", "lang_0215" ); +} + +QString CLanguage :: HasLostConnectionSocketErrorGProxy( const QString &error ) const +{ + QString Out = m_CFG->GetString( "lang_0216", "lang_0216" ); + Out.replace("$ERROR$", error); + return Out; +} + +QString CLanguage :: HasLostConnectionClosedByRemoteHostGProxy( ) const +{ + return m_CFG->GetString( "lang_0217", "lang_0217" ); +} + +QString CLanguage :: WaitForReconnectSecondsRemain( const QString &seconds ) const +{ + QString Out = m_CFG->GetString( "lang_0218", "lang_0218" ); + Out.replace("$SECONDS$", seconds); + return Out; +} + +QString CLanguage :: WasUnrecoverablyDroppedFromGProxy( ) const +{ + return m_CFG->GetString( "lang_0219", "lang_0219" ); +} + +QString CLanguage :: PlayerReconnectedWithGProxy( const QString &name ) const +{ + QString Out = m_CFG->GetString( "lang_0220", "lang_0220" ); + Out.replace("$NAME$", name); + return Out; +} diff --git a/src/libghost/language.h b/src/libghost/language.h new file mode 100644 index 0000000..f85b477 --- /dev/null +++ b/src/libghost/language.h @@ -0,0 +1,263 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef LANGUAGE_H +#define LANGUAGE_H + +#include + +class CConfig; + +// +// CLanguage +// + +class CLanguage +{ +private: + CConfig *m_CFG; + +public: + CLanguage( const QString &nCFGFile ); + ~CLanguage( ); + + QString UnableToCreateGameTryAnotherName( const QString &server, const QString &gamename ) const; + QString UserIsAlreadyAnAdmin( const QString &server, const QString &user ) const; + QString AddedUserToAdminDatabase( const QString &server, const QString &user ) const; + QString ErrorAddingUserToAdminDatabase( const QString &server, const QString &user ) const; + QString YouDontHaveAccessToThatCommand( ) const; + QString UserIsAlreadyBanned( const QString &server, const QString &victim ) const; + QString BannedUser( const QString &server, const QString &victim ) const; + QString ErrorBanningUser( const QString &server, const QString &victim ) const; + QString UserIsAnAdmin( const QString &server, const QString &user ) const; + QString UserIsNotAnAdmin( const QString &server, const QString &user ) const; + QString UserWasBannedOnByBecause( const QString &server, const QString &victim, const QString &date, const QString &admin, const QString &reason ) const; + QString UserIsNotBanned( const QString &server, const QString &victim ) const; + QString ThereAreNoAdmins( const QString &server ) const; + QString ThereIsAdmin( const QString &server ) const; + QString ThereAreAdmins( const QString &server, const QString &count ) const; + QString ThereAreNoBannedUsers( const QString &server ) const; + QString ThereIsBannedUser( const QString &server ) const; + QString ThereAreBannedUsers( const QString &server, const QString &count ) const; + QString YouCantDeleteTheRootAdmin( ) const; + QString DeletedUserFromAdminDatabase( const QString &server, const QString &user ) const; + QString ErrorDeletingUserFromAdminDatabase( const QString &server, const QString &user ) const; + QString UnbannedUser( const QString &victim ) const; + QString ErrorUnbanningUser( const QString &victim ) const; + QString GameNumberIs( const QString &number, const QString &description ) const; + QString GameNumberDoesntExist( const QString &number ) const; + QString GameIsInTheLobby( const QString &description, const QString ¤t, const QString &max ) const; + QString ThereIsNoGameInTheLobby( const QString ¤t, const QString &max ) const; + QString UnableToLoadConfigFilesOutside( ) const; + QString LoadingConfigFile( const QString &file ) const; + QString UnableToLoadConfigFileDoesntExist( const QString &file ) const; + QString CreatingPrivateGame( const QString &gamename, const QString &user ) const; + QString CreatingPublicGame( const QString &gamename, const QString &user ) const; + QString UnableToUnhostGameCountdownStarted( const QString &description ) const; + QString UnhostingGame( const QString &description ) const; + QString UnableToUnhostGameNoGameInLobby( ) const; + QString VersionAdmin( const QString &version ) const; + QString VersionNotAdmin( const QString &version ) const; + QString UnableToCreateGameAnotherGameInLobby( const QString &gamename, const QString &description ) const; + QString UnableToCreateGameMaxGamesReached( const QString &gamename, const QString &max ) const; + QString GameIsOver( const QString &description ) const; + QString SpoofCheckByReplying( ) const; + QString GameRefreshed( ) const; + QString SpoofPossibleIsAway( const QString &user ) const; + QString SpoofPossibleIsUnavailable( const QString &user ) const; + QString SpoofPossibleIsRefusingMessages( const QString &user ) const; + QString SpoofDetectedIsNotInGame( const QString &user ) const; + QString SpoofDetectedIsInPrivateChannel( const QString &user ) const; + QString SpoofDetectedIsInAnotherGame( const QString &user ) const; + QString CountDownAborted( ) const; + QString TryingToJoinTheGameButBanned( const QString &victim ) const; + QString UnableToBanNoMatchesFound( const QString &victim ) const; + QString PlayerWasBannedByPlayer( const QString &server, const QString &victim, const QString &user ) const; + QString UnableToBanFoundMoreThanOneMatch( const QString &victim ) const; + QString AddedPlayerToTheHoldList( const QString &user ) const; + QString UnableToKickNoMatchesFound( const QString &victim ) const; + QString UnableToKickFoundMoreThanOneMatch( const QString &victim ) const; + QString SettingLatencyToMinimum( const QString &min ) const; + QString SettingLatencyToMaximum( const QString &max ) const; + QString SettingLatencyTo( const QString &latency ) const; + QString KickingPlayersWithPingsGreaterThan( const QString &total, const QString &ping ) const; + QString HasPlayedGamesWithThisBot( const QString &user, const QString &firstgame, const QString &lastgame, const QString &totalgames, const QString &avgloadingtime, const QString &avgstay ) const; + QString HasntPlayedGamesWithThisBot( const QString &user ) const; + QString AutokickingPlayerForExcessivePing( const QString &victim, const QString &ping ) const; + QString SpoofCheckAcceptedFor( const QString &server, const QString &user ) const; + QString PlayersNotYetSpoofChecked( const QString ¬spoofchecked ) const; + QString ManuallySpoofCheckByWhispering( const QString &hostname ) const; + QString SpoofCheckByWhispering( const QString &hostname ) const; + QString EveryoneHasBeenSpoofChecked( ) const; + QString PlayersNotYetPinged( const QString ¬pinged ) const; + QString EveryoneHasBeenPinged( ) const; + QString ShortestLoadByPlayer( const QString &user, const QString &loadingtime ) const; + QString LongestLoadByPlayer( const QString &user, const QString &loadingtime ) const; + QString YourLoadingTimeWas( const QString &loadingtime ) const; + QString HasPlayedDotAGamesWithThisBot( const QString &user, const QString &totalgames, const QString &totalwins, const QString &totallosses, const QString &totalkills, const QString &totaldeaths, const QString &totalcreepkills, const QString &totalcreepdenies, const QString &totalassists, const QString &totalneutralkills, const QString &totaltowerkills, const QString &totalraxkills, const QString &totalcourierkills, const QString &avgkills, const QString &avgdeaths, const QString &avgcreepkills, const QString &avgcreepdenies, const QString &avgassists, const QString &avgneutralkills, const QString &avgtowerkills, const QString &avgraxkills, const QString &avgcourierkills ) const; + QString HasntPlayedDotAGamesWithThisBot( const QString &user ) const; + QString WasKickedForReservedPlayer( const QString &reserved ) const; + QString WasKickedForOwnerPlayer( const QString &owner ) const; + QString WasKickedByPlayer( const QString &user ) const; + QString HasLostConnectionPlayerError( const QString &error ) const; + QString HasLostConnectionSocketError( const QString &error ) const; + QString HasLostConnectionClosedByRemoteHost( ) const; + QString HasLeftVoluntarily( ) const; + QString EndingGame( const QString &description ) const; + QString HasLostConnectionTimedOut( ) const; + QString GlobalChatMuted( ) const; + QString GlobalChatUnmuted( ) const; + QString ShufflingPlayers( ) const; + QString UnableToLoadConfigFileGameInLobby( ) const; + QString PlayersStillDownloading( const QString &stilldownloading ) const; + QString RefreshMessagesEnabled( ) const; + QString RefreshMessagesDisabled( ) const; + QString AtLeastOneGameActiveUseForceToShutdown( ) const; + QString CurrentlyLoadedMapCFGIs( const QString &mapcfg ) const; + QString LaggedOutDroppedByAdmin( ) const; + QString LaggedOutDroppedByVote( ) const; + QString PlayerVotedToDropLaggers( const QString &user ) const; + QString LatencyIs( const QString &latency ) const; + QString SyncLimitIs( const QString &synclimit ) const; + QString SettingSyncLimitToMinimum( const QString &min ) const; + QString SettingSyncLimitToMaximum( const QString &max ) const; + QString SettingSyncLimitTo( const QString &synclimit ) const; + QString UnableToCreateGameNotLoggedIn( const QString &gamename ) const; + QString AdminLoggedIn( ) const; + QString AdminInvalidPassword( const QString &attempt ) const; + QString ConnectingToBNET( const QString &server ) const; + QString ConnectedToBNET( const QString &server ) const; + QString DisconnectedFromBNET( const QString &server ) const; + QString LoggedInToBNET( const QString &server ) const; + QString BNETGameHostingSucceeded( const QString &server ) const; + QString BNETGameHostingFailed( const QString &server, const QString &gamename ) const; + QString ConnectingToBNETTimedOut( const QString &server ) const; + QString PlayerDownloadedTheMap( const QString &user, const QString &seconds, const QString &rate ) const; + QString UnableToCreateGameNameTooLong( const QString &gamename ) const; + QString SettingGameOwnerTo( const QString &owner ) const; + QString TheGameIsLocked( ) const; + QString GameLocked( ) const; + QString GameUnlocked( ) const; + QString UnableToStartDownloadNoMatchesFound( const QString &victim ) const; + QString UnableToStartDownloadFoundMoreThanOneMatch( const QString &victim ) const; + QString UnableToSetGameOwner( const QString &owner ) const; + QString UnableToCheckPlayerNoMatchesFound( const QString &victim ) const; + QString CheckedPlayer( const QString &victim, const QString &ping, const QString &from, const QString &admin, const QString &owner, const QString &spoofed, const QString &spoofedrealm, const QString &reserved ) const; + QString UnableToCheckPlayerFoundMoreThanOneMatch( const QString &victim ) const; + QString TheGameIsLockedBNET( ) const; + QString UnableToCreateGameDisabled( const QString &gamename ) const; + QString BotDisabled( ) const; + QString BotEnabled( ) const; + QString UnableToCreateGameInvalidMap( const QString &gamename ) const; + QString WaitingForPlayersBeforeAutoStart( const QString &players, const QString &playersleft ) const; + QString AutoStartDisabled( ) const; + QString AutoStartEnabled( const QString &players ) const; + QString AnnounceMessageEnabled( ) const; + QString AnnounceMessageDisabled( ) const; + QString AutoHostEnabled( ) const; + QString AutoHostDisabled( ) const; + QString UnableToLoadSaveGamesOutside( ) const; + QString UnableToLoadSaveGameGameInLobby( ) const; + QString LoadingSaveGame( const QString &file ) const; + QString UnableToLoadSaveGameDoesntExist( const QString &file ) const; + QString UnableToCreateGameInvalidSaveGame( const QString &gamename ) const; + QString UnableToCreateGameSaveGameMapMismatch( const QString &gamename ) const; + QString AutoSaveEnabled( ) const; + QString AutoSaveDisabled( ) const; + QString DesyncDetected( ) const; + QString UnableToMuteNoMatchesFound( const QString &victim ) const; + QString MutedPlayer( const QString &victim, const QString &user ) const; + QString UnmutedPlayer( const QString &victim, const QString &user ) const; + QString UnableToMuteFoundMoreThanOneMatch( const QString &victim ) const; + QString PlayerIsSavingTheGame( const QString &player ) const; + QString UpdatingClanList( ) const; + QString UpdatingFriendsList( ) const; + QString MultipleIPAddressUsageDetected( const QString &player, const QString &others ) const; + QString UnableToVoteKickAlreadyInProgress( ) const; + QString UnableToVoteKickNotEnoughPlayers( ) const; + QString UnableToVoteKickNoMatchesFound( const QString &victim ) const; + QString UnableToVoteKickPlayerIsReserved( const QString &victim ) const; + QString StartedVoteKick( const QString &victim, const QString &user, const QString &votesneeded ) const; + QString UnableToVoteKickFoundMoreThanOneMatch( const QString &victim ) const; + QString VoteKickPassed( const QString &victim ) const; + QString ErrorVoteKickingPlayer( const QString &victim ) const; + QString VoteKickAcceptedNeedMoreVotes( const QString &victim, const QString &user, const QString &votes ) const; + QString VoteKickCancelled( const QString &victim ) const; + QString VoteKickExpired( const QString &victim ) const; + QString WasKickedByVote( ) const; + QString TypeYesToVote( const QString &commandtrigger ) const; + QString PlayersNotYetPingedAutoStart( const QString ¬pinged ) const; + QString WasKickedForNotSpoofChecking( ) const; + QString WasKickedForHavingFurthestScore( const QString &score, const QString &average ) const; + QString PlayerHasScore( const QString &player, const QString &score ) const; + QString RatedPlayersSpread( const QString &rated, const QString &total, const QString &spread ) const; + QString ErrorListingMaps( ) const; + QString FoundMaps( const QString &maps ) const; + QString NoMapsFound( ) const; + QString ErrorListingMapConfigs( ) const; + QString FoundMapConfigs( const QString &mapconfigs ) const; + QString NoMapConfigsFound( ) const; + QString PlayerFinishedLoading( const QString &user ) const; + QString PleaseWaitPlayersStillLoading( ) const; + QString MapDownloadsDisabled( ) const; + QString MapDownloadsEnabled( ) const; + QString MapDownloadsConditional( ) const; + QString SettingHCL( const QString &HCL ) const; + QString UnableToSetHCLInvalid( ) const; + QString UnableToSetHCLTooLong( ) const; + QString TheHCLIs( const QString &HCL ) const; + QString TheHCLIsTooLongUseForceToStart( ) const; + QString ClearingHCL( ) const; + QString TryingToRehostAsPrivateGame( const QString &gamename ) const; + QString TryingToRehostAsPublicGame( const QString &gamename ) const; + QString RehostWasSuccessful( ) const; + QString TryingToJoinTheGameButBannedByName( const QString &victim ) const; + QString TryingToJoinTheGameButBannedByIP( const QString &victim, const QString &ip, const QString &bannedname ) const; + QString HasBannedName( const QString &victim ) const; + QString HasBannedIP( const QString &victim, const QString &ip, const QString &bannedname ) const; + QString PlayersInGameState( const QString &number, const QString &players ) const; + QString ValidServers( const QString &servers ) const; + QString TeamCombinedScore( const QString &team, const QString &score ) const; + QString BalancingSlotsCompleted( ) const; + QString PlayerWasKickedForFurthestScore( const QString &name, const QString &score, const QString &average ) const; + QString LocalAdminMessagesEnabled( ) const; + QString LocalAdminMessagesDisabled( ) const; + QString WasDroppedDesync( ) const; + QString WasKickedForHavingLowestScore( const QString &score ) const; + QString PlayerWasKickedForLowestScore( const QString &name, const QString &score ) const; + QString ReloadingConfigurationFiles( ) const; + QString CountDownAbortedSomeoneLeftRecently( ) const; + QString UnableToCreateGameMustEnforceFirst( const QString &gamename ) const; + QString UnableToLoadReplaysOutside( ) const; + QString LoadingReplay( const QString &file ) const; + QString UnableToLoadReplayDoesntExist( const QString &file ) const; + QString CommandTrigger( const QString &trigger ) const; + QString CantEndGameOwnerIsStillPlaying( const QString &owner ) const; + QString CantUnhostGameOwnerIsPresent( const QString &owner ) const; + QString WasAutomaticallyDroppedAfterSeconds( const QString &seconds ) const; + QString HasLostConnectionTimedOutGProxy( ) const; + QString HasLostConnectionSocketErrorGProxy( const QString &error ) const; + QString HasLostConnectionClosedByRemoteHostGProxy( ) const; + QString WaitForReconnectSecondsRemain( const QString &seconds ) const; + QString WasUnrecoverablyDroppedFromGProxy( ) const; + QString PlayerReconnectedWithGProxy( const QString &name ) const; +}; + +#endif diff --git a/src/libghost/libghost.pro b/src/libghost/libghost.pro new file mode 100644 index 0000000..58b1d0e --- /dev/null +++ b/src/libghost/libghost.pro @@ -0,0 +1,109 @@ +# ------------------------------------------------- +# Project created by QtCreator 2010-04-19T13:31:03 +# ------------------------------------------------- +! include( ../lib.pri ) { + error( Couldn't find lib.pri! ) +} + +QT += network sql +QT -= gui +TARGET = ghost +CONFIG += debug_and_release +INCLUDEPATH += .. \ + ../../include \ + ../../include/mysql +LIBS += -L../../src/lib +LIBS += -lbncsutil -lgmp + +macx { + LIBS += -framework CoreFoundation -framework CoreServices + LIBS += -L. -L/usr/lib -lbz2 -lz + CONFIG += x86_64 x86 +# CXXFLAGS += -fvisibility=hidden +# QMAKE_CXXFLAGS += -fvisibility=hidden +} + +#!isEmpty( $$MY_LIBRARY_DEST_PATH ) { +# QMAKE_POST_LINK = make install +# list_of_files_to_install.files = $TARGET.$TARGET_EXT +# list_of_files_to_install.path = $$MY_LIBRARY_DEST_PATH +# INSTALLS += list_of_files_to_install +#} + + + +SOURCES += util.cpp \ + statsw3mmd.cpp \ + statsdota.cpp \ + stats.cpp \ + sqlite3.c \ + sha1.cpp \ + savegame.cpp \ + replay.cpp \ + packed.cpp \ + map.cpp \ + language.cpp \ + gpsprotocol.cpp \ + ghostdbsqlite.cpp \ + ghostdbmysql.cpp \ + ghostdb.cpp \ + ghost.cpp \ + gameslot.cpp \ + gameprotocol.cpp \ + gameplayer.cpp \ + game_base.cpp \ + game_admin.cpp \ + game.cpp \ + csvparser.cpp \ + crc32.cpp \ + config.cpp \ + commandpacket.cpp \ + bnlsprotocol.cpp \ + bnlsclient.cpp \ + bnetprotocol.cpp \ + bnet.cpp \ + bncsutilinterface.cpp \ + mpqarchive.cpp \ + mpqfile.cpp +#OTHER_FILES += w3g_format.txt \ +# w3g_actions.txt \ +# ghost.vcproj + +HEADERS += interfaces.h \ + util.h \ + statsw3mmd.h \ + statsdota.h \ + stats.h \ + sqlite3ext.h \ + sqlite3.h \ + sha1.h \ + savegame.h \ + replay.h \ + packed.h \ + next_combination.h \ + map.h \ + language.h \ + includes.h \ + gpsprotocol.h \ + ghostdbsqlite.h \ + ghostdbmysql.h \ + ghostdb.h \ + ghost.h \ + ghost_p.h \ + gameslot.h \ + gameprotocol.h \ + gameplayer.h \ + game_base.h \ + game_admin.h \ + game.h \ + csvparser.h \ + crc32.h \ + config.h \ + commandpacket.h \ + bnlsprotocol.h \ + bnlsclient.h \ + bnetprotocol.h \ + bnet.h \ + bncsutilinterface.h \ + mpqarchive.h \ + mpqfile.h diff --git a/src/libghost/main.cpp b/src/libghost/main.cpp new file mode 100644 index 0000000..df6cabd --- /dev/null +++ b/src/libghost/main.cpp @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include + +#include "ghost.h" +#include "util.h" +#include "config.h" +#ifdef WIN32 +#include "windows.h" +#endif + +QFile gLogFile; +QTextStream gLogStream(&gLogFile); + +QString gCFGFile; +quint32 gLogMethod; +CGHost *gGHost = NULL; + +void SignalCatcher2( int s ) +{ + CONSOLE_Print( "[!!!] caught signal " + QString::number( s ) + ", exiting NOW" ); + + if( gGHost ) + { + if( gGHost->m_Exiting ) + exit( 1 ); + else + gGHost->m_Exiting = true; + } + else + exit( 1 ); +} + +void SignalCatcher( int s ) +{ + // signal( SIGABRT, SignalCatcher2 ); + signal( SIGINT, SignalCatcher2 ); + + CONSOLE_Print( "[!!!] caught signal " + QString::number( s ) + ", exiting nicely" ); + + if( gGHost ) + gGHost->EventExitNice(); + else + exit( 1 ); +} + +// +// main +// + +#include "mpqarchive.h" +#include "mpqfile.h" + +int main( int argc, char **argv ) +{ + QCoreApplication a(argc, argv); + + /*MPQArchive arch("/mnt/disk/Programme/Warcraft III/War3Patch.mpq"); + if (!arch.open() && arch.m_Error != MPQArchive::NO_FILE_LIST) + { + DEBUG_Print("Failed to open, error " + QString::number(arch.m_Error)); + exit(1); + }*/ + + + + /*if (!arch.m_ListFile->read()) + { + DEBUG_Print("Failed to read file list, error " + QString::number(arch.m_ListFile->m_Error)); + }*/ + + + /*DEBUG_Print("Successfully open MPQ file"); + + MPQFile* common_j = arch.getFile("Scripts\\common.j"); + + if (!common_j->read()) + { + DEBUG_Print("Failed to read common.j, error " + QString::number(common_j->m_Error)); + } + exit(0);*/ + + gCFGFile = "ghost.cfg"; + + if( argc > 1 && argv[1] ) + gCFGFile = argv[1]; + + // read config file + + CConfig CFG; + CFG.Read( "default.cfg" ); + CFG.Read( gCFGFile ); + gLogFile.setFileName(CFG.GetString( "bot_log", QString( ) )); + gLogMethod = CFG.GetInt( "bot_logmethod", 1 ); + + if( !gLogFile.fileName().isEmpty() ) + { + if( gLogMethod == 1 ) + { + // log method 1: open, append, and close the log for every message + // this works well on Linux but poorly on Windows, particularly as the log file grows in size + // the log file can be edited/moved/deleted while GHost++ is running + } + else if( gLogMethod == 2 ) + { + // log method 2: open the log on startup, flush the log for every message, close the log on shutdown + // the log file CANNOT be edited/moved/deleted while GHost++ is running + + gLogFile.open(QFile::WriteOnly | QFile::Append); + } + } + + CONSOLE_Print( "[GHOST] starting up" ); + + if( !gLogFile.fileName().isEmpty() ) + { + if( gLogMethod == 1 ) + CONSOLE_Print( "[GHOST] using log method 1, logging is enabled and [" + gLogFile.fileName() + "] will not be locked" ); + else if( gLogMethod == 2 ) + { + if( gLogFile.error() != QFile::NoError ) + CONSOLE_Print( "[GHOST] using log method 2 but unable to open [" + gLogFile.fileName() + "] for appending, logging is disabled" ); + else + CONSOLE_Print( "[GHOST] using log method 2, logging is enabled and [" + gLogFile.fileName() + "] is now locked" ); + } + } + else + CONSOLE_Print( "[GHOST] no log file specified, logging is disabled" ); + + // catch SIGABRT and SIGINT + + // signal( SIGABRT, SignalCatcher ); + signal( SIGINT, SignalCatcher ); + +#ifndef WIN32 + // disable SIGPIPE since some systems like OS X don't define MSG_NOSIGNAL + + signal( SIGPIPE, SIG_IGN ); +#endif + +#ifdef WIN32 + // increase process priority + + CONSOLE_Print( "[GHOST] setting process priority to \"above normal\"" ); + SetPriorityClass( GetCurrentProcess( ), ABOVE_NORMAL_PRIORITY_CLASS ); +#endif + + // initialize ghost + + gGHost = new CGHost( &CFG, gCFGFile ); + + QObject::connect(gGHost, SIGNAL(destroyed()), &a, SLOT(deleteLater())); + + return a.exec(); +} diff --git a/ghost/map.cpp b/src/libghost/map.cpp similarity index 73% rename from ghost/map.cpp rename to src/libghost/map.cpp index 857a997..f3ca283 100644 --- a/ghost/map.cpp +++ b/src/libghost/map.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -18,6 +18,9 @@ */ +#include +using std::istringstream; + #include "ghost.h" #include "util.h" #include "crc32.h" @@ -25,9 +28,6 @@ #include "config.h" #include "map.h" -#define __STORMLIB_SELF__ -#include - #define ROTL(x,n) ((x)<<(n))|((x)>>(32-(n))) // this won't work with signed types #define ROTR(x,n) ((x)>>(n))|((x)<<(32-(n))) // this won't work with signed types @@ -73,7 +73,7 @@ CMap :: CMap( CGHost *nGHost ) m_Slots.push_back( CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, 11, 11, SLOTRACE_RANDOM | SLOTRACE_SELECTABLE ) ); } -CMap :: CMap( CGHost *nGHost, CConfig *CFG, string nCFGFile ) +CMap :: CMap( CGHost *nGHost, const CConfig &CFG, const QString &nCFGFile ) { m_GHost = nGHost; Load( CFG, nCFGFile ); @@ -84,7 +84,7 @@ CMap :: ~CMap( ) } -BYTEARRAY CMap :: GetMapGameFlags( ) +QByteArray CMap :: GetMapGameFlags( ) const { /* @@ -111,7 +111,7 @@ BYTEARRAY CMap :: GetMapGameFlags( ) */ - uint32_t GameFlags = 0; + quint32 GameFlags = 0; // speed @@ -155,48 +155,48 @@ BYTEARRAY CMap :: GetMapGameFlags( ) if( m_MapFlags & MAPFLAG_RANDOMRACES ) GameFlags |= 0x04000000; - return UTIL_CreateByteArray( GameFlags, false ); + return Util::fromUInt32(GameFlags); } -uint32_t CMap :: GetMapGameType( ) +quint32 CMap :: GetMapGameType( ) const { /* spec stolen from Strilanc as follows: - Public Enum GameTypes As UInteger - None = 0 - Unknown0 = 1 << 0 '[always seems to be set?] + Public Enum GameTypes As UInteger + None = 0 + Unknown0 = 1 << 0 '[always seems to be set?] - '''Setting this bit causes wc3 to check the map and disc if it is not signed by Blizzard - AuthenticatedMakerBlizzard = 1 << 3 - OfficialMeleeGame = 1 << 5 + '''Setting this bit causes wc3 to check the map and disc if it is not signed by Blizzard + AuthenticatedMakerBlizzard = 1 << 3 + OfficialMeleeGame = 1 << 5 SavedGame = 1 << 9 - PrivateGame = 1 << 11 - - MakerUser = 1 << 13 - MakerBlizzard = 1 << 14 - TypeMelee = 1 << 15 - TypeScenario = 1 << 16 - SizeSmall = 1 << 17 - SizeMedium = 1 << 18 - SizeLarge = 1 << 19 - ObsFull = 1 << 20 - ObsOnDeath = 1 << 21 - ObsNone = 1 << 22 - - MaskObs = ObsFull Or ObsOnDeath Or ObsNone - MaskMaker = MakerBlizzard Or MakerUser - MaskType = TypeMelee Or TypeScenario - MaskSize = SizeLarge Or SizeMedium Or SizeSmall - MaskFilterable = MaskObs Or MaskMaker Or MaskType Or MaskSize - End Enum + PrivateGame = 1 << 11 + + MakerUser = 1 << 13 + MakerBlizzard = 1 << 14 + TypeMelee = 1 << 15 + TypeScenario = 1 << 16 + SizeSmall = 1 << 17 + SizeMedium = 1 << 18 + SizeLarge = 1 << 19 + ObsFull = 1 << 20 + ObsOnDeath = 1 << 21 + ObsNone = 1 << 22 + + MaskObs = ObsFull Or ObsOnDeath Or ObsNone + MaskMaker = MakerBlizzard Or MakerUser + MaskType = TypeMelee Or TypeScenario + MaskSize = SizeLarge Or SizeMedium Or SizeSmall + MaskFilterable = MaskObs Or MaskMaker Or MaskType Or MaskSize + End Enum */ // note: we allow "conflicting" flags to be set at the same time (who knows if this is a good idea) // we also don't set any flags this class is unaware of such as Unknown0, SavedGame, and PrivateGame - uint32_t GameType = 0; + quint32 GameType = 0; // maker @@ -233,7 +233,7 @@ uint32_t CMap :: GetMapGameType( ) return GameType; } -unsigned char CMap :: GetMapLayoutStyle( ) +unsigned char CMap :: GetMapLayoutStyle( ) const { // 0 = melee // 1 = custom forces @@ -249,26 +249,26 @@ unsigned char CMap :: GetMapLayoutStyle( ) return 3; } -void CMap :: Load( CConfig *CFG, string nCFGFile ) +void CMap :: Load( const CConfig &CFG, const QString &nCFGFile ) { m_Valid = true; m_CFGFile = nCFGFile; // load the map data - m_MapLocalPath = CFG->GetString( "map_localpath", string( ) ); + m_MapLocalPath = CFG.GetString( "map_localpath", QString( ) ); m_MapData.clear( ); - if( !m_MapLocalPath.empty( ) ) + if( !m_MapLocalPath.isEmpty( ) ) m_MapData = UTIL_FileRead( m_GHost->m_MapPath + m_MapLocalPath ); // load the map MPQ - - string MapMPQFileName = m_GHost->m_MapPath + m_MapLocalPath; +/* + QString MapMPQFileName = m_GHost->m_MapPath + m_MapLocalPath; HANDLE MapMPQ; bool MapMPQReady = false; - if( SFileOpenArchive( MapMPQFileName.c_str( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &MapMPQ ) ) + if( SFileOpenArchive( MapMPQFileName.toStdString().c_str(), 0, MPQ_OPEN_FORCE_MPQ_V1, &MapMPQ ) ) { CONSOLE_Print( "[MAP] loading MPQ file [" + MapMPQFileName + "]" ); MapMPQReady = true; @@ -278,41 +278,41 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) // try to calculate map_size, map_info, map_crc, map_sha1 - BYTEARRAY MapSize; - BYTEARRAY MapInfo; - BYTEARRAY MapCRC; - BYTEARRAY MapSHA1; + QByteArray MapSize; + QByteArray MapInfo; + QByteArray MapCRC; + QByteArray MapSHA1; - if( !m_MapData.empty( ) ) + if( !m_MapData.isEmpty( ) ) { m_GHost->m_SHA->Reset( ); // calculate map_size - MapSize = UTIL_CreateByteArray( (uint32_t)m_MapData.size( ), false ); - CONSOLE_Print( "[MAP] calculated map_size = " + UTIL_ByteArrayToDecString( MapSize ) ); + MapSize = Util::fromUInt32(m_MapData.size( )); + CONSOLE_Print( "[MAP] calculated map_size = " + UTIL_QByteArrayToDecString( MapSize ) ); // calculate map_info (this is actually the CRC) - MapInfo = UTIL_CreateByteArray( (uint32_t)m_GHost->m_CRC->FullCRC( (unsigned char *)m_MapData.c_str( ), m_MapData.size( ) ), false ); - CONSOLE_Print( "[MAP] calculated map_info = " + UTIL_ByteArrayToDecString( MapInfo ) ); + MapInfo = Util::fromUInt32(m_GHost->m_CRC->FullCRC( m_MapData )); + CONSOLE_Print( "[MAP] calculated map_info = " + UTIL_QByteArrayToDecString( MapInfo ) ); // calculate map_crc (this is not the CRC) and map_sha1 // a big thank you to Strilanc for figuring the map_crc algorithm out - string CommonJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "common.j" ); + QString CommonJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "common.j" ); - if( CommonJ.empty( ) ) + if( CommonJ.isEmpty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "common.j]" ); else { - string BlizzardJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "blizzard.j" ); + QString BlizzardJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "blizzard.j" ); - if( BlizzardJ.empty( ) ) + if( BlizzardJ.isEmpty( ) ) CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "blizzard.j]" ); else { - uint32_t Val = 0; + quint32 Val = 0; // update: it's possible for maps to include their own copies of common.j and/or blizzard.j // this code now overrides the default copies if required @@ -328,7 +328,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( SFileOpenFileEx( MapMPQ, "Scripts\\common.j", 0, &SubFile ) ) { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { @@ -352,8 +352,8 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( !OverrodeCommonJ ) { - Val = Val ^ XORRotateLeft( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); - m_GHost->m_SHA->Update( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) ); + Val = Val ^ XORRotateLeft( (unsigned char *)CommonJ.toStdString().c_str( ), CommonJ.size( ) ); + m_GHost->m_SHA->Update( (unsigned char *)CommonJ.toStdString().c_str( ), CommonJ.size( ) ); } if( MapMPQReady ) @@ -364,7 +364,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( SFileOpenFileEx( MapMPQ, "Scripts\\blizzard.j", 0, &SubFile ) ) { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { @@ -388,8 +388,8 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( !OverrodeBlizzardJ ) { - Val = Val ^ XORRotateLeft( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); - m_GHost->m_SHA->Update( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) ); + Val = Val ^ XORRotateLeft( (unsigned char *)BlizzardJ.toStdString().c_str( ), BlizzardJ.size( ) ); + m_GHost->m_SHA->Update( (unsigned char *)BlizzardJ.toStdString().c_str( ), BlizzardJ.size( ) ); } Val = ROTL( Val, 3 ); @@ -398,7 +398,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( MapMPQReady ) { - vector FileList; + QList FileList; FileList.push_back( "war3map.j" ); FileList.push_back( "scripts\\war3map.j" ); FileList.push_back( "war3map.w3e" ); @@ -411,7 +411,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) FileList.push_back( "war3map.w3q" ); bool FoundScript = false; - for( vector :: iterator i = FileList.begin( ); i != FileList.end( ); i++ ) + for( QList :: const_iterator i = FileList.begin( ); i != FileList.end( ); i++ ) { // don't use scripts\war3map.j if we've already used war3map.j (yes, some maps have both but only war3map.j is used) @@ -420,9 +420,9 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) HANDLE SubFile; - if( SFileOpenFileEx( MapMPQ, (*i).c_str( ), 0, &SubFile ) ) + if( SFileOpenFileEx( MapMPQ, (*i).toStdString().c_str( ), 0, &SubFile ) ) { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { @@ -453,15 +453,15 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( !FoundScript ) CONSOLE_Print( "[MAP] couldn't find war3map.j or scripts\\war3map.j in MPQ file, calculated map_crc/sha1 is probably wrong" ); - MapCRC = UTIL_CreateByteArray( Val, false ); - CONSOLE_Print( "[MAP] calculated map_crc = " + UTIL_ByteArrayToDecString( MapCRC ) ); + MapCRC = Util::fromUInt32( Val ); + CONSOLE_Print( "[MAP] calculated map_crc = " + UTIL_QByteArrayToDecString( MapCRC ) ); m_GHost->m_SHA->Final( ); unsigned char SHA1[20]; memset( SHA1, 0, sizeof( unsigned char ) * 20 ); m_GHost->m_SHA->GetHash( SHA1 ); - MapSHA1 = UTIL_CreateByteArray( SHA1, 20 ); - CONSOLE_Print( "[MAP] calculated map_sha1 = " + UTIL_ByteArrayToDecString( MapSHA1 ) ); + MapSHA1 = QByteArray( (char*) SHA1, 20 ); + CONSOLE_Print( "[MAP] calculated map_sha1 = " + UTIL_QByteArrayToDecString( MapSHA1 ) ); } else CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - map MPQ file not loaded" ); @@ -473,14 +473,14 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) // try to calculate map_width, map_height, map_slot, map_numplayers, map_numteams - uint32_t MapOptions = 0; - BYTEARRAY MapWidth; - BYTEARRAY MapHeight; - uint32_t MapNumPlayers = 0; - uint32_t MapNumTeams = 0; - vector Slots; + quint32 MapOptions = 0; + QByteArray MapWidth; + QByteArray MapHeight; + quint32 MapNumPlayers = 0; + quint32 MapNumTeams = 0; + QList Slots; - if( !m_MapData.empty( ) ) + if( !m_MapData.isEmpty( ) ) { if( MapMPQReady ) { @@ -488,7 +488,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( SFileOpenFileEx( MapMPQ, "war3map.w3i", 0, &SubFile ) ) { - uint32_t FileLength = SFileGetFileSize( SubFile, NULL ); + quint32 FileLength = SFileGetFileSize( SubFile, NULL ); if( FileLength > 0 && FileLength != 0xFFFFFFFF ) { @@ -502,12 +502,12 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) // war3map.w3i format found at http://www.wc3campaigns.net/tools/specs/index.html by Zepir/PitzerMike string GarbageString; - uint32_t FileFormat; - uint32_t RawMapWidth; - uint32_t RawMapHeight; - uint32_t RawMapFlags; - uint32_t RawMapNumPlayers; - uint32_t RawMapNumTeams; + quint32 FileFormat; + quint32 RawMapWidth; + quint32 RawMapHeight; + quint32 RawMapFlags; + quint32 RawMapNumPlayers; + quint32 RawMapNumTeams; ISS.read( (char *)&FileFormat, 4 ); // file format (18 = ROC, 25 = TFT) @@ -570,14 +570,14 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) } ISS.read( (char *)&RawMapNumPlayers, 4 ); // number of players - uint32_t ClosedSlots = 0; + quint32 ClosedSlots = 0; - for( uint32_t i = 0; i < RawMapNumPlayers; i++ ) + for( quint32 i = 0; i < RawMapNumPlayers; i++ ) { CGameSlot Slot( 0, 255, SLOTSTATUS_OPEN, 0, 0, 1, SLOTRACE_RANDOM ); - uint32_t Colour; - uint32_t Status; - uint32_t Race; + quint32 Colour; + quint32 Status; + quint32 Race; ISS.read( (char *)&Colour, 4 ); // colour Slot.SetColour( Colour ); @@ -623,10 +623,10 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) ISS.read( (char *)&RawMapNumTeams, 4 ); // number of teams - for( uint32_t i = 0; i < RawMapNumTeams; i++ ) + for( quint32 i = 0; i < RawMapNumTeams; i++ ) { - uint32_t Flags; - uint32_t PlayerMask; + quint32 Flags; + quint32 PlayerMask; ISS.read( (char *)&Flags, 4 ); // flags ISS.read( (char *)&PlayerMask, 4 ); // player mask @@ -635,7 +635,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) { if( PlayerMask & 1 ) { - for( vector :: iterator k = Slots.begin( ); k != Slots.end( ); k++ ) + for( QList :: iterator k = Slots.begin( ); k != Slots.end( ); k++ ) { if( (*k).GetColour( ) == j ) (*k).SetTeam( i ); @@ -652,21 +652,21 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) // let's not confuse the user by displaying erroneous map options so zero them out now MapOptions = RawMapFlags & ( MAPOPT_MELEE | MAPOPT_FIXEDPLAYERSETTINGS | MAPOPT_CUSTOMFORCES ); - CONSOLE_Print( "[MAP] calculated map_options = " + UTIL_ToString( MapOptions ) ); - MapWidth = UTIL_CreateByteArray( (uint16_t)RawMapWidth, false ); - CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_ByteArrayToDecString( MapWidth ) ); - MapHeight = UTIL_CreateByteArray( (uint16_t)RawMapHeight, false ); - CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_ByteArrayToDecString( MapHeight ) ); + CONSOLE_Print( "[MAP] calculated map_options = " + QString::number( MapOptions ) ); + MapWidth = Util::fromUInt16(RawMapWidth); + CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_QByteArrayToDecString( MapWidth ) ); + MapHeight = Util::fromUInt16(RawMapHeight); + CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_QByteArrayToDecString( MapHeight ) ); MapNumPlayers = RawMapNumPlayers - ClosedSlots; - CONSOLE_Print( "[MAP] calculated map_numplayers = " + UTIL_ToString( MapNumPlayers ) ); + CONSOLE_Print( "[MAP] calculated map_numplayers = " + QString::number( MapNumPlayers ) ); MapNumTeams = RawMapNumTeams; - CONSOLE_Print( "[MAP] calculated map_numteams = " + UTIL_ToString( MapNumTeams ) ); + CONSOLE_Print( "[MAP] calculated map_numteams = " + QString::number( MapNumTeams ) ); - uint32_t SlotNum = 1; + quint32 SlotNum = 1; - for( vector :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) + for( QList :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { - CONSOLE_Print( "[MAP] calculated map_slot" + UTIL_ToString( SlotNum ) + " = " + UTIL_ByteArrayToDecString( (*i).GetByteArray( ) ) ); + CONSOLE_Print( "[MAP] calculated map_slot" + QString::number( SlotNum ) + " = " + UTIL_QByteArrayToDecString( (*i).GetQByteArray( ) ) ); SlotNum++; } @@ -678,7 +678,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) unsigned char Team = 0; - for( vector :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) + for( QList :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) { (*i).SetTeam( Team++ ); (*i).SetRace( SLOTRACE_RANDOM ); @@ -689,7 +689,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) { // make races selectable - for( vector :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) + for( QList :: iterator i = Slots.begin( ); i != Slots.end( ); i++ ) (*i).SetRace( (*i).GetRace( ) | SLOTRACE_SELECTABLE ); } } @@ -716,44 +716,44 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( MapMPQReady ) SFileCloseArchive( MapMPQ ); - m_MapPath = CFG->GetString( "map_path", string( ) ); + m_MapPath = CFG->GetString( "map_path", QString( ) ); - if( MapSize.empty( ) ) - MapSize = UTIL_ExtractNumbers( CFG->GetString( "map_size", string( ) ), 4 ); + if( MapSize.isEmpty( ) ) + MapSize = UTIL_ExtractNumbers( CFG->GetString( "map_size", QString( ) ), 4 ); else if( CFG->Exists( "map_size" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_size with config value map_size = " + CFG->GetString( "map_size", string( ) ) ); - MapSize = UTIL_ExtractNumbers( CFG->GetString( "map_size", string( ) ), 4 ); + CONSOLE_Print( "[MAP] overriding calculated map_size with config value map_size = " + CFG->GetString( "map_size", QString( ) ) ); + MapSize = UTIL_ExtractNumbers( CFG->GetString( "map_size", QString( ) ), 4 ); } m_MapSize = MapSize; - if( MapInfo.empty( ) ) - MapInfo = UTIL_ExtractNumbers( CFG->GetString( "map_info", string( ) ), 4 ); + if( MapInfo.isEmpty( ) ) + MapInfo = UTIL_ExtractNumbers( CFG->GetString( "map_info", QString( ) ), 4 ); else if( CFG->Exists( "map_info" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_info with config value map_info = " + CFG->GetString( "map_info", string( ) ) ); - MapInfo = UTIL_ExtractNumbers( CFG->GetString( "map_info", string( ) ), 4 ); + CONSOLE_Print( "[MAP] overriding calculated map_info with config value map_info = " + CFG->GetString( "map_info", QString( ) ) ); + MapInfo = UTIL_ExtractNumbers( CFG->GetString( "map_info", QString( ) ), 4 ); } m_MapInfo = MapInfo; - if( MapCRC.empty( ) ) - MapCRC = UTIL_ExtractNumbers( CFG->GetString( "map_crc", string( ) ), 4 ); + if( MapCRC.isEmpty( ) ) + MapCRC = UTIL_ExtractNumbers( CFG->GetString( "map_crc", QString( ) ), 4 ); else if( CFG->Exists( "map_crc" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_crc with config value map_crc = " + CFG->GetString( "map_crc", string( ) ) ); - MapCRC = UTIL_ExtractNumbers( CFG->GetString( "map_crc", string( ) ), 4 ); + CONSOLE_Print( "[MAP] overriding calculated map_crc with config value map_crc = " + CFG->GetString( "map_crc", QString( ) ) ); + MapCRC = UTIL_ExtractNumbers( CFG->GetString( "map_crc", QString( ) ), 4 ); } m_MapCRC = MapCRC; - if( MapSHA1.empty( ) ) - MapSHA1 = UTIL_ExtractNumbers( CFG->GetString( "map_sha1", string( ) ), 20 ); + if( MapSHA1.isEmpty( ) ) + MapSHA1 = UTIL_ExtractNumbers( CFG->GetString( "map_sha1", QString( ) ), 20 ); else if( CFG->Exists( "map_sha1" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_sha1 with config value map_sha1 = " + CFG->GetString( "map_sha1", string( ) ) ); - MapSHA1 = UTIL_ExtractNumbers( CFG->GetString( "map_sha1", string( ) ), 20 ); + CONSOLE_Print( "[MAP] overriding calculated map_sha1 with config value map_sha1 = " + CFG->GetString( "map_sha1", QString( ) ) ); + MapSHA1 = UTIL_ExtractNumbers( CFG->GetString( "map_sha1", QString( ) ), 20 ); } m_MapSHA1 = MapSHA1; @@ -772,35 +772,35 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) MapOptions = CFG->GetInt( "map_options", 0 ); else if( CFG->Exists( "map_options" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_options with config value map_options = " + CFG->GetString( "map_options", string( ) ) ); + CONSOLE_Print( "[MAP] overriding calculated map_options with config value map_options = " + CFG->GetString( "map_options", QString( ) ) ); MapOptions = CFG->GetInt( "map_options", 0 ); } m_MapOptions = MapOptions; - if( MapWidth.empty( ) ) - MapWidth = UTIL_ExtractNumbers( CFG->GetString( "map_width", string( ) ), 2 ); + if( MapWidth.isEmpty( ) ) + MapWidth = UTIL_ExtractNumbers( CFG->GetString( "map_width", QString( ) ), 2 ); else if( CFG->Exists( "map_width" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_width with config value map_width = " + CFG->GetString( "map_width", string( ) ) ); - MapWidth = UTIL_ExtractNumbers( CFG->GetString( "map_width", string( ) ), 2 ); + CONSOLE_Print( "[MAP] overriding calculated map_width with config value map_width = " + CFG->GetString( "map_width", QString( ) ) ); + MapWidth = UTIL_ExtractNumbers( CFG->GetString( "map_width", QString( ) ), 2 ); } m_MapWidth = MapWidth; - if( MapHeight.empty( ) ) - MapHeight = UTIL_ExtractNumbers( CFG->GetString( "map_height", string( ) ), 2 ); + if( MapHeight.isEmpty( ) ) + MapHeight = UTIL_ExtractNumbers( CFG->GetString( "map_height", QString( ) ), 2 ); else if( CFG->Exists( "map_height" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_height with config value map_height = " + CFG->GetString( "map_height", string( ) ) ); - MapHeight = UTIL_ExtractNumbers( CFG->GetString( "map_height", string( ) ), 2 ); + CONSOLE_Print( "[MAP] overriding calculated map_height with config value map_height = " + CFG->GetString( "map_height", QString( ) ) ); + MapHeight = UTIL_ExtractNumbers( CFG->GetString( "map_height", QString( ) ), 2 ); } m_MapHeight = MapHeight; - m_MapType = CFG->GetString( "map_type", string( ) ); - m_MapMatchMakingCategory = CFG->GetString( "map_matchmakingcategory", string( ) ); - m_MapStatsW3MMDCategory = CFG->GetString( "map_statsw3mmdcategory", string( ) ); - m_MapDefaultHCL = CFG->GetString( "map_defaulthcl", string( ) ); + m_MapType = CFG->GetString( "map_type", QString( ) ); + m_MapMatchMakingCategory = CFG->GetString( "map_matchmakingcategory", QString( ) ); + m_MapStatsW3MMDCategory = CFG->GetString( "map_statsw3mmdcategory", QString( ) ); + m_MapDefaultHCL = CFG->GetString( "map_defaulthcl", QString( ) ); m_MapDefaultPlayerScore = CFG->GetInt( "map_defaultplayerscore", 1000 ); m_MapLoadInGame = CFG->GetInt( "map_loadingame", 0 ) == 0 ? false : true; @@ -808,7 +808,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) MapNumPlayers = CFG->GetInt( "map_numplayers", 0 ); else if( CFG->Exists( "map_numplayers" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_numplayers with config value map_numplayers = " + CFG->GetString( "map_numplayers", string( ) ) ); + CONSOLE_Print( "[MAP] overriding calculated map_numplayers with config value map_numplayers = " + CFG->GetString( "map_numplayers", QString( ) ) ); MapNumPlayers = CFG->GetInt( "map_numplayers", 0 ); } @@ -818,22 +818,22 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) MapNumTeams = CFG->GetInt( "map_numteams", 0 ); else if( CFG->Exists( "map_numteams" ) ) { - CONSOLE_Print( "[MAP] overriding calculated map_numteams with config value map_numteams = " + CFG->GetString( "map_numteams", string( ) ) ); + CONSOLE_Print( "[MAP] overriding calculated map_numteams with config value map_numteams = " + CFG->GetString( "map_numteams", QString( ) ) ); MapNumTeams = CFG->GetInt( "map_numteams", 0 ); } m_MapNumTeams = MapNumTeams; - if( Slots.empty( ) ) + if( Slots.isEmpty( ) ) { - for( uint32_t Slot = 1; Slot <= 12; Slot++ ) + for( quint32 Slot = 1; Slot <= 12; Slot++ ) { - string SlotString = CFG->GetString( "map_slot" + UTIL_ToString( Slot ), string( ) ); + QString SlotString = CFG->GetString( "map_slot" + QString::number( Slot ), QString( ) ); - if( SlotString.empty( ) ) + if( SlotString.isEmpty( ) ) break; - BYTEARRAY SlotData = UTIL_ExtractNumbers( SlotString, 9 ); + QByteArray SlotData = UTIL_ExtractNumbers( SlotString, 9 ); Slots.push_back( CGameSlot( SlotData ) ); } } @@ -842,14 +842,14 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) CONSOLE_Print( "[MAP] overriding slots" ); Slots.clear( ); - for( uint32_t Slot = 1; Slot <= 12; Slot++ ) + for( quint32 Slot = 1; Slot <= 12; Slot++ ) { - string SlotString = CFG->GetString( "map_slot" + UTIL_ToString( Slot ), string( ) ); + QString SlotString = CFG->GetString( "map_slot" + QString::number( Slot ), QString( ) ); - if( SlotString.empty( ) ) + if( SlotString.isEmpty( ) ) break; - BYTEARRAY SlotData = UTIL_ExtractNumbers( SlotString, 9 ); + QByteArray SlotData = UTIL_ExtractNumbers( SlotString, 9 ); Slots.push_back( CGameSlot( SlotData ) ); } } @@ -862,7 +862,7 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) { CONSOLE_Print( "[MAP] forcing races to random" ); - for( vector :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) + for( QList :: iterator i = m_Slots.begin( ); i != m_Slots.end( ); i++ ) (*i).SetRace( SLOTRACE_RANDOM ); } @@ -870,11 +870,11 @@ void CMap :: Load( CConfig *CFG, string nCFGFile ) if( m_MapObservers == MAPOBS_ALLOWED || m_MapObservers == MAPOBS_REFEREES ) { - CONSOLE_Print( "[MAP] adding " + UTIL_ToString( 12 - m_Slots.size( ) ) + " observer slots" ); + CONSOLE_Print( "[MAP] adding " + QString::number( 12 - m_Slots.size( ) ) + " observer slots" ); while( m_Slots.size( ) < 12 ) m_Slots.push_back( CGameSlot( 0, 255, SLOTSTATUS_OPEN, 0, 12, 12, SLOTRACE_RANDOM ) ); - } + }*/ CheckValid( ); } @@ -883,7 +883,7 @@ void CMap :: CheckValid( ) { // todotodo: should this code fix any errors it sees rather than just warning the user? - if( m_MapPath.empty( ) ) + if( m_MapPath.isEmpty( ) ) { m_Valid = false; CONSOLE_Print( "[MAP] invalid map_path detected" ); @@ -891,7 +891,7 @@ void CMap :: CheckValid( ) else if( m_MapPath[0] == '\\' ) CONSOLE_Print( "[MAP] warning - map_path starts with '\\', any replays saved by GHost++ will not be playable in Warcraft III" ); - if( m_MapPath.find( '/' ) != string :: npos ) + if( m_MapPath.indexOf( '/' ) != -1 ) CONSOLE_Print( "[MAP] warning - map_path contains forward slashes '/' but it must use Windows style back slashes '\\'" ); if( m_MapSize.size( ) != 4 ) @@ -899,10 +899,10 @@ void CMap :: CheckValid( ) m_Valid = false; CONSOLE_Print( "[MAP] invalid map_size detected" ); } - else if( !m_MapData.empty( ) && m_MapData.size( ) != UTIL_ByteArrayToUInt32( m_MapSize, false ) ) + else if( !m_MapData.isEmpty( ) && (unsigned int)m_MapData.size( ) != Util::extractUInt32(m_MapSize) ) { m_Valid = false; - CONSOLE_Print( "[MAP] invalid map_size detected - size mismatch with actual map data" ); + CONSOLE_Print( "[MAP] invalid map_size detected - size mismatch with actual map data "); } if( m_MapInfo.size( ) != 4 ) @@ -968,25 +968,25 @@ void CMap :: CheckValid( ) CONSOLE_Print( "[MAP] invalid map_numteams detected" ); } - if( m_Slots.empty( ) || m_Slots.size( ) > 12 ) + if( m_Slots.isEmpty( ) || m_Slots.size( ) > 12 ) { m_Valid = false; CONSOLE_Print( "[MAP] invalid map_slot detected" ); } } -uint32_t CMap :: XORRotateLeft( unsigned char *data, uint32_t length ) +quint32 CMap :: XORRotateLeft( unsigned char *data, quint32 length ) { // a big thank you to Strilanc for figuring this out - uint32_t i = 0; - uint32_t Val = 0; + quint32 i = 0; + quint32 Val = 0; if( length > 3 ) { while( i < length - 3 ) { - Val = ROTL( Val ^ ( (uint32_t)data[i] + (uint32_t)( data[i + 1] << 8 ) + (uint32_t)( data[i + 2] << 16 ) + (uint32_t)( data[i + 3] << 24 ) ), 3 ); + Val = ROTL( Val ^ ( (quint32)data[i] + (quint32)( data[i + 1] << 8 ) + (quint32)( data[i + 2] << 16 ) + (quint32)( data[i + 3] << 24 ) ), 3 ); i += 4; } } diff --git a/src/libghost/map.h b/src/libghost/map.h new file mode 100644 index 0000000..a048c89 --- /dev/null +++ b/src/libghost/map.h @@ -0,0 +1,167 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef MAP_H +#define MAP_H + +#define MAPSPEED_SLOW 1 +#define MAPSPEED_NORMAL 2 +#define MAPSPEED_FAST 3 + +#define MAPVIS_HIDETERRAIN 1 +#define MAPVIS_EXPLORED 2 +#define MAPVIS_ALWAYSVISIBLE 3 +#define MAPVIS_DEFAULT 4 + +#define MAPOBS_NONE 1 +#define MAPOBS_ONDEFEAT 2 +#define MAPOBS_ALLOWED 3 +#define MAPOBS_REFEREES 4 + +#define MAPFLAG_TEAMSTOGETHER 1 +#define MAPFLAG_FIXEDTEAMS 2 +#define MAPFLAG_UNITSHARE 4 +#define MAPFLAG_RANDOMHERO 8 +#define MAPFLAG_RANDOMRACES 16 + +#define MAPOPT_HIDEMINIMAP 1 << 0 +#define MAPOPT_MODIFYALLYPRIORITIES 1 << 1 +#define MAPOPT_MELEE 1 << 2 // the bot cares about this one... +#define MAPOPT_REVEALTERRAIN 1 << 4 +#define MAPOPT_FIXEDPLAYERSETTINGS 1 << 5 // and this one... +#define MAPOPT_CUSTOMFORCES 1 << 6 // and this one, the rest don't affect the bot's logic +#define MAPOPT_CUSTOMTECHTREE 1 << 7 +#define MAPOPT_CUSTOMABILITIES 1 << 8 +#define MAPOPT_CUSTOMUPGRADES 1 << 9 +#define MAPOPT_WATERWAVESONCLIFFSHORES 1 << 11 +#define MAPOPT_WATERWAVESONSLOPESHORES 1 << 12 + +#define MAPFILTER_MAKER_USER 1 +#define MAPFILTER_MAKER_BLIZZARD 2 + +#define MAPFILTER_TYPE_MELEE 1 +#define MAPFILTER_TYPE_SCENARIO 2 + +#define MAPFILTER_SIZE_SMALL 1 +#define MAPFILTER_SIZE_MEDIUM 2 +#define MAPFILTER_SIZE_LARGE 4 + +#define MAPFILTER_OBS_FULL 1 +#define MAPFILTER_OBS_ONDEATH 2 +#define MAPFILTER_OBS_NONE 4 + +#define MAPGAMETYPE_UNKNOWN0 1 // always set except for saved games? +// AuthenticatedMakerBlizzard = 1 << 3 +// OfficialMeleeGame = 1 << 5 +#define MAPGAMETYPE_SAVEDGAME 1 << 9 +#define MAPGAMETYPE_PRIVATEGAME 1 << 11 +#define MAPGAMETYPE_MAKERUSER 1 << 13 +#define MAPGAMETYPE_MAKERBLIZZARD 1 << 14 +#define MAPGAMETYPE_TYPEMELEE 1 << 15 +#define MAPGAMETYPE_TYPESCENARIO 1 << 16 +#define MAPGAMETYPE_SIZESMALL 1 << 17 +#define MAPGAMETYPE_SIZEMEDIUM 1 << 18 +#define MAPGAMETYPE_SIZELARGE 1 << 19 +#define MAPGAMETYPE_OBSFULL 1 << 20 +#define MAPGAMETYPE_OBSONDEATH 1 << 21 +#define MAPGAMETYPE_OBSNONE 1 << 22 + +#include "gameslot.h" + +// +// CMap +// + +class CMap +{ +public: + CGHost *m_GHost; + +private: + bool m_Valid; + QString m_CFGFile; + QString m_MapPath; // config value: map path + QByteArray m_MapSize; // config value: map size (4 bytes) + QByteArray m_MapInfo; // config value: map info (4 bytes) -> this is the real CRC + QByteArray m_MapCRC; // config value: map crc (4 bytes) -> this is not the real CRC, it's the "xoro" value + QByteArray m_MapSHA1; // config value: map sha1 (20 bytes) + unsigned char m_MapSpeed; + unsigned char m_MapVisibility; + unsigned char m_MapObservers; + unsigned char m_MapFlags; + unsigned char m_MapFilterMaker; + unsigned char m_MapFilterType; + unsigned char m_MapFilterSize; + unsigned char m_MapFilterObs; + quint32 m_MapOptions; + QByteArray m_MapWidth; // config value: map width (2 bytes) + QByteArray m_MapHeight; // config value: map height (2 bytes) + QString m_MapType; // config value: map type (for stats class) + QString m_MapMatchMakingCategory; // config value: map matchmaking category (for matchmaking) + QString m_MapStatsW3MMDCategory; // config value: map stats w3mmd category (for saving w3mmd stats) + QString m_MapDefaultHCL; // config value: map default HCL to use (this should really be specified elsewhere and not part of the map config) + quint32 m_MapDefaultPlayerScore; // config value: map default player score (for matchmaking) + QString m_MapLocalPath; // config value: map local path + bool m_MapLoadInGame; + QByteArray m_MapData; // the map data itself, for sending the map to players + quint32 m_MapNumPlayers; + quint32 m_MapNumTeams; + QList m_Slots; + +public: + CMap( CGHost *nGHost ); + CMap( CGHost *nGHost, const CConfig &CFG, const QString &nCFGFile ); + ~CMap( ); + + bool GetValid( ) const { return m_Valid; } + const QString &GetCFGFile( ) const { return m_CFGFile; } + const QString &GetMapPath( ) const { return m_MapPath; } + const QByteArray &GetMapSize( ) const { return m_MapSize; } + const QByteArray &GetMapInfo( ) const { return m_MapInfo; } + const QByteArray &GetMapCRC( ) const { return m_MapCRC; } + const QByteArray &GetMapSHA1( ) const { return m_MapSHA1; } + unsigned char GetMapSpeed( ) const { return m_MapSpeed; } + unsigned char GetMapVisibility( ) const { return m_MapVisibility; } + unsigned char GetMapObservers( ) const { return m_MapObservers; } + unsigned char GetMapFlags( ) const { return m_MapFlags; } + QByteArray GetMapGameFlags( ) const; + quint32 GetMapGameType( ) const; + quint32 GetMapOptions( ) const { return m_MapOptions; } + unsigned char GetMapLayoutStyle( ) const; + const QByteArray &GetMapWidth( ) const { return m_MapWidth; } + const QByteArray &GetMapHeight( ) const { return m_MapHeight; } + const QString &GetMapType( ) const { return m_MapType; } + const QString &GetMapMatchMakingCategory( ) const { return m_MapMatchMakingCategory; } + const QString &GetMapStatsW3MMDCategory( ) const { return m_MapStatsW3MMDCategory; } + const QString &GetMapDefaultHCL( ) const { return m_MapDefaultHCL; } + quint32 GetMapDefaultPlayerScore( ) { return m_MapDefaultPlayerScore; } + const QString &GetMapLocalPath( ) const { return m_MapLocalPath; } + bool GetMapLoadInGame( ) const { return m_MapLoadInGame; } + const QByteArray &GetMapData( ) const { return m_MapData; } + quint32 GetMapNumPlayers( ) const { return m_MapNumPlayers; } + quint32 GetMapNumTeams( ) const { return m_MapNumTeams; } + const QList &GetSlots( ) const { return m_Slots; } + + void Load( const CConfig &CFG, const QString &nCFGFile ); + void CheckValid( ); + quint32 XORRotateLeft( unsigned char *data, quint32 length ); +}; + +#endif diff --git a/src/libghost/mpqarchive.cpp b/src/libghost/mpqarchive.cpp new file mode 100644 index 0000000..bc6880e --- /dev/null +++ b/src/libghost/mpqarchive.cpp @@ -0,0 +1,479 @@ +// rewritten using StormLib: +/*****************************************************************************/ +/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */ +/* */ +/* Author : Ladislav Zezula */ +/* E-mail : ladik@zezula.net */ +/* WWW : www.zezula.net */ +/*---------------------------------------------------------------------------*/ +/* Archive functions of Storm.dll */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/*****************************************************************************/ + +#include +#include "mpqarchive.h" +#include "mpqfile.h" +#include "includes.h" + +QByteArray m_ID; + + +bool MPQArchive::Header::readFrom(MPQArchive *parent) +{ + char buffer[32]; + if (parent->read(buffer, 32) != 32) + return false; +DEBUG_Print(QByteArray(buffer, 32).toHex()); + //<- 4b -> <- 4b -> <- 4b -> <- 4b -> <- 4b -> <- 4b -> <- 4b -> <- 4b -> + //4d50511a 20000000 98a46c00 00000f00 c8256c00 c8656c00 00040000 ed030000 + + m_ID = QByteArray(buffer, 4); + m_HeaderSize = qFromLittleEndian((unsigned char*)buffer + 4); + m_ArchiveSize = qFromLittleEndian((unsigned char*)buffer + 8); + m_FormatVersion = qFromLittleEndian((unsigned char*)buffer + 12); + m_BlockSize = qFromLittleEndian((unsigned char*)buffer + 14); + m_HashTablePos = qFromLittleEndian((unsigned char*)buffer + 16); + m_BlockTablePos = qFromLittleEndian((unsigned char*)buffer + 20); + m_HashTableSize = qFromLittleEndian((unsigned char*)buffer + 24); + m_BlockTableSize = qFromLittleEndian((unsigned char*)buffer + 28); + + return true; +} + +bool MPQArchive::Shunt::readFrom(MPQArchive *parent) +{ + char buffer[12]; + if (parent->read(buffer, 12) != 12) + return false; + + m_ID = QByteArray(buffer, 4); + m_HeaderPos = qFromLittleEndian((unsigned char*)buffer + 8); + + return true; +} + +bool MPQArchive::HashEntry::readFrom(MPQArchive *parent, quint32 &Seed1, quint32 &Seed2) +{ + char buffer[16]; + if (parent->read(buffer, 16) != 16) + return false; + + unsigned char buffer_out[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + for (int i = 0; i < 4; i++) + { + quint32 p = qFromLittleEndian((unsigned char*)buffer + i * 4); + Seed2 += parent->m_CryptBuffer[0x400 + (Seed1 & 0xFF)]; + quint32 ch = p ^ (Seed1 + Seed2); + + Seed1 = ((~Seed1 << 0x15) + 0x11111111) | (Seed1 >> 0x0B); + Seed2 = ch + Seed2 + (Seed2 << 5) + 3; + qToLittleEndian(ch, buffer_out + i * 4); + } + + m_Name1 = qFromLittleEndian(buffer_out + 0); + m_Name2 = qFromLittleEndian(buffer_out + 4); + m_Locale = qFromLittleEndian(buffer_out + 8); + m_Platform = qFromLittleEndian(buffer_out + 10); + m_BlockIndex = qFromLittleEndian(buffer_out + 12); + + return true; +} + +bool MPQArchive::BlockEntry::readFrom(MPQArchive *parent, quint32 &Seed1, quint32 &Seed2) +{ + m_Parent = parent; + char buffer[16]; + if (parent->read(buffer, 16) != 16) + return false; + + unsigned char buffer_out[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + for (int i = 0; i < 4; i++) + { + quint32 p = qFromLittleEndian((unsigned char*)buffer + i * 4); + Seed2 += parent->m_CryptBuffer[0x400 + (Seed1 & 0xFF)]; + quint32 ch = p ^ (Seed1 + Seed2); + + Seed1 = ((~Seed1 << 0x15) + 0x11111111) | (Seed1 >> 0x0B); + Seed2 = ch + Seed2 + (Seed2 << 5) + 3; + qToLittleEndian(ch, buffer_out + i * 4); + } + + m_FilePos = qFromLittleEndian(buffer_out + 0); + m_CSize = qFromLittleEndian(buffer_out + 4); + m_FSize = qFromLittleEndian(buffer_out + 8); + m_Flags = qFromLittleEndian(buffer_out + 12); + return true; +} + +bool MPQArchive::BlockEntry::encrypted() +{ + return (m_Flags & 0x00010000); +} + +bool MPQArchive::BlockEntry::fixSeed() +{ + return (m_Flags & 0x00020000); +} + +bool MPQArchive::BlockEntry::compressed() +{ + return (m_Flags & 0x0000FF00); +} + +bool MPQArchive::BlockEntry::exists() +{ + return (m_Flags & 0x80000000); +} + +bool MPQArchive::BlockEntry::singleUnit() +{ + return (m_Flags & 0x01000000); +} + +bool MPQArchive::BlockEntry::hasExtra() +{ + return (m_Flags & 0x04000000); +} + +bool MPQArchive::BlockEntry::usesImplode() +{ + return (m_Flags & 0x00000100); +} + +bool MPQArchive::BlockEntry::valid() +{ + return !(m_Flags & ~( 0x00000100 | 0x00000200 | 0x00010000 | 0x00020000 | 0x01000000 | 0x02000000 | 0x04000000 | 0x80000000 )); +} + +QByteArray MPQArchive::BlockEntry::readAll() +{ + //m_Parent->seek(m_FilePos + m_Parent->m_HeaderOffset); + //return m_Parent->read(m_CSize); + if (compressed()) + return "SINGLEUNIT"; + + return "-"; +} + +bool MPQArchive::FileNode::readFrom(MPQArchive *parent) +{ + char buffer[16]; + if (parent->read(buffer, 16) != 16) + return false; + + qint32 m_References; + QByteArray m_Filename; + int m_Size; + return true; +} + + +MPQArchive::MPQArchive(const QString &file) + : QFile(file) +{ + m_Error = NO_ERROR; + m_HashTable = NULL; + + m_FileList = NULL; + m_BlockTable = NULL; + m_HashTable = NULL; + m_ListFile = NULL; + + quint32 dwSeed = 0x00100001; + + // Initialize the decryption buffer. + for (int index1 = 0; index1 < 0x100; index1++) + { + for (int index2 = index1, i = 0; i < 5; i++, index2 += 0x100) + { + quint32 temp1, temp2; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp1 = (dwSeed & 0xFFFF) << 0x10; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp2 = (dwSeed & 0xFFFF); + + m_CryptBuffer[index2] = (temp1 | temp2); + } + } +} + +quint32 MPQArchive::getHash(const char *data, int offset) +{ + quint32 Seed1 = 0x7FED7FED; + quint32 Seed2 = 0xEEEEEEEE; + + while(*data != 0) + { + quint32 ch = toupper(*data++); + + Seed1 = m_CryptBuffer[offset + ch] ^ (Seed1 + Seed2); + Seed2 = ch + Seed1 + Seed2 + (Seed2 << 5) + 3; + } + + return Seed1; +} + +bool MPQArchive::open() +{ + if (!QFile::open(ReadOnly)) + { + m_Error = CANNOT_OPEN_FILE; + return false; + } + + m_HeaderOffset = 0; + + for(;;) + { + if (!m_Header.readFrom(this)) + { + m_Error = FILE_CORRUPT; + return false; + } + + // Special check : Some MPQs are actually AVI files, only with + // changed extension. + if (m_Header.m_ID == "FFIR" || + m_Header.m_ID == " IVA" || + m_Header.m_ID == "TSIL") + { + m_Error = FILE_IS_AVI; + return false; + } +/* +/ note: Ignore the MPQ shunt completely if the caller wants to open the MPQ as V1.0 + + // If there is the MPQ shunt signature, process it + if (m_Header.m_ID == "MPQ\x1B") + { + + //ha->ShuntPos = MpqPos; + + if (!m_CurrentShunt.readFrom(this)) + return false; + + // Set the MPQ pos and repeat the search + if (!seek(m_CurrentShunt.m_HeaderPos)) + return false; + + continue; + } +*/ + // There must be MPQ header signature + if (m_Header.m_ID != "MPQ\x1A") + { + m_HeaderOffset += 0x200; + if (!seek(m_HeaderOffset)) + { + m_Error = FILE_CORRUPT; + return false; + } + + continue; + } + + // If valid signature has been found, break the loop + if(m_Header.m_FormatVersion == 0) + break; + + m_Error = INVALID_HEADER; + return false; + } + + m_BlockSize = 0x200 << m_Header.m_BlockSize; + DEBUG_Print("Block size is " + QString::number(m_Header.m_BlockSize) + " bzw. " + QString::number(m_BlockSize)); + + // read hash table + if (m_Header.m_HashTableSize > 0) + { + m_HashTable = new HashEntry[m_Header.m_HashTableSize]; + seek(m_Header.m_HashTablePos + m_HeaderOffset); + + // Decrypt hash table on the fly + const char *key = "(HASH TABLE)"; + quint32 Seed1 = getHash(key, 0x300);//0x7FED7FED; + quint32 Seed2 = 0xEEEEEEEE; + + // Prepare seeds + /*for (uint i = 0; i < strlen(key); i++) + { + Seed1 = m_CryptBuffer[0x300 + key[i]] ^ (Seed1 + Seed2); + Seed2 = key[i] + Seed1 + Seed2 + (Seed2 << 5) + 3; + } + + Seed1 = getHash(key, 0x300); + Seed2 = 0xEEEEEEEE; + */ + + for (uint i = 0; i < m_Header.m_HashTableSize; i++) + if (!m_HashTable[i].readFrom(this, Seed1, Seed2)) + { + m_Error = FILE_CORRUPT; + return false; + } + + DEBUG_Print("Read "+ QString::number(m_Header.m_HashTableSize) + " hash entries"); + } + + // read block table + if (m_Header.m_BlockTableSize > 0) + { + m_BlockTable = new BlockEntry[m_Header.m_BlockTableSize]; + seek(m_Header.m_BlockTablePos + m_HeaderOffset); + + // Decrypt hash table on the fly + const char *key = "(BLOCK TABLE)"; + quint32 Seed1 = getHash(key, 0x300);//0x7FED7FED; + quint32 Seed2 = 0xEEEEEEEE; + + // Prepare seeds + /*for (uint i = 0; i < strlen(key); i++) + { + Seed1 = m_CryptBuffer[0x300 + key[i]] ^ (Seed1 + Seed2); + Seed2 = key[i] + Seed1 + Seed2 + (Seed2 << 5) + 3; + } + + Seed2 = 0xEEEEEEEE; + */ + + for (uint i = 0; i < m_Header.m_BlockTableSize; i++) + if (!m_BlockTable[i].readFrom(this, Seed1, Seed2)) + { + m_Error = FILE_CORRUPT; + return false; + } + + DEBUG_Print("Read "+ QString::number(m_Header.m_BlockTableSize) + " block entries"); + } + + // verify the block table + BlockEntry *pBlockEnd = m_BlockTable + m_Header.m_BlockTableSize + 1; + BlockEntry *pBlock = m_BlockTable; + + // we will check if all sizes in the block table is correct. + for(; pBlock < pBlockEnd; pBlock++) + if(pBlock->m_Flags & 0x80000000 /*MPQ_FILE_EXISTS*/ && pBlock->m_FilePos > size()) + { + m_Error = BLOCK_TABLE_CORRUPT; + return false; + } + + // Add the internal listfile + const char* listfilename = "(listfile)"; + HashEntry *pHash = GetHashEntry(listfilename); + + if (pHash == NULL || pHash->m_BlockIndex > m_Header.m_BlockTableSize) + { + m_Error = NO_FILE_LIST; + return false; + } + + // Get block and test if the file was not already deleted. + pBlock = m_BlockTable + pHash->m_BlockIndex; + + if (!pBlock->exists() || !pBlock->valid()) + { + m_Error = NO_FILE_LIST; + return false; + } + + DEBUG_Print("file list @block " + QString::number(pHash->m_BlockIndex)); + + m_ListFile = new MPQFile(this, listfilename, pBlock, pHash); + + // If the caller didn't specified otherwise, + // load the "(attributes)" file + // Ignore the result here. Attrobutes are not necessary, + // if they are not there, we will just ignore them +// SAttrFileLoad(ha); + + return true; +} + +MPQFile* MPQArchive::getFile(const QByteArray &filename) +{ + HashEntry *pHash = GetHashEntry(filename.data()); + + if (pHash == NULL || pHash->m_BlockIndex > m_Header.m_BlockTableSize) + { + m_Error = NO_FILE_LIST; + return false; + } + + // Get block and test if the file was not already deleted. + BlockEntry *pBlock = m_BlockTable + pHash->m_BlockIndex; + + if (!pBlock->exists() || !pBlock->valid()) + { + m_Error = NO_FILE_LIST; + return false; + } + + DEBUG_Print("file @block " + QString::number(pHash->m_BlockIndex)); + + return new MPQFile(this, filename.data(), pBlock, pHash); +} + +MPQArchive::~MPQArchive() +{ + delete[] m_CryptBuffer; + delete[] m_BlockTable; + delete[] m_HashTable; + delete[] m_FileList; + delete m_ListFile; +} + +MPQArchive::HashEntry *MPQArchive::GetHashEntry(const char * file, quint32 locale) +{ + HashEntry *pHashEnd = m_HashTable + m_Header.m_HashTableSize; + HashEntry *pHash0; // File hash entry (start) + HashEntry *pHash; // File hash entry (current) + HashEntry *pHashNeutral = NULL; + + // Decrypt name and block index + quint32 index = getHash(file) & (m_Header.m_HashTableSize - 1); + quint32 name1 = getHash(file, 0x100); + quint32 name2 = getHash(file, 0x200); + cout << file << " " << index << " " << m_Header.m_HashTableSize << " " << name2 << endl; + + pHash = pHash0 = m_HashTable + index; + + // Look for hash index + while(pHash->m_BlockIndex != 0xFFFFFFFF /*HASH_ENTRY_FREE*/) + { + if(pHash->m_Name1 == name1 && + pHash->m_Name2 == name2 && + pHash->m_BlockIndex != 0xFFFFFFFE /*HASH_ENTRY_DELETED*/) + { + if (locale == 0xFFFFFFFF) + return pHash; + + else + { + if (pHash->m_Locale == 0) + pHashNeutral = pHash; + + if (pHash->m_Locale == locale) + return pHash; + } + } + + // Move to the next hash entry + if(++pHash >= pHashEnd) + pHash = m_HashTable; + if(pHash == pHash0) + break; + } + + // File was not found + return pHashNeutral; +} + diff --git a/src/libghost/mpqarchive.h b/src/libghost/mpqarchive.h new file mode 100644 index 0000000..ae57263 --- /dev/null +++ b/src/libghost/mpqarchive.h @@ -0,0 +1,172 @@ +#ifndef MPQARCHIVE_H +#define MPQARCHIVE_H + +#include +class MPQFile; + +class MPQArchive : public QFile +{ + Q_OBJECT + +public: + MPQArchive(const QString & filename); + virtual ~MPQArchive(); + + bool open(); + MPQFile* getFile(const QByteArray &filename); + + enum Error + { + NO_ERROR, + FILE_CORRUPT, + INVALID_HEADER, + FILE_IS_AVI, + CANNOT_OPEN_FILE, + BLOCK_TABLE_CORRUPT, + NO_FILE_LIST, + } m_Error; + + class Header + { + public: + bool readFrom(MPQArchive* parent); + + // The ID_MPQ ('MPQ\x1A') signature + QByteArray m_ID; + + // Size of the archive header + quint32 m_HeaderSize; + + // Size of MPQ archive + // This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive + // is calculated as the size from the beginning of the archive to the end of the hash table, + // block table, or extended block table (whichever is largest). + quint32 m_ArchiveSize; + + // 0 = Original format + // 1 = Extended format (The Burning Crusade and newer) + quint16 m_FormatVersion; + + // Power of two exponent specifying the number of 512-byte disk sectors in each logical sector + // in the archive. The size of each logical sector in the archive is 512 * 2^SectorSizeShift. + // Bugs in the Storm library dictate that this should always be 3 (4096 byte sectors). + quint16 m_BlockSize; + + // Offset to the beginning of the hash table, relative to the beginning of the archive. + quint32 m_HashTablePos; + + // Offset to the beginning of the block table, relative to the beginning of the archive. + quint32 m_BlockTablePos; + + // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for + // the original MoPaQ format, or less than 2^20 for the Burning Crusade format. + quint32 m_HashTableSize; + + // Number of entries in the block table + quint32 m_BlockTableSize; + }; + + class Shunt + { + public: + bool readFrom(MPQArchive* parent); + + // The ID_MPQ_SHUNT ('MPQ\x1B') signature + QByteArray m_ID; + + // Position of the MPQ header, relative to the begin of the shunt + qint32 m_HeaderPos; + }; + + class FileNode + { + public: + bool readFrom(MPQArchive* parent); + + qint32 m_References; + QByteArray m_Filename; + int m_Size; + }; + + class HashEntry + { + public: + bool readFrom(MPQArchive* parent, quint32 &Seed1, quint32& Seed2); + + // The hash of the file path, using method A. + quint32 m_Name1; + + // The hash of the file path, using method B. + quint32 m_Name2; + + // The language of the file. This is a Windows LANGID data type, and uses the same values. + // 0 indicates the default language (American English), or that the file is language-neutral. + quint16 m_Locale; + + // The platform the file is used for. 0 indicates the default platform. + // No other values have been observed. + quint16 m_Platform; + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + quint32 m_BlockIndex; + }; + + class BlockEntry + { + public: + bool readFrom(MPQArchive* parent, quint32 &Seed1, quint32& Seed2); + + bool exists(); + bool valid(); + bool compressed(); + bool encrypted(); + bool fixSeed(); + bool singleUnit(); + bool hasExtra(); + bool usesImplode(); + + MPQArchive *m_Parent; + QByteArray readAll(); + + // Offset of the beginning of the block, relative to the beginning of the archive. + quint32 m_FilePos; + + // Compressed file size + quint32 m_CSize; + + // Only valid if the block is a file; otherwise meaningless, and should be 0. + // If the file is compressed, this is the size of the uncompressed file data. + quint32 m_FSize; + + // Flags for the file. See MPQ_FILE_XXXX constants + quint32 m_Flags; + }; + + int m_HeaderOffset; // offset where the header was found + int m_BlockSize; // Size of file block + quint32 getHash(const char *data, int offset = 0x000); + MPQFile *m_ListFile; + quint32 m_CryptBuffer[0x500]; + +private: + HashEntry *GetHashEntry(const char * file, quint32 locale = 0xFFFFFFFF); + + int m_ShuntPos; // MPQShunt offset (only valid if a shunt is present) + int m_HashTablePos; // Hash table offset (relative to the begin of the file) + int m_BlockTablePos; // Block table offset (relative to the begin of the file) + int m_ExtBlockTablePos; // Ext. block table offset (relative to the begin of the file) + int m_MpqSize; // Size of MPQ archive + + Header m_Header; // MPQ header + HashEntry *m_HashTable; + BlockEntry *m_BlockTable; + FileNode *m_FileList; + +}; + +#endif // MPGARCHIVE_H diff --git a/src/libghost/mpqfile.cpp b/src/libghost/mpqfile.cpp new file mode 100644 index 0000000..3c33bb2 --- /dev/null +++ b/src/libghost/mpqfile.cpp @@ -0,0 +1,239 @@ +#include "mpqfile.h" +#include "includes.h" +#include + +MPQFile::MPQFile(MPQArchive *archive, const QString &filename, MPQArchive::BlockEntry *block, MPQArchive::HashEntry *hash) +{ + m_Parent = archive; + m_BlockEntry = block; + m_HashEntry = hash; + m_Seed1 = 0; + m_Name = filename; + m_Size = block->m_FSize; + DEBUG_Print("Block size: " + QString::number(block->m_CSize)); + DEBUG_Print("File size: " + QString::number(block->m_FSize)); + m_Blocks = (block->m_FSize + archive->m_BlockSize - 1) / archive->m_BlockSize; + DEBUG_Print("Number of blocks: " + QString::number(m_Blocks)); + + m_PositionFromBegin = block->m_FilePos + archive->m_HeaderOffset; + m_PositionFromHeader = block->m_FilePos; + + if (block->compressed()) + { + } + + if (block->encrypted()) + { + QString name = filename.section('\\', -1); + + m_Seed1 = archive->getHash(name.toUtf8().data(), 0x300); + if (block->fixSeed()) + m_Seed1 = (m_Seed1 + block->m_FilePos) ^ block->m_FSize; + } +/* + // Resolve pointers to file's attributes + if(nError == ERROR_SUCCESS && ha->pAttributes != NULL) + { + if(ha->pAttributes->pCrc32 != NULL) + hf->pCrc32 = ha->pAttributes->pCrc32 + dwBlockIndex; + if(ha->pAttributes->pFileTime != NULL) + hf->pFileTime = ha->pAttributes->pFileTime + dwBlockIndex; + if(ha->pAttributes->pMd5 != NULL) + hf->pMd5 = ha->pAttributes->pMd5 + dwBlockIndex; + }*/ +} + +bool MPQFile::read() +{ + MPQArchive::BlockEntry *block = m_BlockEntry; + + if (block->compressed()) + { + m_BlockPosTableSize = m_Blocks + 1 + (block->hasExtra() ? 1 : 0); + m_BlockPosTable = new qint32[m_BlockPosTableSize]; + + m_Parent->seek(m_PositionFromBegin); + + char buffer[4]; + qint32 *pos = m_BlockPosTable, *posEnd = pos + m_BlockPosTableSize; + for (; pos != posEnd; pos++) + { + if (m_Parent->read(buffer, 4) != 4) + { + m_Error = POS_TABLE_CORRUPT; + return false; + } + + *pos = qFromLittleEndian((unsigned char*)buffer); + } + + // encryption check + qint32 bytes = m_BlockPosTableSize * 4; + if (m_BlockPosTable[0] != bytes) + m_BlockEntry->m_Flags |= 0x00010000; + + quint32 saveSeed1 = 0; + if (m_BlockEntry->encrypted()) + { + quint32 temp = (m_BlockPosTable[0] ^ bytes) - 0xEEEEEEEE; + + int i; + for(i = 0; i < 0x100; i++) // Try all 255 possibilities + { + quint32 seed1; + quint32 seed2 = 0xEEEEEEEE; + quint32 ch; + + // Try the first DWORD (We exactly know the value) + seed1 = temp - m_Parent->m_CryptBuffer[0x400 + i]; + seed2 += m_Parent->m_CryptBuffer[0x400 + (seed1 & 0xFF)]; + ch = m_BlockPosTable[0] ^ (seed1 + seed2); + + if(ch != (quint32)bytes) + continue; + + // Add 1 because we are decrypting block positions + saveSeed1 = seed1 + 1; + + // If OK, continue and test the second value. We don't know exactly the value, + // but we know that the second one has lower 16 bits set to zero + // (no compressed block is larger than 0xFFFF bytes) + seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B); + seed2 = ch + seed2 + (seed2 << 5) + 3; + + seed2 += m_Parent->m_CryptBuffer[0x400 + (seed1 & 0xFF)]; + ch = m_BlockPosTable[1] ^ (seed1 + seed2); + + if((ch & 0xFFFF0000) == 0) + break; + } + + if (i == 0x100) + { + m_Error = SEED_NOT_FOUND; + return false; + } + + decryptBlock((quint32*)m_BlockPosTable, m_BlockPosTableSize, saveSeed1 - 1); + } + + cout << m_BlockPosTableSize << ", " << m_BlockEntry->m_FilePos << ", " << m_BlockPosTable[0] << ", " << m_BlockPosTable[1] << endl; + + if (m_BlockPosTable[0] != bytes) + { + m_Error = DECRYPTION_FAILED; + return false; + } + + DEBUG_Print(QString::number(m_BlockPosTableSize) + " blockpos loaded"); + + for (int i = 0; i < m_Blocks - 1; i++) + readBlock(m_BlockPosTable[i + 1], m_BlockPosTable[i + 2], saveSeed1 + i); + + QFile out("test.out"); + if (out.open(QFile::WriteOnly | QFile::Truncate)) + { + out.write(m_Content); + out.close(); + } + + return true; + } + + DEBUG_Print("file not compressed"); + + + + return true; +} + +bool MPQFile::readBlock(quint32 from, quint32 to, quint32 seed) +{ + int len = to - from; + + if (len > m_Parent->m_BlockSize) + len = m_Parent->m_BlockSize; + + m_Parent->seek(m_PositionFromBegin + from); + QByteArray part; + + if (m_BlockEntry->encrypted()) + { + quint32 num = len >> 2; + + char buffer[4]; + quint32 data[num]; + + for (uint i = 0; i < num; i++) + { + if (m_Parent->read((char*)buffer, 4) != 4) + { + m_Error = FILE_CORRUPTED; + return false; + } + + data[i] = qFromLittleEndian((unsigned char*)buffer); + } + + decryptBlock(data, num, seed); + + for (uint i = 0; i < num; i++) + { + //qToLittleEndian(data[i], (unsigned char*)buffer); + //part.append(buffer, 4); + part.append((char*)&data[i], 4); + } + } + + else + { + QByteArray ba = m_Parent->read(len); + if (ba.size() != len) + { + m_Error = FILE_CORRUPTED; + return false; + } + + part.append(ba); + } + + if (m_BlockEntry->usesImplode()) + { + DEBUG_Print("Uses PKWARE"); + } + + m_Content.append(part); + + return true; +} + +void MPQFile::decryptBlock(quint32 *data, quint32 length, quint32 seed) +{ + quint32 seed2 = 0xEEEEEEEE; + quint32 ch; + + while(length-- > 0) + { + seed2 += m_Parent->m_CryptBuffer[0x400 + (seed & 0xFF)]; + ch = *data ^ (seed + seed2); + + seed = ((~seed << 0x15) + 0x11111111) | (seed >> 0x0B); + seed2 = ch + seed2 + (seed2 << 5) + 3; + *data++ = ch; + } +} + + + + + + + + + + + + + + + diff --git a/src/libghost/mpqfile.h b/src/libghost/mpqfile.h new file mode 100644 index 0000000..e55a860 --- /dev/null +++ b/src/libghost/mpqfile.h @@ -0,0 +1,56 @@ +#ifndef MPQFILE_H +#define MPQFILE_H + +#include "mpqarchive.h" + +class MPQFile +{ +public: + MPQFile(MPQArchive* archive, const QString &filename, MPQArchive::BlockEntry *block, MPQArchive::HashEntry *hash); + + enum Error + { + NO_ERROR, + POS_TABLE_CORRUPT, + SEED_NOT_FOUND, + DECRYPTION_FAILED, + FILE_CORRUPTED, + } m_Error; + + bool read(); + bool readBlock(quint32 from, quint32 to, quint32 seed); + void decryptBlock(quint32 *data, quint32 length, quint32 seed); + + MPQArchive* m_Parent; + MPQArchive::BlockEntry *m_BlockEntry; + MPQArchive::HashEntry *m_HashEntry; + + quint32 m_Seed1; + quint32 m_PositionFromBegin; + quint32 m_PositionFromHeader; + quint32 m_Size; + + int m_BlockPosTableSize; + qint32 *m_BlockPosTable; + + int m_Blocks; + + QByteArray m_Content; + + QString m_Name; + +/* DWORD * pdwBlockPos; // Position of each file block (only for compressed files) + DWORD nBlocks; // Number of blocks in the file (incl. the last incomplete one) + BOOL bBlockPosLoaded; // TRUE if block positions loaded + BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size) + + TMPQCRC32 * pCrc32; // Pointer to CRC32 (NULL if none) + TMPQFileTime * pFileTime; // Pointer to file's FILETIME (NULL if none) + TMPQMD5 * pMd5; // Pointer to file's MD5 (NULL if none) + + DWORD dwHashIndex; // Index to Hash table + DWORD dwBlockIndex; // Index to Block table + char szFileName[1]; // File name (variable length) */ +}; + +#endif // MPQFILE_H diff --git a/ghost/next_combination.h b/src/libghost/next_combination.h similarity index 68% rename from ghost/next_combination.h rename to src/libghost/next_combination.h index ba8b785..42ae347 100644 --- a/ghost/next_combination.h +++ b/src/libghost/next_combination.h @@ -7,34 +7,34 @@ #include template -void disjoint_rotate(Iterator begin1, Iterator end1, size_t size1, - Iterator begin2, Iterator end2, size_t size2, - Value *type) { +void disjoint_rotate(Iterator begin1, Iterator /*end1*/, size_t size1, + Iterator begin2, Iterator /*end2*/, size_t size2, + Value */*type*/) { const size_t total = size1 + size2; size_t gcd = total; for (size_t div = size1; div != 0; ) { - gcd %= div; - std::swap(gcd, div); + gcd %= div; + std::swap(gcd, div); } const size_t skip = total / gcd - 1; for (size_t i = 0; i < gcd; ++i) { - Iterator curr((i < size1) ? begin1 + i : begin2 + (i - size1)); - size_t ctr = i; - const Value v(*curr); - for (size_t j = 0; j < skip; ++j) { - ctr = (ctr + size1) % total; - Iterator next((ctr < size1) ? begin1 + ctr : begin2 + (ctr - size1)); - *curr = *next; - curr = next; - } - *curr = v; + Iterator curr((i < size1) ? begin1 + i : begin2 + (i - size1)); + size_t ctr = i; + const Value v(*curr); + for (size_t j = 0; j < skip; ++j) { + ctr = (ctr + size1) % total; + Iterator next((ctr < size1) ? begin1 + ctr : begin2 + (ctr - size1)); + *curr = *next; + curr = next; + } + *curr = v; } } template bool next_combination(Iterator begin, Iterator mid, Iterator end) { if (begin == mid || mid == end) { - return false; + return false; } // Starting from mid backwards, find first char that is // less than last char. Call it head_pos. This is the one @@ -45,27 +45,27 @@ bool next_combination(Iterator begin, Iterator mid, Iterator end) { --head_pos; size_t head_len = 1; while (head_pos != begin && !(*head_pos < *tail_pos)) { - --head_pos; - ++head_len; + --head_pos; + ++head_len; } if (head_pos == begin && !(*head_pos < *tail_pos)) { - // Last combination. We know that the smallest elements are - // in tail (in order) and largest elements are in head (also - // in order). rotate everything back into order and return false. - std::rotate(begin, mid, end); - return false; + // Last combination. We know that the smallest elements are + // in tail (in order) and largest elements are in head (also + // in order). rotate everything back into order and return false. + std::rotate(begin, mid, end); + return false; } // Now decrement tail_pos as long as it is larger than *head_pos. // This way we'll find the two positions to swap. size_t tail_len = 1; while (tail_pos > mid) { - --tail_pos; - ++tail_len; - if (!(*tail_pos > *head_pos)) { - ++tail_pos; - --tail_len; - break; - } + --tail_pos; + ++tail_len; + if (!(*tail_pos > *head_pos)) { + ++tail_pos; + --tail_len; + break; + } } // Now we have head_pos and tail_pos. Lets call // - 'h': the element at head_pos @@ -88,22 +88,22 @@ bool next_combination(Iterator begin, Iterator mid, Iterator end) { // Same is true if tail_len == 1 (T == ''). Proof: h H ; t -> t H ; h, // so this time H will stay in place and swap will suffice. if (head_len == 1 || tail_len == 1) { - std::iter_swap(head_pos, tail_pos); - return true; + std::iter_swap(head_pos, tail_pos); + return true; } // If head_len == tail_len, this operation reduces to a swap_ranges. // Proof: since len(H) == len(T), the swap is h H ; t T -> t T ; h H if (head_len == tail_len) { - std::swap_ranges(head_pos, mid, tail_pos); - return true; + std::swap_ranges(head_pos, mid, tail_pos); + return true; } // Finally we have to do the full reorder. Simply swap h and t, then // do what std::rotate would do with the sequence H T with the // constraint that the elements are not stored in consecutive locations. std::iter_swap(head_pos, tail_pos); disjoint_rotate(head_pos + 1, mid, head_len - 1, - tail_pos + 1, end, tail_len - 1, - &*head_pos); + tail_pos + 1, end, tail_len - 1, + &*head_pos); return true; } diff --git a/ghost/packed.cpp b/src/libghost/packed.cpp similarity index 70% rename from ghost/packed.cpp rename to src/libghost/packed.cpp index f0a9f6a..d27220f 100644 --- a/ghost/packed.cpp +++ b/src/libghost/packed.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -23,7 +23,7 @@ #include "crc32.h" #include "packed.h" -#include +#include // we can't use zlib's uncompress function because it expects a complete compressed buffer // however, we're going to be passing it chunks of incomplete data @@ -88,7 +88,7 @@ CPacked :: ~CPacked( ) delete m_CRC; } -void CPacked :: Load( string fileName, bool allBlocks ) +void CPacked :: Load( QString fileName, bool allBlocks ) { m_Valid = true; CONSOLE_Print( "[PACKED] loading data from file [" + fileName + "]" ); @@ -96,20 +96,20 @@ void CPacked :: Load( string fileName, bool allBlocks ) Decompress( allBlocks ); } -bool CPacked :: Save( bool TFT, string fileName ) +bool CPacked :: Save( bool TFT, QString fileName ) { Compress( TFT ); if( m_Valid ) { CONSOLE_Print( "[PACKED] saving data to file [" + fileName + "]" ); - return UTIL_FileWrite( fileName, (unsigned char *)m_Compressed.c_str( ), m_Compressed.size( ) ); + return UTIL_FileWrite( fileName, m_Compressed ); } else return false; } -bool CPacked :: Extract( string inFileName, string outFileName ) +bool CPacked :: Extract( QString inFileName, QString outFileName ) { m_Valid = true; CONSOLE_Print( "[PACKED] extracting data from file [" + inFileName + "] to file [" + outFileName + "]" ); @@ -117,12 +117,12 @@ bool CPacked :: Extract( string inFileName, string outFileName ) Decompress( true ); if( m_Valid ) - return UTIL_FileWrite( outFileName, (unsigned char *)m_Decompressed.c_str( ), m_Decompressed.size( ) ); + return UTIL_FileWrite( outFileName, m_Decompressed ); else return false; } -bool CPacked :: Pack( bool TFT, string inFileName, string outFileName ) +bool CPacked :: Pack( bool TFT, QString inFileName, QString outFileName ) { m_Valid = true; CONSOLE_Print( "[PACKET] packing data from file [" + inFileName + "] to file [" + outFileName + "]" ); @@ -130,20 +130,20 @@ bool CPacked :: Pack( bool TFT, string inFileName, string outFileName ) Compress( TFT ); if( m_Valid ) - return UTIL_FileWrite( outFileName, (unsigned char *)m_Compressed.c_str( ), m_Compressed.size( ) ); + return UTIL_FileWrite( outFileName, m_Compressed ); else return false; } -void CPacked :: Decompress( bool allBlocks ) +void CPacked :: Decompress( bool /*allBlocks*/ ) { - CONSOLE_Print( "[PACKED] decompressing data" ); + /*CONSOLE_Print( "[PACKED] decompressing data" ); // format found at http://www.thehelper.net/forums/showthread.php?t=42787 m_Decompressed.clear( ); istringstream ISS( m_Compressed ); - string GarbageString; + QString GarbageString; // read header @@ -196,10 +196,10 @@ void CPacked :: Decompress( bool allBlocks ) // read blocks - for( uint32_t i = 0; i < m_NumBlocks; i++ ) + for( quint32 i = 0; i < m_NumBlocks; i++ ) { - uint16_t BlockCompressed; - uint16_t BlockDecompressed; + quint16 BlockCompressed; + quint16 BlockDecompressed; // read block header @@ -253,7 +253,7 @@ void CPacked :: Decompress( bool allBlocks ) return; } - m_Decompressed += string( (char *)DecompressedData, BlockDecompressedLong ); + m_Decompressed += QString( (char *)DecompressedData, BlockDecompressedLong ); delete [] DecompressedData; delete [] CompressedData; @@ -278,7 +278,7 @@ void CPacked :: Decompress( bool allBlocks ) CONSOLE_Print( "[PACKED] discarding " + UTIL_ToString( m_Decompressed.size( ) - m_DecompressedSize ) + " bytes" ); m_Decompressed.erase( m_DecompressedSize ); - } + }*/ } void CPacked :: Compress( bool TFT ) @@ -292,10 +292,10 @@ void CPacked :: Compress( bool TFT ) // compress data into blocks of size 8192 bytes // use a buffer of size 8213 bytes because in the worst case zlib will grow the data 0.1% plus 12 bytes - uint32_t CompressedSize = 0; - string Padded = m_Decompressed; + quint32 CompressedSize = 0; + string Padded = QString(m_Decompressed).toStdString(); Padded.append( 8192 - ( Padded.size( ) % 8192 ), 0 ); - vector CompressedBlocks; + QList CompressedBlocks; string :: size_type Position = 0; unsigned char *CompressedData = new unsigned char[8213]; @@ -306,7 +306,7 @@ void CPacked :: Compress( bool TFT ) if( Result != Z_OK ) { - CONSOLE_Print( "[PACKED] compress error " + UTIL_ToString( Result ) ); + CONSOLE_Print( "[PACKED] compress error " + QString::number( Result ) ); delete [] CompressedData; m_Valid = false; return; @@ -321,16 +321,16 @@ void CPacked :: Compress( bool TFT ) // build header - uint32_t HeaderSize = 68; - uint32_t HeaderCompressedSize = HeaderSize + CompressedSize + CompressedBlocks.size( ) * 8; - uint32_t HeaderVersion = 1; - BYTEARRAY Header; - UTIL_AppendByteArray( Header, "Warcraft III recorded game\x01A" ); - UTIL_AppendByteArray( Header, HeaderSize, false ); - UTIL_AppendByteArray( Header, HeaderCompressedSize, false ); - UTIL_AppendByteArray( Header, HeaderVersion, false ); - UTIL_AppendByteArray( Header, (uint32_t)m_Decompressed.size( ), false ); - UTIL_AppendByteArray( Header, (uint32_t)CompressedBlocks.size( ), false ); + quint32 HeaderSize = 68; + quint32 HeaderCompressedSize = HeaderSize + CompressedSize + CompressedBlocks.size( ) * 8; + quint32 HeaderVersion = 1; + QByteArray Header; + Header.append("Warcraft III recorded game\x01A"); + Header.append(Util::fromUInt32(HeaderSize)); + Header.append(Util::fromUInt32(HeaderCompressedSize)); + Header.append(Util::fromUInt32(HeaderVersion)); + Header.append(Util::fromUInt32(m_Decompressed.size( ))); + Header.append(Util::fromUInt32(CompressedBlocks.size( ))); if( TFT ) { @@ -347,60 +347,57 @@ void CPacked :: Compress( bool TFT ) Header.push_back( 'W' ); } - UTIL_AppendByteArray( Header, m_War3Version, false ); - UTIL_AppendByteArray( Header, m_BuildNumber, false ); - UTIL_AppendByteArray( Header, m_Flags, false ); - UTIL_AppendByteArray( Header, m_ReplayLength, false ); + Header.append(Util::fromUInt32(m_War3Version)); + Header.append(Util::fromUInt16(m_BuildNumber)); + Header.append(Util::fromUInt16(m_Flags)); + Header.append(Util::fromUInt32(m_ReplayLength)); // append zero header CRC // the header CRC is calculated over the entire header with itself set to zero // we'll overwrite the zero header CRC after we calculate it - UTIL_AppendByteArray( Header, (uint32_t)0, false ); + Header.append(Util::fromUInt32(0)); // calculate header CRC - - string HeaderString = string( Header.begin( ), Header.end( ) ); - uint32_t CRC = m_CRC->FullCRC( (unsigned char *)HeaderString.c_str( ), HeaderString.size( ) ); + quint32 CRC = m_CRC->FullCRC( Header ); // overwrite the (currently zero) header CRC with the calculated CRC - Header.erase( Header.end( ) - 4, Header.end( ) ); - UTIL_AppendByteArray( Header, CRC, false ); + Header.remove(Header.size() - 4, 4); + Header.append(Util::fromUInt32(CRC)); // append header - m_Compressed += string( Header.begin( ), Header.end( ) ); + m_Compressed += Header; // append blocks - for( vector :: iterator i = CompressedBlocks.begin( ); i != CompressedBlocks.end( ); i++ ) + for( QList :: const_iterator i = CompressedBlocks.begin( ); i != CompressedBlocks.end( ); i++ ) { - BYTEARRAY BlockHeader; - UTIL_AppendByteArray( BlockHeader, (uint16_t)(*i).size( ), false ); - UTIL_AppendByteArray( BlockHeader, (uint16_t)8192, false ); + QByteArray BlockHeader; + BlockHeader.append(Util::fromUInt16((*i).size( ))); + BlockHeader.append(Util::fromUInt16(8192)); // append zero block header CRC - UTIL_AppendByteArray( BlockHeader, (uint32_t)0, false ); + BlockHeader.append(Util::fromUInt32(0)); // calculate block header CRC - string BlockHeaderString = string( BlockHeader.begin( ), BlockHeader.end( ) ); - uint32_t CRC1 = m_CRC->FullCRC( (unsigned char *)BlockHeaderString.c_str( ), BlockHeaderString.size( ) ); + quint32 CRC1 = m_CRC->FullCRC( BlockHeader ); CRC1 = CRC1 ^ ( CRC1 >> 16 ); - uint32_t CRC2 = m_CRC->FullCRC( (unsigned char *)(*i).c_str( ), (*i).size( ) ); + quint32 CRC2 = m_CRC->FullCRC( QString::fromStdString(*i).toUtf8() ); CRC2 = CRC2 ^ ( CRC2 >> 16 ); - uint32_t BlockCRC = ( CRC1 & 0xFFFF ) | ( CRC2 << 16 ); + quint32 BlockCRC = ( CRC1 & 0xFFFF ) | ( CRC2 << 16 ); // overwrite the block header CRC with the calculated CRC - BlockHeader.erase( BlockHeader.end( ) - 4, BlockHeader.end( ) ); - UTIL_AppendByteArray( BlockHeader, BlockCRC, false ); + BlockHeader.remove( BlockHeader.size() - 4, 4 ); + BlockHeader.append(Util::fromUInt32(BlockCRC)); // append block header and data - m_Compressed += string( BlockHeader.begin( ), BlockHeader.end( ) ); - m_Compressed += *i; + m_Compressed += BlockHeader; + m_Compressed += QString::fromStdString(*i); } } diff --git a/src/libghost/packed.h b/src/libghost/packed.h new file mode 100644 index 0000000..58bcede --- /dev/null +++ b/src/libghost/packed.h @@ -0,0 +1,79 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef PACKED_H +#define PACKED_H + +// +// CPacked +// + +class CCRC32; + +class CPacked +{ +public: + CCRC32 *m_CRC; + +protected: + bool m_Valid; + QByteArray m_Compressed; + QByteArray m_Decompressed; + quint32 m_HeaderSize; + quint32 m_CompressedSize; + quint32 m_HeaderVersion; + quint32 m_DecompressedSize; + quint32 m_NumBlocks; + quint32 m_War3Identifier; + quint32 m_War3Version; + quint16 m_BuildNumber; + quint16 m_Flags; + quint32 m_ReplayLength; + +public: + CPacked( ); + virtual ~CPacked( ); + + virtual bool GetValid( ) { return m_Valid; } + virtual quint32 GetHeaderSize( ) { return m_HeaderSize; } + virtual quint32 GetCompressedSize( ) { return m_CompressedSize; } + virtual quint32 GetHeaderVersion( ) { return m_HeaderVersion; } + virtual quint32 GetDecompressedSize( ) { return m_DecompressedSize; } + virtual quint32 GetNumBlocks( ) { return m_NumBlocks; } + virtual quint32 GetWar3Identifier( ) { return m_War3Identifier; } + virtual quint32 GetWar3Version( ) { return m_War3Version; } + virtual quint16 GetBuildNumber( ) { return m_BuildNumber; } + virtual quint16 GetFlags( ) { return m_Flags; } + virtual quint32 GetReplayLength( ) { return m_ReplayLength; } + + virtual void SetWar3Version( quint32 nWar3Version ) { m_War3Version = nWar3Version; } + virtual void SetBuildNumber( quint16 nBuildNumber ) { m_BuildNumber = nBuildNumber; } + virtual void SetFlags( quint16 nFlags ) { m_Flags = nFlags; } + virtual void SetReplayLength( quint32 nReplayLength ) { m_ReplayLength = nReplayLength; } + + virtual void Load( QString fileName, bool allBlocks ); + virtual bool Save( bool TFT, QString fileName ); + virtual bool Extract( QString inFileName, QString outFileName ); + virtual bool Pack( bool TFT, QString inFileName, QString outFileName ); + virtual void Decompress( bool allBlocks ); + virtual void Compress( bool TFT ); +}; + +#endif diff --git a/ghost/replay.cpp b/src/libghost/replay.cpp similarity index 64% rename from ghost/replay.cpp rename to src/libghost/replay.cpp index f9ff04d..a47912e 100644 --- a/ghost/replay.cpp +++ b/src/libghost/replay.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -44,101 +44,101 @@ CReplay :: ~CReplay( ) } -void CReplay :: AddLeaveGame( uint32_t reason, unsigned char PID, uint32_t result ) +void CReplay :: AddLeaveGame( quint32 reason, unsigned char PID, quint32 result ) { - BYTEARRAY Block; + QByteArray Block; Block.push_back( REPLAY_LEAVEGAME ); - UTIL_AppendByteArray( Block, reason, false ); + Block.append(Util::fromUInt32(reason)); Block.push_back( PID ); - UTIL_AppendByteArray( Block, result, false ); - UTIL_AppendByteArray( Block, (uint32_t)1, false ); - m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); + Block.append(Util::fromUInt32(result)); + Block.append(Util::fromUInt32(1)); + m_CompiledBlocks += Block; } -void CReplay :: AddLeaveGameDuringLoading( uint32_t reason, unsigned char PID, uint32_t result ) +void CReplay :: AddLeaveGameDuringLoading( quint32 reason, unsigned char PID, quint32 result ) { - BYTEARRAY Block; + QByteArray Block; Block.push_back( REPLAY_LEAVEGAME ); - UTIL_AppendByteArray( Block, reason, false ); + Block.append(Util::fromUInt32(reason)); Block.push_back( PID ); - UTIL_AppendByteArray( Block, result, false ); - UTIL_AppendByteArray( Block, (uint32_t)1, false ); - m_LoadingBlocks.push( Block ); + Block.append(Util::fromUInt32(result)); + Block.append(Util::fromUInt32(1)); + m_LoadingBlocks.enqueue( Block ); } -void CReplay :: AddTimeSlot2( queue actions ) +void CReplay :: AddTimeSlot2( QQueue actions ) { - BYTEARRAY Block; + QByteArray Block; Block.push_back( REPLAY_TIMESLOT2 ); - UTIL_AppendByteArray( Block, (uint16_t)0, false ); - UTIL_AppendByteArray( Block, (uint16_t)0, false ); + Block.append(Util::fromUInt16(0)); + Block.append(Util::fromUInt16(0)); - while( !actions.empty( ) ) + while( !actions.isEmpty( ) ) { CIncomingAction *Action = actions.front( ); - actions.pop( ); + actions.dequeue( ); Block.push_back( Action->GetPID( ) ); - UTIL_AppendByteArray( Block, (uint16_t)Action->GetAction( )->size( ), false ); - UTIL_AppendByteArrayFast( Block, *Action->GetAction( ) ); + Block.append(Util::fromUInt16(Action->GetAction( ).size( ))); + Block.append(Action->GetAction( )); } // assign length - BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 3 ), false ); + QByteArray LengthBytes = Util::fromUInt16( Block.size( ) - 3 ); Block[1] = LengthBytes[0]; Block[2] = LengthBytes[1]; - m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); + m_CompiledBlocks += Block; } -void CReplay :: AddTimeSlot( uint16_t timeIncrement, queue actions ) +void CReplay :: AddTimeSlot( quint16 timeIncrement, QQueue actions ) { - BYTEARRAY Block; + QByteArray Block; Block.push_back( REPLAY_TIMESLOT ); - UTIL_AppendByteArray( Block, (uint16_t)0, false ); - UTIL_AppendByteArray( Block, timeIncrement, false ); + Block.append(Util::fromUInt16(0)); + Block.append(Util::fromUInt16(timeIncrement)); - while( !actions.empty( ) ) + while( !actions.isEmpty( ) ) { CIncomingAction *Action = actions.front( ); - actions.pop( ); + actions.dequeue( ); Block.push_back( Action->GetPID( ) ); - UTIL_AppendByteArray( Block, (uint16_t)Action->GetAction( )->size( ), false ); - UTIL_AppendByteArrayFast( Block, *Action->GetAction( ) ); + Block.append(Util::fromUInt16(Action->GetAction( ).size( ))); + Block.append(Action->GetAction( )); } // assign length - BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 3 ), false ); + QByteArray LengthBytes = Util::fromUInt16( Block.size( ) - 3 ); Block[1] = LengthBytes[0]; Block[2] = LengthBytes[1]; - m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); + m_CompiledBlocks += Block; m_ReplayLength += timeIncrement; } -void CReplay :: AddChatMessage( unsigned char PID, unsigned char flags, uint32_t chatMode, string message ) +void CReplay :: AddChatMessage( unsigned char PID, unsigned char flags, quint32 chatMode, QString message ) { - BYTEARRAY Block; + QByteArray Block; Block.push_back( REPLAY_CHATMESSAGE ); Block.push_back( PID ); - UTIL_AppendByteArray( Block, (uint16_t)0, false ); + Block.append(Util::fromUInt16(0)); Block.push_back( flags ); - UTIL_AppendByteArray( Block, chatMode, false ); - UTIL_AppendByteArrayFast( Block, message ); + Block.append(Util::fromUInt32(chatMode)); + Block.append(message); // assign length - BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 4 ), false ); + QByteArray LengthBytes = Util::fromUInt16( Block.size( ) - 4 ); Block[2] = LengthBytes[0]; Block[3] = LengthBytes[1]; - m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); + m_CompiledBlocks += Block; } -void CReplay :: AddLoadingBlock( BYTEARRAY &loadingBlock ) +void CReplay :: AddLoadingBlock( QByteArray &loadingBlock ) { - m_LoadingBlocks.push( loadingBlock ); + m_LoadingBlocks.enqueue( loadingBlock ); } -void CReplay :: BuildReplay( string gameName, string statString, uint32_t war3Version, uint16_t buildNumber ) +void CReplay :: BuildReplay( QString gameName, QString statString, quint32 war3Version, quint16 buildNumber ) { m_War3Version = war3Version; m_BuildNumber = buildNumber; @@ -146,82 +146,83 @@ void CReplay :: BuildReplay( string gameName, string statString, uint32_t war3Ve CONSOLE_Print( "[REPLAY] building replay" ); - uint32_t LanguageID = 0x0012F8B0; - - BYTEARRAY Replay; - Replay.push_back( 16 ); // Unknown (4.0) - Replay.push_back( 1 ); // Unknown (4.0) - Replay.push_back( 0 ); // Unknown (4.0) - Replay.push_back( 0 ); // Unknown (4.0) - Replay.push_back( 0 ); // Host RecordID (4.1) - Replay.push_back( m_HostPID ); // Host PlayerID (4.1) - UTIL_AppendByteArrayFast( Replay, m_HostName ); // Host PlayerName (4.1) - Replay.push_back( 1 ); // Host AdditionalSize (4.1) - Replay.push_back( 0 ); // Host AdditionalData (4.1) - UTIL_AppendByteArrayFast( Replay, gameName ); // GameName (4.2) - Replay.push_back( 0 ); // Null (4.0) - UTIL_AppendByteArrayFast( Replay, statString ); // StatString (4.3) - UTIL_AppendByteArray( Replay, (uint32_t)m_Slots.size( ), false ); // PlayerCount (4.6) - UTIL_AppendByteArray( Replay, m_MapGameType, false ); // GameType (4.7) - UTIL_AppendByteArray( Replay, LanguageID, false ); // LanguageID (4.8) + quint32 LanguageID = 0x0012F8B0; + + QByteArray Replay; + Replay.push_back( (char)16 ); // Unknown (4.0) + Replay.push_back( (char)1 ); // Unknown (4.0) + Replay.push_back( (char)0 ); // Unknown (4.0) + Replay.push_back( (char)0 ); // Unknown (4.0) + Replay.push_back( (char)0 ); // Host RecordID (4.1) + Replay.push_back( (char)m_HostPID ); // Host PlayerID (4.1) + Replay.append(m_HostName); // Host PlayerName (4.1) + Replay.push_back( (char)1 ); // Host AdditionalSize (4.1) + Replay.push_back( (char)0 ); // Host AdditionalData (4.1) + Replay.append(gameName); // GameName (4.2) + Replay.push_back( (char)0 ); // Null (4.0) + Replay.append(statString); // StatString (4.3) + Replay.append(Util::fromUInt32(m_Slots.size( ))); // PlayerCount (4.6) + Replay.append(Util::fromUInt32(m_MapGameType)); // GameType (4.7) + Replay.append(Util::fromUInt32(LanguageID)); // LanguageID (4.8) // PlayerList (4.9) - for( vector :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) + for( QList :: const_iterator i = m_Players.begin( ); i != m_Players.end( ); i++ ) { if( (*i).first != m_HostPID ) { Replay.push_back( 22 ); // Player RecordID (4.1) Replay.push_back( (*i).first ); // Player PlayerID (4.1) - UTIL_AppendByteArrayFast( Replay, (*i).second ); // Player PlayerName (4.1) + Replay.append((*i).second); // Player PlayerName (4.1) Replay.push_back( 1 ); // Player AdditionalSize (4.1) - Replay.push_back( 0 ); // Player AdditionalData (4.1) - UTIL_AppendByteArray( Replay, (uint32_t)0, false ); // Unknown + Replay.push_back( (char)0 ); // Player AdditionalData (4.1) + Replay.append(Util::fromUInt32(0)); // Unknown } } // GameStartRecord (4.10) Replay.push_back( 25 ); // RecordID (4.10) - UTIL_AppendByteArray( Replay, (uint16_t)( 7 + m_Slots.size( ) * 9 ), false ); // Size (4.10) + Replay.append(Util::fromUInt16( 7 + m_Slots.size( ) * 9 )); // Size (4.10) Replay.push_back( m_Slots.size( ) ); // NumSlots (4.10) for( unsigned char i = 0; i < m_Slots.size( ); i++ ) - UTIL_AppendByteArray( Replay, m_Slots[i].GetByteArray( ) ); + Replay.append(m_Slots[i].GetQByteArray( )); - UTIL_AppendByteArray( Replay, m_RandomSeed, false ); // RandomSeed (4.10) + Replay.append(Util::fromUInt32(m_RandomSeed)); // RandomSeed (4.10) Replay.push_back( m_SelectMode ); // SelectMode (4.10) Replay.push_back( m_StartSpotCount ); // StartSpotCount (4.10) // ReplayData (5.0) Replay.push_back( REPLAY_FIRSTSTARTBLOCK ); - UTIL_AppendByteArray( Replay, (uint32_t)1, false ); + Replay.append(Util::fromUInt32(1)); Replay.push_back( REPLAY_SECONDSTARTBLOCK ); - UTIL_AppendByteArray( Replay, (uint32_t)1, false ); + Replay.append(Util::fromUInt32(1)); // leavers during loading need to be stored between the second and third start blocks - while( !m_LoadingBlocks.empty( ) ) + while( !m_LoadingBlocks.isEmpty( ) ) { - UTIL_AppendByteArray( Replay, m_LoadingBlocks.front( ) ); - m_LoadingBlocks.pop( ); + Replay.append(m_LoadingBlocks.front( )); + m_LoadingBlocks.dequeue( ); } Replay.push_back( REPLAY_THIRDSTARTBLOCK ); - UTIL_AppendByteArray( Replay, (uint32_t)1, false ); + Replay.append(Util::fromUInt32(1)); // done - m_Decompressed = string( Replay.begin( ), Replay.end( ) ); + m_Decompressed = Replay; m_Decompressed += m_CompiledBlocks; } #define READB( x, y, z ) (x).read( (char *)(y), (z) ) #define READSTR( x, y ) getline( (x), (y), '\0' ) -void CReplay :: ParseReplay( bool parseBlocks ) +void CReplay :: ParseReplay( bool /*parseBlocks*/ ) { + /* m_HostPID = 0; m_HostName.clear( ); m_GameName.clear( ); @@ -233,9 +234,9 @@ void CReplay :: ParseReplay( bool parseBlocks ) m_RandomSeed = 0; m_SelectMode = 0; m_StartSpotCount = 0; - m_LoadingBlocks = queue( ); - m_Blocks = queue( ); - m_CheckSums = queue( ); + m_LoadingBlocks = QQueue( ); + m_Blocks = QQueue( ); + m_CheckSums = QQueue( ); if( m_Flags != 32768 ) { @@ -247,8 +248,8 @@ void CReplay :: ParseReplay( bool parseBlocks ) istringstream ISS( m_Decompressed ); unsigned char Garbage1; - uint32_t Garbage4; - string GarbageString; + quint32 Garbage4; + QString GarbageString; unsigned char GarbageData[65535]; READB( ISS, &Garbage4, 4 ); // Unknown (4.0) @@ -320,7 +321,7 @@ void CReplay :: ParseReplay( bool parseBlocks ) if( Garbage1 == 22 ) { unsigned char PlayerID; - string PlayerName; + QString PlayerName; READB( ISS, &PlayerID, 1 ); // Player PlayerID (4.1) if( PlayerID > 15 ) @@ -370,7 +371,7 @@ void CReplay :: ParseReplay( bool parseBlocks ) } } - uint16_t Size; + quint16 Size; unsigned char NumSlots; READB( ISS, &Size, 2 ); // Size (4.10) READB( ISS, &NumSlots, 1 ); // NumSlots (4.10) @@ -393,7 +394,7 @@ void CReplay :: ParseReplay( bool parseBlocks ) { unsigned char SlotData[9]; READB( ISS, SlotData, 9 ); - BYTEARRAY SlotDataBA = UTIL_CreateByteArray( SlotData, 9 ); + QByteArray SlotDataBA = UTIL_CreateBYTEARRAY( SlotData, 9 ); m_Slots.push_back( CGameSlot( SlotDataBA ) ); } @@ -460,10 +461,10 @@ void CReplay :: ParseReplay( bool parseBlocks ) if( Garbage1 == CReplay :: REPLAY_LEAVEGAME ) { READB( ISS, GarbageData, 13 ); - BYTEARRAY LoadingBlock; + QByteArray LoadingBlock; LoadingBlock.push_back( Garbage1 ); - UTIL_AppendByteArray( LoadingBlock, GarbageData, 13 ); - m_LoadingBlocks.push( LoadingBlock ); + UTIL_AppendBYTEARRAY( LoadingBlock, GarbageData, 13 ); + m_LoadingBlocks.enqueue( LoadingBlock ); } else if( Garbage1 == CReplay :: REPLAY_THIRDSTARTBLOCK ) break; @@ -491,7 +492,7 @@ void CReplay :: ParseReplay( bool parseBlocks ) return; } - uint32_t ActualReplayLength = 0; + quint32 ActualReplayLength = 0; while( 1 ) { @@ -505,14 +506,14 @@ void CReplay :: ParseReplay( bool parseBlocks ) // reconstruct the block - BYTEARRAY Block; + QByteArray Block; Block.push_back( CReplay :: REPLAY_LEAVEGAME ); - UTIL_AppendByteArray( Block, GarbageData, 13 ); - m_Blocks.push( Block ); + UTIL_AppendBYTEARRAY( Block, GarbageData, 13 ); + m_Blocks.enqueue( Block ); } else if( Garbage1 == CReplay :: REPLAY_TIMESLOT ) { - uint16_t BlockSize; + quint16 BlockSize; READB( ISS, &BlockSize, 2 ); READB( ISS, GarbageData, BlockSize ); @@ -521,16 +522,16 @@ void CReplay :: ParseReplay( bool parseBlocks ) // reconstruct the block - BYTEARRAY Block; + QByteArray Block; Block.push_back( CReplay :: REPLAY_TIMESLOT ); - UTIL_AppendByteArray( Block, BlockSize, false ); - UTIL_AppendByteArray( Block, GarbageData, BlockSize ); - m_Blocks.push( Block ); + Block.append(Util::fromUInt32(BlockSize)); + UTIL_AppendBYTEARRAY( Block, GarbageData, BlockSize ); + m_Blocks.enqueue( Block ); } else if( Garbage1 == CReplay :: REPLAY_CHATMESSAGE ) { unsigned char PID; - uint16_t BlockSize; + quint16 BlockSize; READB( ISS, &PID, 1 ); if( PID > 15 ) @@ -545,12 +546,12 @@ void CReplay :: ParseReplay( bool parseBlocks ) // reconstruct the block - BYTEARRAY Block; + QByteArray Block; Block.push_back( CReplay :: REPLAY_CHATMESSAGE ); Block.push_back( PID ); - UTIL_AppendByteArray( Block, BlockSize, false ); - UTIL_AppendByteArray( Block, GarbageData, BlockSize ); - m_Blocks.push( Block ); + Block.append(Util::fromUInt32(BlockSize)); + UTIL_AppendBYTEARRAY( Block, GarbageData, BlockSize ); + m_Blocks.enqueue( Block ); } else if( Garbage1 == CReplay :: REPLAY_CHECKSUM ) { @@ -563,9 +564,9 @@ void CReplay :: ParseReplay( bool parseBlocks ) return; } - uint32_t CheckSum; + quint32 CheckSum; READB( ISS, &CheckSum, 4 ); - m_CheckSums.push( CheckSum ); + m_CheckSums.enqueue( CheckSum ); } else { @@ -579,4 +580,5 @@ void CReplay :: ParseReplay( bool parseBlocks ) CONSOLE_Print( "[REPLAY] warning - replay length mismatch (" + UTIL_ToString( m_ReplayLength ) + "ms/" + UTIL_ToString( ActualReplayLength ) + "ms)" ); m_Valid = true; + */ } diff --git a/src/libghost/replay.h b/src/libghost/replay.h new file mode 100644 index 0000000..3ce2d35 --- /dev/null +++ b/src/libghost/replay.h @@ -0,0 +1,104 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef REPLAY_H +#define REPLAY_H + +#include "gameslot.h" +#include + +// +// CReplay +// + +class CIncomingAction; + +class CReplay : public CPacked +{ +public: + enum BlockID { + REPLAY_LEAVEGAME = 0x17, + REPLAY_FIRSTSTARTBLOCK = 0x1A, + REPLAY_SECONDSTARTBLOCK = 0x1B, + REPLAY_THIRDSTARTBLOCK = 0x1C, + REPLAY_TIMESLOT2 = 0x1E, // corresponds to W3GS_INCOMING_ACTION2 + REPLAY_TIMESLOT = 0x1F, // corresponds to W3GS_INCOMING_ACTION + REPLAY_CHATMESSAGE = 0x20, + REPLAY_CHECKSUM = 0x22, // corresponds to W3GS_OUTGOING_KEEPALIVE + REPLAY_DESYNC = 0x23 + }; + +private: + unsigned char m_HostPID; + QString m_HostName; + QString m_GameName; + QString m_StatString; + quint32 m_PlayerCount; + quint32 m_MapGameType; + QList m_Players; + QList m_Slots; + quint32 m_RandomSeed; + unsigned char m_SelectMode; // also known as the "layout style" elsewhere in this project + unsigned char m_StartSpotCount; + QQueue m_LoadingBlocks; + QQueue m_Blocks; + QQueue m_CheckSums; + QString m_CompiledBlocks; + +public: + CReplay( ); + virtual ~CReplay( ); + + unsigned char GetHostPID( ) { return m_HostPID; } + QString GetHostName( ) { return m_HostName; } + QString GetGameName( ) { return m_GameName; } + QString GetStatString( ) { return m_StatString; } + quint32 GetPlayerCount( ) { return m_PlayerCount; } + quint32 GetMapGameType( ) { return m_MapGameType; } + QList GetPlayers( ) { return m_Players; } + QList GetSlots( ) { return m_Slots; } + quint32 GetRandomSeed( ) { return m_RandomSeed; } + unsigned char GetSelectMode( ) { return m_SelectMode; } + unsigned char GetStartSpotCount( ) { return m_StartSpotCount; } + QQueue *GetLoadingBlocks( ) { return &m_LoadingBlocks; } + QQueue *GetBlocks( ) { return &m_Blocks; } + QQueue *GetCheckSums( ) { return &m_CheckSums; } + + void AddPlayer( unsigned char nPID, QString nName ) { m_Players.push_back( PIDPlayer( nPID, nName ) ); } + void SetSlots( QList nSlots ) { m_Slots = nSlots; } + void SetRandomSeed( quint32 nRandomSeed ) { m_RandomSeed = nRandomSeed; } + void SetSelectMode( unsigned char nSelectMode ) { m_SelectMode = nSelectMode; } + void SetStartSpotCount( unsigned char nStartSpotCount ) { m_StartSpotCount = nStartSpotCount; } + void SetMapGameType( quint32 nMapGameType ) { m_MapGameType = nMapGameType; } + void SetHostPID( unsigned char nHostPID ) { m_HostPID = nHostPID; } + void SetHostName( QString nHostName ) { m_HostName = nHostName; } + + void AddLeaveGame( quint32 reason, unsigned char PID, quint32 result ); + void AddLeaveGameDuringLoading( quint32 reason, unsigned char PID, quint32 result ); + void AddTimeSlot2( QQueue actions ); + void AddTimeSlot( quint16 timeIncrement, QQueue actions ); + void AddChatMessage( unsigned char PID, unsigned char flags, quint32 chatMode, QString message ); + void AddLoadingBlock( QByteArray &loadingBlock ); + void BuildReplay( QString gameName, QString statString, quint32 war3Version, quint16 buildNumber ); + + void ParseReplay( bool parseBlocks ); +}; + +#endif diff --git a/ghost/savegame.cpp b/src/libghost/savegame.cpp similarity index 82% rename from ghost/savegame.cpp rename to src/libghost/savegame.cpp index 9c9ce6f..fdbb721 100644 --- a/ghost/savegame.cpp +++ b/src/libghost/savegame.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -42,7 +42,7 @@ CSaveGame :: ~CSaveGame( ) #define READSTR( x, y ) getline( (x), (y), '\0' ) void CSaveGame :: ParseSaveGame( ) -{ +{/* m_MapPath.clear( ); m_GameName.clear( ); m_NumSlots = 0; @@ -60,11 +60,11 @@ void CSaveGame :: ParseSaveGame( ) istringstream ISS( m_Decompressed ); // savegame format figured out by Varlock: - // string -> map path - // 0 (string?) -> ??? (no idea what this is) - // string -> game name - // 0 (string?) -> ??? (maybe original game password) - // string -> stat string + // QString -> map path + // 0 (QString?) -> ??? (no idea what this is) + // QString -> game name + // 0 (QString?) -> ??? (maybe original game password) + // QString -> stat QString // 4 bytes -> ??? (seems to be # of slots) // 4 bytes -> ??? (seems to be 0x01 0x28 0x49 0x00 on both of the savegames examined) // 2 bytes -> ??? (no idea what this is) @@ -72,16 +72,16 @@ void CSaveGame :: ParseSaveGame( ) // 4 bytes -> magic number unsigned char Garbage1; - uint16_t Garbage2; - uint32_t Garbage4; - string GarbageString; - uint32_t MagicNumber; + quint16 Garbage2; + quint32 Garbage4; + QString GarbageString; + quint32 MagicNumber; READSTR( ISS, m_MapPath ); // map path READSTR( ISS, GarbageString ); // ??? READSTR( ISS, m_GameName ); // game name READSTR( ISS, GarbageString ); // ??? - READSTR( ISS, GarbageString ); // stat string + READSTR( ISS, GarbageString ); // stat QString READB( ISS, &Garbage4, 4 ); // ??? READB( ISS, &Garbage4, 4 ); // ??? READB( ISS, &Garbage2, 2 ); // ??? @@ -113,6 +113,6 @@ void CSaveGame :: ParseSaveGame( ) return; } - m_MagicNumber = UTIL_CreateByteArray( MagicNumber, false ); - m_Valid = true; + m_MagicNumber = UTIL_CreateQByteArray( MagicNumber, false ); + m_Valid = true;*/ } diff --git a/ghost/savegame.h b/src/libghost/savegame.h similarity index 53% rename from ghost/savegame.h rename to src/libghost/savegame.h index 326bcf5..7c58cfc 100644 --- a/ghost/savegame.h +++ b/src/libghost/savegame.h @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -30,30 +30,30 @@ class CSaveGame : public CPacked { private: - string m_FileName; - string m_FileNameNoPath; - string m_MapPath; - string m_GameName; + QString m_FileName; + QString m_FileNameNoPath; + QString m_MapPath; + QString m_GameName; unsigned char m_NumSlots; - vector m_Slots; - uint32_t m_RandomSeed; - BYTEARRAY m_MagicNumber; + QList m_Slots; + quint32 m_RandomSeed; + QByteArray m_MagicNumber; public: CSaveGame( ); virtual ~CSaveGame( ); - string GetFileName( ) { return m_FileName; } - string GetFileNameNoPath( ) { return m_FileNameNoPath; } - string GetMapPath( ) { return m_MapPath; } - string GetGameName( ) { return m_GameName; } + QString GetFileName( ) { return m_FileName; } + QString GetFileNameNoPath( ) { return m_FileNameNoPath; } + QString GetMapPath( ) { return m_MapPath; } + QString GetGameName( ) { return m_GameName; } unsigned char GetNumSlots( ) { return m_NumSlots; } - vector GetSlots( ) { return m_Slots; } - uint32_t GetRandomSeed( ) { return m_RandomSeed; } - BYTEARRAY GetMagicNumber( ) { return m_MagicNumber; } + QList GetSlots( ) { return m_Slots; } + quint32 GetRandomSeed( ) { return m_RandomSeed; } + QByteArray GetMagicNumber( ) { return m_MagicNumber; } - void SetFileName( string nFileName ) { m_FileName = nFileName; } - void SetFileNameNoPath( string nFileNameNoPath ) { m_FileNameNoPath = nFileNameNoPath; } + void SetFileName( QString nFileName ) { m_FileName = nFileName; } + void SetFileNameNoPath( QString nFileNameNoPath ) { m_FileNameNoPath = nFileNameNoPath; } void ParseSaveGame( ); }; diff --git a/ghost/sha1.cpp b/src/libghost/sha1.cpp similarity index 94% rename from ghost/sha1.cpp rename to src/libghost/sha1.cpp index 82fb7fa..9832d4c 100644 --- a/ghost/sha1.cpp +++ b/src/libghost/sha1.cpp @@ -44,9 +44,9 @@ void CSHA1::Reset() m_count[1] = 0; } -void CSHA1::Transform(uint32_t state[5], unsigned char buffer[64]) +void CSHA1::Transform(quint32 state[5], unsigned char buffer[64]) { - uint32_t a = 0, b = 0, c = 0, d = 0, e = 0; + quint32 a = 0, b = 0, c = 0, d = 0, e = 0; SHA1_WORKSPACE_BLOCK* block; static unsigned char workspace[64]; @@ -96,7 +96,7 @@ void CSHA1::Transform(uint32_t state[5], unsigned char buffer[64]) // Use this function to hash in binary data and strings void CSHA1::Update(unsigned char* data, unsigned int len) { - uint32_t i = 0, j = 0; + quint32 i = 0, j = 0; j = (m_count[0] >> 3) & 63; @@ -123,7 +123,7 @@ void CSHA1::Update(unsigned char* data, unsigned int len) void CSHA1::Final() { - uint32_t i = 0, j = 0; + quint32 i = 0, j = 0; unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; for (i = 0; i < 8; i++) @@ -152,8 +152,8 @@ void CSHA1::Final() Transform(m_state, m_buffer); } -// Get the final hash as a pre-formatted string -void CSHA1::ReportHash(char *szReport, unsigned char uReportType) +// Get the final hash as a pre-formatted QString +void CSHA1::ReportHash(char */*szReport*/, unsigned char /*uReportType*/) { /* diff --git a/ghost/sha1.h b/src/libghost/sha1.h similarity index 88% rename from ghost/sha1.h rename to src/libghost/sha1.h index dc04677..b93364f 100644 --- a/ghost/sha1.h +++ b/src/libghost/sha1.h @@ -24,12 +24,7 @@ #include // Needed for strcat and strcpy // standard integer sizes for 64 bit compatibility - -#ifdef WIN32 - #include "ms_stdint.h" -#else - #include -#endif +#include #define MAX_FILE_READ_BUFFER 8000 @@ -58,7 +53,7 @@ class CSHA1 typedef union { unsigned char c[64]; - uint32_t l[16]; + quint32 l[16]; } SHA1_WORKSPACE_BLOCK; // Two different formats for ReportHash(...) @@ -68,8 +63,8 @@ class CSHA1 CSHA1(); virtual ~CSHA1(); - uint32_t m_state[5]; - uint32_t m_count[2]; + quint32 m_state[5]; + quint32 m_count[2]; unsigned char m_buffer[64]; unsigned char m_digest[20]; @@ -85,7 +80,7 @@ class CSHA1 private: // Private SHA-1 transformation - void Transform(uint32_t state[5], unsigned char buffer[64]); + void Transform(quint32 state[5], unsigned char buffer[64]); }; #endif // ___SHA1_H___ diff --git a/ghost/sqlite3.c b/src/libghost/sqlite3.c similarity index 100% rename from ghost/sqlite3.c rename to src/libghost/sqlite3.c diff --git a/ghost/sqlite3.h b/src/libghost/sqlite3.h similarity index 98% rename from ghost/sqlite3.h rename to src/libghost/sqlite3.h index cc4d354..0f620c0 100644 --- a/ghost/sqlite3.h +++ b/src/libghost/sqlite3.h @@ -84,7 +84,7 @@ extern "C" { ** the sqlite3.h file specify the version of SQLite with which ** that header file is associated. ** -** The "version" of SQLite is a string of the form "X.Y.Z". +** The "version" of SQLite is a QString of the form "X.Y.Z". ** The phrase "alpha" or "beta" might be appended after the Z. ** The X value is major version number always 3 in SQLite3. ** The X value only changes when backwards compatibility is @@ -114,8 +114,8 @@ extern "C" { ** [SQLITE_VERSION_NUMBER]. ** ** The sqlite3_libversion() function returns the same information as is -** in the sqlite3_version[] string constant. The function is provided -** for use in DLLs since DLL users usually do not have direct access to string +** in the sqlite3_version[] QString constant. The function is provided +** for use in DLLs since DLL users usually do not have direct access to QString ** constants within the DLL. ** ** Requirements: [H10021] [H10022] [H10023] @@ -264,8 +264,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** message returned through the 5th parameter when it has finished using ** the error message. ** -** If the SQL statement in the 2nd parameter is NULL or an empty string -** or a string containing only whitespace and comments, then no SQL +** If the SQL statement in the 2nd parameter is NULL or an empty QString +** or a QString containing only whitespace and comments, then no SQL ** statements are evaluated and the database is not changed. ** ** The sqlite3_exec() interface is implemented in terms of @@ -657,9 +657,9 @@ typedef struct sqlite3_mutex sqlite3_mutex; ** be unique across all VFS modules. ** ** SQLite will guarantee that the zFilename parameter to xOpen -** is either a NULL pointer or string obtained +** is either a NULL pointer or QString obtained ** from xFullPathname(). SQLite further guarantees that -** the string will be valid and unchanged until xClose() is +** the QString will be valid and unchanged until xClose() is ** called. Because of the previous sentence, ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. @@ -1370,11 +1370,11 @@ void sqlite3_interrupt(sqlite3*); ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into -** SQLite for parsing. These routines return 1 if the input string +** SQLite for parsing. These routines return 1 if the input QString ** appears to be a complete SQL statement. A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. Semicolons that are embedded within -** string literals or quoted identifier names or comments are not +** QString literals or quoted identifier names or comments are not ** independent tokens (they are part of the token in which they are ** embedded) and thus do not count as a statement terminator. Whitespace ** and comments that follow the final semicolon are ignored. @@ -1397,7 +1397,7 @@ void sqlite3_interrupt(sqlite3*); ** UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated -** UTF-16 string in native byte order. +** UTF-16 QString in native byte order. */ int sqlite3_complete(const char *sql); int sqlite3_complete16(const void *sql); @@ -1511,7 +1511,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms); ** to zero-terminated strings that contain the names of the columns. ** The remaining entries all point to query results. NULL values result ** in NULL pointers. All other values are in their UTF-8 zero-terminated -** string representation as returned by [sqlite3_column_text()]. +** QString representation as returned by [sqlite3_column_text()]. ** ** A result table might consist of one or more memory allocations. ** It is not safe to pass a result table directly to [sqlite3_free()]. @@ -1545,7 +1545,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms); ** ** The sqlite3_get_table() function evaluates one or more ** semicolon-separated SQL statements in the zero-terminated UTF-8 -** string of its 2nd parameter. It returns a result table to the +** QString of its 2nd parameter. It returns a result table to the ** pointer given in its 3rd parameter. ** ** After the calling function has finished using the result, it should @@ -1604,7 +1604,7 @@ void sqlite3_free_table(char **result); ** As long as the buffer size is greater than zero, sqlite3_snprintf() ** guarantees that the buffer is always zero-terminated. The first ** parameter "n" is the total size of the buffer, including space for -** the zero terminator. So the longest string that can be completely +** the zero terminator. So the longest QString that can be completely ** written will be n-1 characters. ** ** These routines all implement some additional formatting @@ -1613,12 +1613,12 @@ void sqlite3_free_table(char **result); ** is are "%q", "%Q", and "%z" options. ** ** The %q option works like %s in that it substitutes a null-terminated -** string from the argument list. But %q also doubles every '\'' character. -** %q is designed for use inside a string literal. By doubling each '\'' +** QString from the argument list. But %q also doubles every '\'' character. +** %q is designed for use inside a QString literal. By doubling each '\'' ** character it escapes that character and allows it to be inserted into ** the string. ** -** For example, assume the string variable zText contains text as follows: +** For example, assume the QString variable zText contains text as follows: ** **
 **  char *zText = "It's a happy day!";
@@ -1632,7 +1632,7 @@ void sqlite3_free_table(char **result);
 **  sqlite3_free(zSQL);
 ** 
** -** Because the %q format string is used, the '\'' character in zText +** Because the %q format QString is used, the '\'' character in zText ** is escaped and the SQL generated is as follows: ** **
@@ -1647,7 +1647,7 @@ void sqlite3_free_table(char **result);
 ** 
** ** This second example is an SQL syntax error. As a general rule you should -** always use %q instead of %s when inserting text into a string literal. +** always use %q instead of %s when inserting text into a QString literal. ** ** The %Q option works like %q except it also adds single quotes around ** the outside of the total string. Additionally, if the parameter in the @@ -1664,7 +1664,7 @@ void sqlite3_free_table(char **result); ** variable even if the zText variable is a NULL pointer. ** ** The "%z" formatting option works exactly like "%s" with the -** addition that after the string has been read and copied into +** addition that after the QString has been read and copied into ** the result, [sqlite3_free()] is called on the input string. {END} ** ** Requirements: @@ -2118,9 +2118,9 @@ int sqlite3_open_v2( ** ** The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. -** Memory to hold the error message string is managed internally. +** Memory to hold the error message QString is managed internally. ** The application does not need to worry about freeing the result. -** However, the error string might be overwritten or deallocated by +** However, the error QString might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions. ** ** When the serialized [threading mode] is in use, it might be the @@ -2221,7 +2221,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** **
**
SQLITE_LIMIT_LENGTH
-**
The maximum size of any string or BLOB or table row.
+**
The maximum size of any QString or BLOB or table row.
** **
SQLITE_LIMIT_SQL_LENGTH
**
The maximum length of an SQL statement.
@@ -2286,11 +2286,11 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** If the nByte argument is less than zero, then zSql is read up to the ** first zero terminator. If nByte is non-negative, then it is the maximum ** number of bytes read from zSql. When nByte is non-negative, the -** zSql string ends at either the first '\000' or '\u0000' character or +** zSql QString ends at either the first '\000' or '\u0000' character or ** the nByte-th byte, whichever comes first. If the caller knows -** that the supplied string is nul-terminated, then there is a small +** that the supplied QString is nul-terminated, then there is a small ** performance advantage to be gained by passing an nByte parameter that -** is equal to the number of bytes in the input string including +** is equal to the number of bytes in the input QString including ** the nul-terminator bytes. ** ** If pzTail is not NULL then *pzTail is made to point to the first byte @@ -2301,7 +2301,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** *ppStmt is left pointing to a compiled [prepared statement] that can be ** executed using [sqlite3_step()]. If there is an error, *ppStmt is set ** to NULL. If the input text contains no SQL (if the input is an empty -** string or a comment) then *ppStmt is set to NULL. +** QString or a comment) then *ppStmt is set to NULL. ** The calling procedure is responsible for deleting the compiled ** SQL statement using [sqlite3_finalize()] after it has finished with it. ** ppStmt may not be NULL. @@ -2476,12 +2476,12 @@ typedef struct sqlite3_context sqlite3_context; ** In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the value, not the number of characters. -** If the fourth parameter is negative, the length of the string is +** If the fourth parameter is negative, the length of the QString is ** the number of bytes up to the first zero terminator. ** ** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or -** string after SQLite has finished with it. If the fifth argument is +** QString after SQLite has finished with it. If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. ** If the fifth argument has the value [SQLITE_TRANSIENT], then @@ -2559,7 +2559,7 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*); ** This routine returns a pointer to the name of the n-th ** [SQL parameter] in a [prepared statement]. ** SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" -** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" +** have a name which is the QString "?NNN" or ":AAA" or "@AAA" or "$AAA" ** respectively. ** In other words, the initial ":" or "$" or "@" or "?" ** is included as part of the name. @@ -2569,7 +2569,7 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*); ** The first host parameter has an index of 1, not 0. ** ** If the value n is out of range or if the n-th parameter is -** nameless, then NULL is returned. The returned string is +** nameless, then NULL is returned. The returned QString is ** always in UTF-8 encoding even if the named parameter was ** originally specified as UTF-16 in [sqlite3_prepare16()] or ** [sqlite3_prepare16_v2()]. @@ -2631,13 +2631,13 @@ int sqlite3_column_count(sqlite3_stmt *pStmt); ** ** These routines return the name assigned to a particular column ** in the result set of a [SELECT] statement. The sqlite3_column_name() -** interface returns a pointer to a zero-terminated UTF-8 string +** interface returns a pointer to a zero-terminated UTF-8 QString ** and sqlite3_column_name16() returns a pointer to a zero-terminated ** UTF-16 string. The first parameter is the [prepared statement] ** that implements the [SELECT] statement. The second parameter is the ** column number. The leftmost column is number 0. ** -** The returned string pointer is valid until either the [prepared statement] +** The returned QString pointer is valid until either the [prepared statement] ** is destroyed by [sqlite3_finalize()] or until the next call to ** sqlite3_column_name() or sqlite3_column_name16() on the same column. ** @@ -2665,7 +2665,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** either a UTF-8 or UTF-16 string. The _database_ routines return ** the database name, the _table_ routines return the table name, and ** the origin_ routines return the column name. -** The returned string is valid until the [prepared statement] is destroyed +** The returned QString is valid until the [prepared statement] is destroyed ** using [sqlite3_finalize()] or until the same information is requested ** again in a different encoding. ** @@ -2717,7 +2717,7 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); ** expression or subquery) then the declared type of the table ** column is returned. If the Nth column of the result set is an ** expression or subquery, then a NULL pointer is returned. -** The returned string is always UTF-8 encoded. {END} +** The returned QString is always UTF-8 encoded. {END} ** ** For example, given the database schema: ** @@ -2727,7 +2727,7 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); ** ** SELECT c1 + 1, c1 FROM t1; ** -** this routine would return the string "VARIANT" for the second result +** this routine would return the QString "VARIANT" for the second result ** column (i==1), and a NULL pointer for the first result column (i==0). ** ** SQLite uses dynamic run-time typing. So just because a column @@ -2832,7 +2832,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); **
    **
  • 64-bit signed integer **
  • 64-bit IEEE floating point number -**
  • string +**
  • QString **
  • BLOB **
  • NULL **
{END} @@ -2890,12 +2890,12 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** -** If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() +** If the result is a BLOB or UTF-8 QString then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** If the result is a UTF-16 string, then sqlite3_column_bytes() converts -** the string to UTF-8 and then returns the number of bytes. +** the QString to UTF-8 and then returns the number of bytes. ** If the result is a numeric value then sqlite3_column_bytes() uses -** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns +** [sqlite3_snprintf()] to convert that value to a UTF-8 QString and returns ** the number of bytes in that string. ** The value returned does not include the zero terminator at the end ** of the string. For clarity: the value returned is the number of @@ -3229,7 +3229,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void ** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** -** The sqlite3_value_text16() interface extracts a UTF-16 string +** The sqlite3_value_text16() interface extracts a UTF-16 QString ** in the native byte-order of the host machine. The ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. @@ -3238,7 +3238,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other -** words, if the value is a string that looks like a number) +** words, if the value is a QString that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned. ** @@ -3338,7 +3338,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** function. The compiled version of the regular expression is stored as ** metadata associated with the SQL value passed as the regular expression ** pattern. The compiled regular expression can be reused on multiple -** invocations of the same function so that the original pattern string +** invocations of the same function so that the original pattern QString ** does not need to be recompiled on each invocation. ** ** The sqlite3_get_auxdata() interface returns a pointer to the metadata @@ -3421,11 +3421,11 @@ typedef void (*sqlite3_destructor_type)(void*); ** ** The sqlite3_result_error() and sqlite3_result_error16() functions ** cause the implemented SQL function to throw an exception. -** SQLite uses the string pointed to by the +** SQLite uses the QString pointed to by the ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. SQLite interprets the error -** message string from sqlite3_result_error() as UTF-8. SQLite -** interprets the string from sqlite3_result_error16() as UTF-16 in native +** message QString from sqlite3_result_error() as UTF-8. SQLite +** interprets the QString from sqlite3_result_error16() as UTF-16 in native ** byte order. If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. @@ -3442,7 +3442,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. ** ** The sqlite3_result_toobig() interface causes SQLite to throw an error -** indicating that a string or BLOB is to long to represent. +** indicating that a QString or BLOB is to long to represent. ** ** The sqlite3_result_nomem() interface causes SQLite to throw an error ** indicating that a memory allocation failed. @@ -3460,7 +3460,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** The sqlite3_result_text(), sqlite3_result_text16(), ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces ** set the return value of the application-defined function to be -** a text string which is represented as UTF-8, UTF-16 native byte order, +** a text QString which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. ** SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. @@ -3526,9 +3526,9 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n); ** These functions are used to add new collation sequences to the ** [database connection] specified as the first argument. ** -** The name of the new collation sequence is specified as a UTF-8 string +** The name of the new collation sequence is specified as a UTF-8 QString ** for sqlite3_create_collation() and sqlite3_create_collation_v2() -** and a UTF-16 string for sqlite3_create_collation16(). In all cases +** and a UTF-16 QString for sqlite3_create_collation16(). In all cases ** the name is passed as the second function argument. ** ** The third argument may be one of the constants [SQLITE_UTF8], @@ -3552,7 +3552,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n); ** each represented by a (length, data) pair and encoded in the encoding ** that was passed as the third argument when the collation sequence was ** registered. {END} The application defined collation routine should -** return negative, zero or positive if the first string is less than, +** return negative, zero or positive if the first QString is less than, ** equal to, or greater than the second string. i.e. (STRING1 - STRING2). ** ** The sqlite3_create_collation_v2() works like sqlite3_create_collation() @@ -3679,7 +3679,7 @@ int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files {H10310} ** -** If this global variable is made to point to a string which is +** If this global variable is made to point to a QString which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite will be placed in that directory. If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate @@ -3696,7 +3696,7 @@ int sqlite3_sleep(int); ** ** The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. Furthermore, -** the [temp_store_directory pragma] always assumes that any string +** the [temp_store_directory pragma] always assumes that any QString ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. @@ -4323,10 +4323,10 @@ SQLITE_EXPERIMENTAL int sqlite3_create_module_v2( ** common to all module implementations. ** ** Virtual tables methods can set an error message by assigning a -** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should -** take care that any prior string is freed by a call to [sqlite3_free()] -** prior to assigning a new string to zErrMsg. After the error message -** is delivered up to the client application, the string will be automatically +** QString obtained from [sqlite3_mprintf()] to zErrMsg. The method should +** take care that any prior QString is freed by a call to [sqlite3_free()] +** prior to assigning a new QString to zErrMsg. After the error message +** is delivered up to the client application, the QString will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { diff --git a/ghost/sqlite3ext.h b/src/libghost/sqlite3ext.h similarity index 100% rename from ghost/sqlite3ext.h rename to src/libghost/sqlite3ext.h diff --git a/ghost/stats.cpp b/src/libghost/stats.cpp similarity index 77% rename from ghost/stats.cpp rename to src/libghost/stats.cpp index 9dec048..98dd1d2 100644 --- a/ghost/stats.cpp +++ b/src/libghost/stats.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -35,12 +35,12 @@ CStats :: ~CStats( ) } -bool CStats :: ProcessAction( CIncomingAction *Action ) +bool CStats :: ProcessAction( CIncomingAction */*Action*/ ) { return false; } -void CStats :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) +void CStats :: Save( CGHost */*GHost*/, CGHostDB */*DB*/, quint32 /*GameID*/ ) { } diff --git a/ghost/stats.h b/src/libghost/stats.h similarity index 92% rename from ghost/stats.h rename to src/libghost/stats.h index bc02812..24eea8b 100644 --- a/ghost/stats.h +++ b/src/libghost/stats.h @@ -45,7 +45,7 @@ class CStats virtual ~CStats( ); virtual bool ProcessAction( CIncomingAction *Action ); - virtual void Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ); + virtual void Save( CGHost *GHost, CGHostDB *DB, quint32 GameID ); }; #endif diff --git a/ghost/statsdota.cpp b/src/libghost/statsdota.cpp similarity index 76% rename from ghost/statsdota.cpp rename to src/libghost/statsdota.cpp index f7499a8..bb30ef0 100644 --- a/ghost/statsdota.cpp +++ b/src/libghost/statsdota.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -27,6 +27,8 @@ #include "stats.h" #include "statsdota.h" +#include + // // CStatsDOTA // @@ -55,46 +57,51 @@ CStatsDOTA :: ~CStatsDOTA( ) bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) { unsigned int i = 0; - BYTEARRAY *ActionData = Action->GetAction( ); - BYTEARRAY Data; - BYTEARRAY Key; - BYTEARRAY Value; + const QByteArray &ActionData = Action->GetAction( ); + QByteArray Data; + QByteArray Key; + QByteArray Value; - // dota actions with real time replay data start with 0x6b then the null terminated string "dr.x" + // dota actions with real time replay data start with 0x6b then the null terminated QString "dr.x" // unfortunately more than one action can be sent in a single packet and the length of each action isn't explicitly represented in the packet // so we have to either parse all the actions and calculate the length based on the type or we can search for an identifying sequence // parsing the actions would be more correct but would be a lot more difficult to write for relatively little gain // so we take the easy route (which isn't always guaranteed to work) and search the data for the sequence "6b 64 72 2e 78 00" and hope it identifies an action - while( ActionData->size( ) >= i + 6 ) + while( (unsigned int)ActionData.size( ) >= i + 6 ) { - if( (*ActionData)[i] == 0x6b && (*ActionData)[i + 1] == 0x64 && (*ActionData)[i + 2] == 0x72 && (*ActionData)[i + 3] == 0x2e && (*ActionData)[i + 4] == 0x78 && (*ActionData)[i + 5] == 0x00 ) + if( ActionData.at(i) == 0x6b && + ActionData.at(i + 1) == 0x64 && + ActionData.at(i + 2) == 0x72 && + ActionData.at(i + 3) == 0x2e && + ActionData.at(i + 4) == 0x78 && + ActionData.at(i + 5) == 0x00 ) { // we think we've found an action with real time replay data (but we can't be 100% sure) // next we parse out two null terminated strings and a 4 byte integer - if( ActionData->size( ) >= i + 7 ) + if( (unsigned int)ActionData.size( ) >= i + 7 ) { - // the first null terminated string should either be the strings "Data" or "Global" or a player id in ASCII representation, e.g. "1" or "2" + // the first null terminated QString should either be the strings "Data" or "Global" or a player id in ASCII representation, e.g. "1" or "2" - Data = UTIL_ExtractCString( *ActionData, i + 6 ); + Data = UTIL_ExtractCString( ActionData, i + 6 ); - if( ActionData->size( ) >= i + 8 + Data.size( ) ) + if( (unsigned int)ActionData.size( ) >= i + 8 + Data.size( ) ) { - // the second null terminated string should be the key + // the second null terminated QString should be the key - Key = UTIL_ExtractCString( *ActionData, i + 7 + Data.size( ) ); + Key = UTIL_ExtractCString( ActionData, i + 7 + Data.size( ) ); - if( ActionData->size( ) >= i + 12 + Data.size( ) + Key.size( ) ) + if( (unsigned int)ActionData.size( ) >= i + 12 + Data.size( ) + Key.size( ) ) { // the 4 byte integer should be the value - Value = BYTEARRAY( ActionData->begin( ) + i + 8 + Data.size( ) + Key.size( ), ActionData->begin( ) + i + 12 + Data.size( ) + Key.size( ) ); - string DataString = string( Data.begin( ), Data.end( ) ); - string KeyString = string( Key.begin( ), Key.end( ) ); - uint32_t ValueInt = UTIL_ByteArrayToUInt32( Value, false ); + Value = ActionData.mid(i + 8 + Data.size( ) + Key.size( ), 4 ); + QString DataString = Data; + QString KeyString = Key; + quint32 ValueInt = Util::extractUInt32( Value ); - // CONSOLE_Print( "[STATS] " + DataString + ", " + KeyString + ", " + UTIL_ToString( ValueInt ) ); + // CONSOLE_Print( "[STATS] " + DataString + ", " + KeyString + ", " + QString::number( ValueInt ) ); if( DataString == "Data" ) { @@ -102,12 +109,11 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) // you could use these to calculate killing sprees and double or triple kills (you'd have to make up your own time restrictions though) // you could also build a table of "who killed who" data - if( KeyString.size( ) >= 5 && KeyString.substr( 0, 4 ) == "Hero" ) + if( KeyString.size( ) >= 5 && KeyString.mid( 0, 4 ) == "Hero" ) { // a hero died - string VictimColourString = KeyString.substr( 4 ); - uint32_t VictimColour = UTIL_ToUInt32( VictimColourString ); + quint32 VictimColour = KeyString.mid( 4 ).toUInt(); CGamePlayer *Killer = m_Game->GetPlayerFromColour( ValueInt ); CGamePlayer *Victim = m_Game->GetPlayerFromColour( VictimColour ); @@ -121,7 +127,7 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Scourge killed player [" + Victim->GetName( ) + "]" ); } } - else if( KeyString.size( ) >= 8 && KeyString.substr( 0, 7 ) == "Courier" ) + else if( KeyString.size( ) >= 8 && KeyString.mid( 0, 7 ) == "Courier" ) { // a courier died @@ -133,8 +139,7 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) m_Players[ValueInt]->SetCourierKills( m_Players[ValueInt]->GetCourierKills( ) + 1 ); } - string VictimColourString = KeyString.substr( 7 ); - uint32_t VictimColour = UTIL_ToUInt32( VictimColourString ); + quint32 VictimColour = KeyString.mid( 7 ).toUInt(); CGamePlayer *Killer = m_Game->GetPlayerFromColour( ValueInt ); CGamePlayer *Victim = m_Game->GetPlayerFromColour( VictimColour ); @@ -148,7 +153,7 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Scourge killed a courier owned by player [" + Victim->GetName( ) + "]" ); } } - else if( KeyString.size( ) >= 8 && KeyString.substr( 0, 5 ) == "Tower" ) + else if( KeyString.size( ) >= 8 && KeyString.mid( 0, 5 ) == "Tower" ) { // a tower died @@ -160,12 +165,12 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) m_Players[ValueInt]->SetTowerKills( m_Players[ValueInt]->GetTowerKills( ) + 1 ); } - string Alliance = KeyString.substr( 5, 1 ); - string Level = KeyString.substr( 6, 1 ); - string Side = KeyString.substr( 7, 1 ); + QString Alliance = KeyString.mid( 5, 1 ); + QString Level = KeyString.mid( 6, 1 ); + QString Side = KeyString.mid( 7, 1 ); CGamePlayer *Killer = m_Game->GetPlayerFromColour( ValueInt ); - string AllianceString; - string SideString; + QString AllianceString; + QString SideString; if( Alliance == "0" ) AllianceString = "Sentinel"; @@ -193,7 +198,7 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Scourge destroyed a level [" + Level + "] " + AllianceString + " tower (" + SideString + ")" ); } } - else if( KeyString.size( ) >= 6 && KeyString.substr( 0, 3 ) == "Rax" ) + else if( KeyString.size( ) >= 6 && KeyString.mid( 0, 3 ) == "Rax" ) { // a rax died @@ -205,13 +210,13 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) m_Players[ValueInt]->SetRaxKills( m_Players[ValueInt]->GetRaxKills( ) + 1 ); } - string Alliance = KeyString.substr( 3, 1 ); - string Side = KeyString.substr( 4, 1 ); - string Type = KeyString.substr( 5, 1 ); + QString Alliance = KeyString.mid( 3, 1 ); + QString Side = KeyString.mid( 4, 1 ); + QString Type = KeyString.mid( 5, 1 ); CGamePlayer *Killer = m_Game->GetPlayerFromColour( ValueInt ); - string AllianceString; - string SideString; - string TypeString; + QString AllianceString; + QString SideString; + QString TypeString; if( Alliance == "0" ) AllianceString = "Sentinel"; @@ -246,19 +251,19 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Scourge destroyed a " + TypeString + " " + AllianceString + " rax (" + SideString + ")" ); } } - else if( KeyString.size( ) >= 6 && KeyString.substr( 0, 6 ) == "Throne" ) + else if( KeyString.size( ) >= 6 && KeyString.mid( 0, 6 ) == "Throne" ) { // the frozen throne got hurt - CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Frozen Throne is now at " + UTIL_ToString( ValueInt ) + "% HP" ); + CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the Frozen Throne is now at " + QString::number( ValueInt ) + "% HP" ); } - else if( KeyString.size( ) >= 4 && KeyString.substr( 0, 4 ) == "Tree" ) + else if( KeyString.size( ) >= 4 && KeyString.mid( 0, 4 ) == "Tree" ) { // the world tree got hurt - CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the World Tree is now at " + UTIL_ToString( ValueInt ) + "% HP" ); + CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] the World Tree is now at " + QString::number( ValueInt ) + "% HP" ); } - else if( KeyString.size( ) >= 2 && KeyString.substr( 0, 2 ) == "CK" ) + else if( KeyString.size( ) >= 2 && KeyString.mid( 0, 2 ) == "CK" ) { // a player disconnected } @@ -279,18 +284,18 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) else if( m_Winner == 2 ) CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] detected winner: Scourge" ); else - CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] detected winner: " + UTIL_ToString( ValueInt ) ); + CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] detected winner: " + QString::number( ValueInt ) ); } else if( KeyString == "m" ) m_Min = ValueInt; else if( KeyString == "s" ) m_Sec = ValueInt; } - else if( DataString.size( ) <= 2 && DataString.find_first_not_of( "1234567890" ) == string :: npos ) + else if( DataString.size( ) <= 2 && DataString.indexOf(QRegExp( "[^0-9]" )) == -1 ) { // these are only received at the end of the game - uint32_t ID = UTIL_ToUInt32( DataString ); + quint32 ID = DataString.toUInt(); if( ( ID >= 1 && ID <= 5 ) || ( ID >= 7 && ID <= 11 ) ) { @@ -330,19 +335,19 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) else if( KeyString == "7" ) m_Players[ID]->SetNeutralKills( ValueInt ); else if( KeyString == "8_0" ) - m_Players[ID]->SetItem( 0, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 0, QString( Util::reverse(Value) ) ); else if( KeyString == "8_1" ) - m_Players[ID]->SetItem( 1, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 1, QString( Util::reverse(Value) ) ); else if( KeyString == "8_2" ) - m_Players[ID]->SetItem( 2, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 2, QString( Util::reverse(Value) ) ); else if( KeyString == "8_3" ) - m_Players[ID]->SetItem( 3, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 3, QString( Util::reverse(Value) ) ); else if( KeyString == "8_4" ) - m_Players[ID]->SetItem( 4, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 4, QString( Util::reverse(Value) ) ); else if( KeyString == "8_5" ) - m_Players[ID]->SetItem( 5, string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetItem( 5, QString( Util::reverse(Value) ) ); else if( KeyString == "9" ) - m_Players[ID]->SetHero( string( Value.rbegin( ), Value.rend( ) ) ); + m_Players[ID]->SetHero( QString( Util::reverse(Value) ) ); else if( KeyString == "id" ) { // DotA sends id values from 1-10 with 1-5 being sentinel players and 6-10 being scourge players @@ -374,7 +379,7 @@ bool CStatsDOTA :: ProcessAction( CIncomingAction *Action ) return m_Winner != 0; } -void CStatsDOTA :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) +void CStatsDOTA :: Save( CGHost *GHost, CGHostDB *DB, quint32 GameID ) { if( DB->Begin( ) ) { @@ -396,7 +401,7 @@ void CStatsDOTA :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) { if( m_Players[i] ) { - uint32_t Colour = m_Players[i]->GetNewColour( ); + quint32 Colour = m_Players[i]->GetNewColour( ); if( !( ( Colour >= 1 && Colour <= 5 ) || ( Colour >= 7 && Colour <= 11 ) ) ) { @@ -429,7 +434,7 @@ void CStatsDOTA :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) } if( DB->Commit( ) ) - CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] saving " + UTIL_ToString( Players ) + " players" ); + CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] saving " + QString::number( Players ) + " players" ); else CONSOLE_Print( "[STATSDOTA: " + m_Game->GetGameName( ) + "] unable to commit database transaction, data not saved" ); } diff --git a/ghost/statsdota.h b/src/libghost/statsdota.h similarity index 85% rename from ghost/statsdota.h rename to src/libghost/statsdota.h index 8a4ce50..f8d3cb7 100644 --- a/ghost/statsdota.h +++ b/src/libghost/statsdota.h @@ -31,16 +31,16 @@ class CStatsDOTA : public CStats { private: CDBDotAPlayer *m_Players[12]; - uint32_t m_Winner; - uint32_t m_Min; - uint32_t m_Sec; + quint32 m_Winner; + quint32 m_Min; + quint32 m_Sec; public: CStatsDOTA( CBaseGame *nGame ); virtual ~CStatsDOTA( ); virtual bool ProcessAction( CIncomingAction *Action ); - virtual void Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ); + virtual void Save( CGHost *GHost, CGHostDB *DB, quint32 GameID ); }; #endif diff --git a/ghost/statsw3mmd.cpp b/src/libghost/statsw3mmd.cpp similarity index 58% rename from ghost/statsw3mmd.cpp rename to src/libghost/statsw3mmd.cpp index 638f386..b31533e 100644 --- a/ghost/statsw3mmd.cpp +++ b/src/libghost/statsw3mmd.cpp @@ -6,7 +6,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -26,11 +26,13 @@ #include "stats.h" #include "statsw3mmd.h" +#include + // // CStatsW3MMD // -CStatsW3MMD :: CStatsW3MMD( CBaseGame *nGame, string nCategory ) : CStats( nGame ) +CStatsW3MMD :: CStatsW3MMD( CBaseGame *nGame, QString nCategory ) : CStats( nGame ) { CONSOLE_Print( "[STATSW3MMD] using Warcraft 3 Map Meta Data stats parser version 1" ); CONSOLE_Print( "[STATSW3MMD] using map_statsw3mmdcategory [" + nCategory + "]" ); @@ -47,47 +49,45 @@ CStatsW3MMD :: ~CStatsW3MMD( ) bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) { unsigned int i = 0; - BYTEARRAY *ActionData = Action->GetAction( ); - BYTEARRAY MissionKey; - BYTEARRAY Key; - BYTEARRAY Value; + const QByteArray &ActionData = Action->GetAction( ); + QByteArray MissionKey; + QByteArray Key; + QByteArray Value; - while( ActionData->size( ) >= i + 9 ) + while( (unsigned int)ActionData.size( ) >= i + 9 ) { - if( (*ActionData)[i] == 'k' && - (*ActionData)[i + 1] == 'M' && - (*ActionData)[i + 2] == 'M' && - (*ActionData)[i + 3] == 'D' && - (*ActionData)[i + 4] == '.' && - (*ActionData)[i + 5] == 'D' && - (*ActionData)[i + 6] == 'a' && - (*ActionData)[i + 7] == 't' && - (*ActionData)[i + 8] == 0x00 ) + if( ActionData.at(i) == 'k' && + ActionData.at(i + 1) == 'M' && + ActionData.at(i + 2) == 'M' && + ActionData.at(i + 3) == 'D' && + ActionData.at(i + 4) == '.' && + ActionData.at(i + 5) == 'D' && + ActionData.at(i + 6) == 'a' && + ActionData.at(i + 7) == 't' && + ActionData.at(i + 8) == 0x00 ) { - if( ActionData->size( ) >= i + 10 ) + if( (unsigned int)ActionData.size( ) >= i + 10 ) { - MissionKey = UTIL_ExtractCString( *ActionData, i + 9 ); + MissionKey = UTIL_ExtractCString( ActionData, i + 9 ); - if( ActionData->size( ) >= i + 11 + MissionKey.size( ) ) + if( (unsigned int)ActionData.size( ) >= i + 11 + MissionKey.size( ) ) { - Key = UTIL_ExtractCString( *ActionData, i + 10 + MissionKey.size( ) ); + Key = UTIL_ExtractCString( ActionData, i + 10 + MissionKey.size( ) ); - if( ActionData->size( ) >= i + 15 + MissionKey.size( ) + Key.size( ) ) + if( (unsigned int)ActionData.size( ) >= i + 15 + MissionKey.size( ) + Key.size( ) ) { - Value = BYTEARRAY( ActionData->begin( ) + i + 11 + MissionKey.size( ) + Key.size( ), ActionData->begin( ) + i + 15 + MissionKey.size( ) + Key.size( ) ); - string MissionKeyString = string( MissionKey.begin( ), MissionKey.end( ) ); - string KeyString = string( Key.begin( ), Key.end( ) ); - uint32_t ValueInt = UTIL_ByteArrayToUInt32( Value, false ); + Value = ActionData.mid(i + 11 + MissionKey.size( ) + Key.size( ), 4 ); + //quint32 ValueInt = UTIL_QByteArrayToUInt32( Value, false ); - // CONSOLE_Print( "[STATSW3MMD] DEBUG: mkey [" + MissionKeyString + "], key [" + KeyString + "], value [" + UTIL_ToString( ValueInt ) + "]" ); + // CONSOLE_Print( "[STATSW3MMD] DEBUG: mkey [" + MissionKey + "], key [" + Key + "], value [" + QString::number(ValueInt) + "]" ); - if( MissionKeyString.size( ) > 4 && MissionKeyString.substr( 0, 4 ) == "val:" ) + if( MissionKey.size( ) > 4 && MissionKey.mid( 0, 4 ) == "val:" ) { - string ValueIDString = MissionKeyString.substr( 4 ); - uint32_t ValueID = UTIL_ToUInt32( ValueIDString ); - vector Tokens = TokenizeKey( KeyString ); + //QByteArray ValueIDString = MissionKey.mid( 4 ); + //quint32 ValueID = UTIL_ToUInt32( ValueIDString ); + QList Tokens = TokenizeKey( Key ); - if( !Tokens.empty( ) ) + if( !Tokens.isEmpty( ) ) { if( Tokens[0] == "init" && Tokens.size( ) >= 2 ) { @@ -98,7 +98,7 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] map is using Warcraft 3 Map Meta Data library version [" + Tokens[3] + "]" ); - if( UTIL_ToUInt32( Tokens[2] ) > 1 ) + if( Tokens[2].toUInt() > 1 ) CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] warning - parser version 1 is not compatible with this map, minimum version [" + Tokens[2] + "]" ); } else if( Tokens[1] == "pid" && Tokens.size( ) == 4 ) @@ -106,7 +106,7 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) // Tokens[2] = pid // Tokens[3] = name - uint32_t PID = UTIL_ToUInt32( Tokens[2] ); + quint32 PID = Tokens[2].toUInt(); if( m_PIDToName.find( PID ) != m_PIDToName.end( ) ) CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] overwriting previous name [" + m_PIDToName[PID] + "] with new name [" + Tokens[3] + "] for PID [" + Tokens[2] + "]" ); @@ -122,13 +122,13 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) // Tokens[4] = suggestion (ignored here) if( m_DefVarPs.find( Tokens[1] ) != m_DefVarPs.end( ) ) - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] duplicate DefVarP [" + KeyString + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] duplicate DefVarP [" + Key + "] found, ignoring" ); else { - if( Tokens[2] == "int" || Tokens[2] == "real" || Tokens[2] == "string" ) + if( Tokens[2] == "int" || Tokens[2] == "real" || Tokens[2] == "QString" ) m_DefVarPs[Tokens[1]] = Tokens[2]; else - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown DefVarP [" + KeyString + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown DefVarP [" + Key + "] found, ignoring" ); } } @@ -140,77 +140,77 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) // Tokens[4] = value if( m_DefVarPs.find( Tokens[2] ) == m_DefVarPs.end( ) ) - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] VarP [" + KeyString + "] found without a corresponding DefVarP, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] VarP [" + Key + "] found without a corresponding DefVarP, ignoring" ); else { - string ValueType = m_DefVarPs[Tokens[2]]; + QString ValueType = m_DefVarPs[Tokens[2]]; if( ValueType == "int" ) { - VarP VP = VarP( UTIL_ToUInt32( Tokens[1] ), Tokens[2] ); + VarP VP = VarP( Tokens[1].toUInt(), Tokens[2] ); if( Tokens[3] == "=" ) - m_VarPInts[VP] = UTIL_ToInt32( Tokens[4] ); + m_VarPInts[VP] = Tokens[4].toInt(); else if( Tokens[3] == "+=" ) { if( m_VarPInts.find( VP ) != m_VarPInts.end( ) ) - m_VarPInts[VP] += UTIL_ToInt32( Tokens[4] ); + m_VarPInts[VP] += Tokens[4].toInt(); else { - // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] int VarP [" + KeyString + "] found with relative operation [+=] without a previously assigned value, ignoring" ); - m_VarPInts[VP] = UTIL_ToInt32( Tokens[4] ); + // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] int VarP [" + Key + "] found with relative operation [+=] without a previously assigned value, ignoring" ); + m_VarPInts[VP] = Tokens[4].toInt(); } } else if( Tokens[3] == "-=" ) { if( m_VarPInts.find( VP ) != m_VarPInts.end( ) ) - m_VarPInts[VP] -= UTIL_ToInt32( Tokens[4] ); + m_VarPInts[VP] -= Tokens[4].toInt(); else { - // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] int VarP [" + KeyString + "] found with relative operation [-=] without a previously assigned value, ignoring" ); - m_VarPInts[VP] = -UTIL_ToInt32( Tokens[4] ); + // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] int VarP [" + Key + "] found with relative operation [-=] without a previously assigned value, ignoring" ); + m_VarPInts[VP] = -Tokens[4].toInt(); } } else - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown int VarP [" + KeyString + "] operation [" + Tokens[3] + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown int VarP [" + Key + "] operation [" + Tokens[3] + "] found, ignoring" ); } else if( ValueType == "real" ) { - VarP VP = VarP( UTIL_ToUInt32( Tokens[1] ), Tokens[2] ); + VarP VP = VarP( Tokens[1].toUInt(), Tokens[2] ); if( Tokens[3] == "=" ) - m_VarPReals[VP] = UTIL_ToDouble( Tokens[4] ); + m_VarPReals[VP] = Tokens[4].toDouble(); else if( Tokens[3] == "+=" ) { if( m_VarPReals.find( VP ) != m_VarPReals.end( ) ) - m_VarPReals[VP] += UTIL_ToDouble( Tokens[4] ); + m_VarPReals[VP] += Tokens[4].toDouble(); else { - // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] real VarP [" + KeyString + "] found with relative operation [+=] without a previously assigned value, ignoring" ); - m_VarPReals[VP] = UTIL_ToDouble( Tokens[4] ); + // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] real VarP [" + Key + "] found with relative operation [+=] without a previously assigned value, ignoring" ); + m_VarPReals[VP] = Tokens[4].toDouble(); } } else if( Tokens[3] == "-=" ) { if( m_VarPReals.find( VP ) != m_VarPReals.end( ) ) - m_VarPReals[VP] -= UTIL_ToDouble( Tokens[4] ); + m_VarPReals[VP] -= Tokens[4].toDouble(); else { - // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] real VarP [" + KeyString + "] found with relative operation [-=] without a previously assigned value, ignoring" ); - m_VarPReals[VP] = -UTIL_ToDouble( Tokens[4] ); + // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] real VarP [" + Key + "] found with relative operation [-=] without a previously assigned value, ignoring" ); + m_VarPReals[VP] = -Tokens[4].toDouble(); } } else - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown real VarP [" + KeyString + "] operation [" + Tokens[3] + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown real VarP [" + Key + "] operation [" + Tokens[3] + "] found, ignoring" ); } else { - VarP VP = VarP( UTIL_ToUInt32( Tokens[1] ), Tokens[2] ); + VarP VP = VarP( Tokens[1].toUInt(), Tokens[2]); if( Tokens[3] == "=" ) m_VarPStrings[VP] = Tokens[4]; else - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown string VarP [" + KeyString + "] operation [" + Tokens[3] + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown QString VarP [" + Key + "] operation [" + Tokens[3] + "] found, ignoring" ); } } } @@ -221,7 +221,7 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) if( Tokens[2] == "winner" || Tokens[2] == "loser" || Tokens[2] == "drawer" || Tokens[2] == "leaver" || Tokens[2] == "practicing" ) { - uint32_t PID = UTIL_ToUInt32( Tokens[1] ); + quint32 PID = Tokens[1].toUInt(); if( Tokens[2] == "leaver" ) m_FlagsLeaver[PID] = true; @@ -246,13 +246,13 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) // Tokens[n+3] = format if( m_DefEvents.find( Tokens[1] ) != m_DefEvents.end( ) ) - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] duplicate DefEvent [" + KeyString + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] duplicate DefEvent [" + Key + "] found, ignoring" ); else { - uint32_t Arguments = UTIL_ToUInt32( Tokens[2] ); + quint32 Arguments = Tokens[2].toUInt(); - if( Tokens.size( ) == Arguments + 4 ) - m_DefEvents[Tokens[1]] = vector( Tokens.begin( ) + 3, Tokens.end( ) ); + if( (unsigned int)Tokens.size( ) == Arguments + 4 ) + m_DefEvents[Tokens[1]] = Tokens.mid(3); } } else if( Tokens[0] == "Event" && Tokens.size( ) >= 2 ) @@ -261,38 +261,38 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) // Tokens[2..n+2] = arguments (where n is the # of arguments in the corresponding DefEvent) if( m_DefEvents.find( Tokens[1] ) == m_DefEvents.end( ) ) - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] Event [" + KeyString + "] found without a corresponding DefEvent, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] Event [" + Key + "] found without a corresponding DefEvent, ignoring" ); else { - vector DefEvent = m_DefEvents[Tokens[1]]; + QList DefEvent = m_DefEvents[Tokens[1]]; - if( !DefEvent.empty( ) ) + if( !DefEvent.isEmpty( ) ) { - string Format = DefEvent[DefEvent.size( ) - 1]; + QString Format = DefEvent[DefEvent.size( ) - 1]; if( Tokens.size( ) - 2 != DefEvent.size( ) - 1 ) - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] Event [" + KeyString + "] found with " + UTIL_ToString( Tokens.size( ) - 2 ) + " arguments but expected " + UTIL_ToString( DefEvent.size( ) - 1 ) + " arguments, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] Event [" + Key + "] found with " + QString::number( Tokens.size( ) - 2 ) + " arguments but expected " + QString::number(DefEvent.size() - 1 ) + " arguments, ignoring" ); else { - // replace the markers in the format string with the arguments + // replace the markers in the format QString with the arguments - for( uint32_t i = 0; i < Tokens.size( ) - 2; i++ ) + for( int i = 0; i < Tokens.size( ) - 2; i++ ) { // check if the marker is a PID marker - if( DefEvent[i].substr( 0, 4 ) == "pid:" ) + if( DefEvent[i].mid( 0, 4 ) == "pid:" ) { // replace it with the player's name rather than their PID - uint32_t PID = UTIL_ToUInt32( Tokens[i + 2] ); + quint32 PID = Tokens[i + 2].toUInt(); if( m_PIDToName.find( PID ) == m_PIDToName.end( ) ) - UTIL_Replace( Format, "{" + UTIL_ToString( i ) + "}", "PID:" + Tokens[i + 2] ); + Format.replace( "{" + QString::number(i) + "}", "PID:" + Tokens[i + 2] ); else - UTIL_Replace( Format, "{" + UTIL_ToString( i ) + "}", m_PIDToName[PID] ); + Format.replace( "{" + QString::number(i) + "}", m_PIDToName[PID] ); } else - UTIL_Replace( Format, "{" + UTIL_ToString( i ) + "}", Tokens[i + 2] ); + Format.replace( "{" + QString::number(i) + "}", Tokens[i + 2] ); } CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] " + Format ); @@ -300,7 +300,7 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) } } - // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] event [" + KeyString + "]" ); + // CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] event [" + Key + "]" ); } else if( Tokens[0] == "Blank" ) { @@ -308,7 +308,7 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) } else if( Tokens[0] == "Custom" ) { - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] custom [" + KeyString + "]" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] custom [" + Key + "]" ); } else CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown message type [" + Tokens[0] + "] found, ignoring" ); @@ -316,17 +316,17 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) m_NextValueID++; } - else if( MissionKeyString.size( ) > 4 && MissionKeyString.substr( 0, 4 ) == "chk:" ) + else if( MissionKey.size( ) > 4 && MissionKey.mid( 0, 4 ) == "chk:" ) { - string CheckIDString = MissionKeyString.substr( 4 ); - uint32_t CheckID = UTIL_ToUInt32( CheckIDString ); + QString CheckIDString = MissionKey.mid( 4 ); + //quint32 CheckID = UTIL_ToUInt32( CheckIDString ); // todotodo: cheat detection m_NextCheckID++; } else - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown mission key [" + MissionKeyString + "] found, ignoring" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unknown mission key [" + MissionKey + "] found, ignoring" ); i += 15 + MissionKey.size( ) + Key.size( ); } @@ -346,52 +346,52 @@ bool CStatsW3MMD :: ProcessAction( CIncomingAction *Action ) return false; } -void CStatsW3MMD :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) +void CStatsW3MMD :: Save( CGHost *GHost, CGHostDB *DB, quint32 GameID ) { - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] received " + UTIL_ToString( m_NextValueID ) + "/" + UTIL_ToString( m_NextCheckID ) + " value/check messages" ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] received " + QString::number(m_NextValueID) + "/" + QString::number(m_NextCheckID) + " value/check messages" ); if( DB->Begin( ) ) { // todotodo: there's no reason to create a new callable for each entry in this map // rewrite ThreadedW3MMDPlayerAdd to act more like ThreadedW3MMDVarAdd - for( map :: iterator i = m_PIDToName.begin( ); i != m_PIDToName.end( ); i++ ) + for( QMap :: const_iterator i = m_PIDToName.begin( ); i != m_PIDToName.end( ); i++ ) { - string Flags = m_Flags[i->first]; - uint32_t Leaver = 0; - uint32_t Practicing = 0; + QString Flags = m_Flags[i.key()]; + quint32 Leaver = 0; + quint32 Practicing = 0; - if( m_FlagsLeaver.find( i->first ) != m_FlagsLeaver.end( ) && m_FlagsLeaver[i->first] ) + if( m_FlagsLeaver.find( i.key() ) != m_FlagsLeaver.end( ) && m_FlagsLeaver[i.key()] ) { Leaver = 1; - if( !Flags.empty( ) ) + if( !Flags.isEmpty( ) ) Flags += "/"; Flags += "leaver"; } - if( m_FlagsPracticing.find( i->first ) != m_FlagsPracticing.end( ) && m_FlagsPracticing[i->first] ) + if( m_FlagsPracticing.find( i.key() ) != m_FlagsPracticing.end( ) && m_FlagsPracticing[i.key()] ) { Practicing = 1; - if( !Flags.empty( ) ) + if( !Flags.isEmpty( ) ) Flags += "/"; Flags += "practicing"; } - CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] recorded flags [" + Flags + "] for player [" + i->second + "] with PID [" + UTIL_ToString( i->first ) + "]" ); - GHost->m_Callables.push_back( DB->ThreadedW3MMDPlayerAdd( m_Category, GameID, i->first, i->second, m_Flags[i->first], Leaver, Practicing ) ); + CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] recorded flags [" + Flags + "] for player [" + i.value() + "] with PID [" + QString::number( i.key() ) + "]" ); + GHost->m_Callables.push_back( DB->ThreadedW3MMDPlayerAdd( m_Category, GameID, i.key(), i.value(), m_Flags[i.key()], Leaver, Practicing ) ); } - if( !m_VarPInts.empty( ) ) + if( !m_VarPInts.isEmpty( ) ) GHost->m_Callables.push_back( DB->ThreadedW3MMDVarAdd( GameID, m_VarPInts ) ); - if( !m_VarPReals.empty( ) ) + if( !m_VarPReals.isEmpty( ) ) GHost->m_Callables.push_back( DB->ThreadedW3MMDVarAdd( GameID, m_VarPReals ) ); - if( !m_VarPStrings.empty( ) ) + if( !m_VarPStrings.isEmpty( ) ) GHost->m_Callables.push_back( DB->ThreadedW3MMDVarAdd( GameID, m_VarPStrings ) ); if( DB->Commit( ) ) @@ -403,13 +403,15 @@ void CStatsW3MMD :: Save( CGHost *GHost, CGHostDB *DB, uint32_t GameID ) CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] unable to begin database transaction, data not saved" ); } -vector CStatsW3MMD :: TokenizeKey( string key ) +QList CStatsW3MMD :: TokenizeKey( const QByteArray& key ) { - vector Tokens; - string Token; + QList Tokens; + QByteArray Token; bool Escaping = false; - for( string :: iterator i = key.begin( ); i != key.end( ); i++ ) + for( QByteArray::const_iterator i = key.begin(); + i != key.end(); + i++ ) { if( Escaping ) { @@ -420,7 +422,7 @@ vector CStatsW3MMD :: TokenizeKey( string key ) else { CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] error tokenizing key [" + key + "], invalid escape sequence found, ignoring" ); - return vector( ); + return QList( ); } Escaping = false; @@ -429,10 +431,10 @@ vector CStatsW3MMD :: TokenizeKey( string key ) { if( *i == ' ' ) { - if( Token.empty( ) ) + if( Token.isEmpty( ) ) { CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] error tokenizing key [" + key + "], empty token found, ignoring" ); - return vector( ); + return QList( ); } Tokens.push_back( Token ); @@ -445,10 +447,10 @@ vector CStatsW3MMD :: TokenizeKey( string key ) } } - if( Token.empty( ) ) + if( Token.isEmpty( ) ) { CONSOLE_Print( "[STATSW3MMD: " + m_Game->GetGameName( ) + "] error tokenizing key [" + key + "], empty token found, ignoring" ); - return vector( ); + return QList( ); } Tokens.push_back( Token ); diff --git a/src/libghost/statsw3mmd.h b/src/libghost/statsw3mmd.h new file mode 100644 index 0000000..2cfb8a8 --- /dev/null +++ b/src/libghost/statsw3mmd.h @@ -0,0 +1,56 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef STATSW3MMD_H +#define STATSW3MMD_H + +// +// CStatsW3MMD +// + +#include +typedef QPair VarP; + +class CStatsW3MMD : public CStats +{ +private: + QString m_Category; + quint32 m_NextValueID; + quint32 m_NextCheckID; + QMap m_PIDToName; // pid -> player name (e.g. 0 -> "Varlock") --- note: will not be automatically converted to lower case + QMap m_Flags; // pid -> flag (e.g. 0 -> "winner") + QMap m_FlagsLeaver; // pid -> leaver flag (e.g. 0 -> true) --- note: will only be present if true + QMap m_FlagsPracticing; // pid -> practice flag (e.g. 0 -> true) --- note: will only be present if true + QMap m_DefVarPs; // varname -> value type (e.g. "kills" -> "int") + QMap m_VarPInts; // pid,varname -> value (e.g. 0,"kills" -> 5) + QMap m_VarPReals; // pid,varname -> value (e.g. 0,"x" -> 0.8) + QMap m_VarPStrings; // pid,varname -> value (e.g. 0,"hero" -> "heroname") + QMap > m_DefEvents; // event -> vector of arguments + format + +public: + CStatsW3MMD( CBaseGame *nGame, QString nCategory ); + virtual ~CStatsW3MMD( ); + + virtual bool ProcessAction( CIncomingAction *Action ); + virtual void Save( CGHost *GHost, CGHostDB *DB, quint32 GameID ); + virtual QList TokenizeKey( const QByteArray& key ); +}; + +#endif diff --git a/src/libghost/ttmath/CHANGELOG b/src/libghost/ttmath/CHANGELOG new file mode 100644 index 0000000..c280246 --- /dev/null +++ b/src/libghost/ttmath/CHANGELOG @@ -0,0 +1,498 @@ +Version 0.9.1 (2010.02.07): + * fixed: the parser didn't use characters for changing the base (# and &) + those characters were skipped + (this bug was introduced in 0.9.0) + * fixed: added in the parser: operator's associativity + operator ^ (powering) is right-associative: + sample: 2^3^4 is equal 2^(3^4) and it is: 2.41e+24 + previously was: 2^3^4 = (2^3)^4 = 4096 + * fixed: in Big::ToString_CreateNewMantissaAndExponent() changed the formula: + new_exp_ = [log base (2^exponent)] + 1 + now the part '+ 1' is only made when the logarithm is positive and with fraction + if the value is negative we can only skip the fraction, previously + we lost some last digits from the new mantissa + Consider this binary value (32 bit mantissa): + (bin)1.0000000000000000000000000000011 + previously ToString() gave 1, now we have: 1.000000001 + * changed: in Big::ToString() the base rounding is made only if the result value + would not be an integer, e.g. if the value is 1.999999999999 then + the base rounding will not be done - because as the result would be 2 + * added: IEEE 754 half-to-even rounding (bankers' rounding) to the following + floating point algorithms: Big::Add, Big::Sub, Big::Mul, Big::Div + * added: static sint UInt::FindLowestBitInWord(uint x) + this method is looking for the lowest set bit in a word + * added: UInt::FindLowestBit(uint & table_id, uint & index) + this method is looking for the lowest set bit + + +Version 0.9.0 (2009.11.25): + * added: support for wide characters (wchar_t, std::wstring) + * added: Big::IsInteger() + returns true if the value is integer (without fraction) + (NaN flag is not checked) + * added: global Gamma() function + * added: gamma() function to the parser + * added: CGamma class + is used with Gamma() and Factorial() in multithreaded environment + * added: multithread support for Big<> class + you should compile with TTMATH_MULTITHREADS + and use TTMATH_MULTITHREADS_HELPER macro somewhere in your *.cpp file + * added: x86_64 asm code for Microsoft Visual compiler + file: ttmathuint_x86_64_msvc.asm + (this file should be compiled first because MS VC doesn't support inline assembler in x86_64 mode) + * added: flag TTMATH_BIG_ZERO to Big<> class + if this flag is set then there is a value zero + Big::IsZero() is faster now + * added: Big::ClearInfoBit(unsigned char) + Big::SetInfoBit(unsigned char) + Big::IsInfoBit(unsigned char) + some methods for manipulating the info flags + * added: macro: TTMATH_BITS(min_bits) + which returns the number of machine words + capable to hold min_bits bits + * added: bool Parser::Calculated() + this method returns true is something was calculated + (at least one mathematical operator was used or a function or variable) + * added: to the parser: operator percentage + e.g. 1000-50%=1000-(1000*0,5)=500 + * added: struct: Conv + consists of some parameters used + in ToString() and FromString() + * added: Big::ToString() can group digits + e.g. 1234567 -> 1`234`567 + * added: Parser::SetGroup(int g) + Parser::SetComma(int c, int c2 = 0) + Parser::SetParamSep(int s) + * added: std::string UInt::ToString(uint b = 10) + std::wstring UInt::ToWString(uint b = 10) + std::string Int::ToString(uint b = 10) + std::wstring Int::ToWString(uint b = 10) + uint Big::ToString(std::string & result, const Conv & conv) + uint Big::ToString(std::wstring & result, const Conv & conv) + std::string Big::ToString(const Conv & conv) + std::string Big::ToString() + std::wstring Big::ToWString(const Conv & conv) + std::wstring Big::ToWString() + * added: uint FromString(const char * source, const Conv & conv, const char **, bool *) + uint FromString(const wchar_t * source, const Conv & conv, const wchar_t **, bool *) + uint FromString(const std::string & string, const Conv & conv, const wchar_t **, bool *) + uint FromString(const std::wstring & string, const Conv & conv, const wchar_t **, bool *) + * added: UInt::Sqrt() - a new algorithm for calculating the square root + * added: to the parser: function frac() - returns a value without the integer part + (only fraction remains) + * added: Int::DivInt(sint divisor, sint * remainder) + * added: const char * UInt::LibTypeStr() + const char * Big::LibTypeStr() + LibTypeCode UInt::LibType() + LibTypeCode Big::LibType() + returning a string/enum represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + * added: UInt::operator>>(int) + UInt::operator>>=(int) + UInt::operator<<(int) + UInt::operator<<=(int) + * changed: Factorial() is using the Gamma() function now + * changed: Big::Div(ss2) + Big::Mod(ss2) + they return 2 when ss2 is zero + previously returned 1 + * changed: algorithms in Big::Sqrt() and ttmath::Root(x ; n) + they were not too much accurate for some integers + e.g. Root(16;4) returned a value very closed to 2 (not exactly 2) + * changed: added specializations to Big::ToString() when the base is equal 4, 8 or 16 + the previous version was not accurate on some last digits (after the comma operator) + consider this binary value (32 bit mantissa): + base 2: 1.1111 1111 1111 1111 1111 1111 1110 101 + previous ToString() gave: + base 4: 1.33333333333332 + base 8: 1.777777777 + base 16: 1.FFFFFF + now we have: + base 4: 1.3333333333333222 + base 8: 1.77777777724 + base 16: 1.FFFFFFEA + * changed: in Big::ToString() some additional rounding (base_round) is now made only + when the value is not an integer + * changed: another compilers than MS VC or GCC by default use no asm version (TTMATH_NOASM) + * removed: Parser<>::SetFactorialMax() method + the factorial() is such a fast now that we don't need the method longer + * removed: ErrorCode::err_too_big_factorial + * removed: macros: TTMATH_COMMA_CHARACTER_1 and TTMATH_COMMA_CHARACTER_2 + the comma characters we have in Conv struct now + + +Version 0.8.6 (2009.10.25): + * fixed: UInt::SetBitInWord(uint & value, uint bit) set 1 if the bit was + equal 1 (should be set 2) + this affected only no-asm parts - when macro TTMATH_NOASM was defined + * fixed: UInt::MulInt(uint ss2) + there was a buffer overflow when value_size was equal 1 + * fixed: UInt::AddVector() and UInt::SubVector() didn't want to compile + when macro TTMATH_NOASM was defined + * fixed: Big::operator>> didn't correctly recognize values in scientific mode (with 'e' character) + * fixed: Int::FromString(const tt_string & s, uint b = 10) + didn't use 'b' (always was '10') + * fixed: buffer overflow in Big::ToInt(Int & result) + * fixed: powering algorithm in: + UInt::Pow(UInt pow) + Big::Pow(UInt pow) + Big::PowUInt(Big pow) + when 'pow' was sufficient large the algorithm returned carry + but the result could have been calculated correctly + + +Version 0.8.5 (2009.06.16): + * fixed: Big::Mod(x) didn't correctly return a carry + and the result was sometimes very big (even greater than x) + * fixed: global function Mod(x) didn't set an ErrorCode object + * fixed: global function Round() didn't test a carry + now it sets ErrorCode object + * changed: function Sin(x) to Sin(x, ErrorCode * err=0) + when x was very big the function returns zero + now it sets ErrorCode object to err_overflow + and the result has a NaN flag set + the same is to Cos() function + * changed: PrepareSin(x) is using Big::Mod() now when reducing 2PI period + should be a little accurate especially on a very big 'x' + * changed: uint Mul(const UInt & ss2, uint algorithm = 100) + void MulBig(const UInt & ss2, UInt & result, uint algorithm = 100) + those methods by default use MulFastest() and MulFastestBig() + * changed: changed a little Mul2Big() to cooperate with Mul3Big() + * added: uint UInt::Mul3(const UInt & ss2) + void UInt::Mul3Big(const UInt & ss2, UInt & result) + a new multiplication algorithm: Karatsuba multiplication, + on a vector UInt<100> with all items different from zero this algorithm is faster + about 3 times than Mul2Big(), and on a vector UInt<1000> with all items different from + zero this algorithm is faster more than 5 times than Mul2Big() + (measured on 32bit platform with GCC 4.3.3 with -O3 and -DTTMATH_RELEASE) + * added: uint MulFastest(const UInt & ss2) + void MulFastestBig(const UInt & ss2, UInt & result) + those methods are trying to select the fastest multiplication algorithm + * added: uint AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + uint SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + three forms: asm x86, asm x86_64, no-asm + those methods are used by the Karatsuba multiplication algorithm + * added: to Big<> class: support for NaN flag (Not a Number) + bool Big::IsNan() - returns true if the NaN flag is set + void Big::SetNan() - sets the NaN flag + The NaN flag is set by default after creating an object: + Big<1, 2> a; // NaN is set (it means the object has not a valid number) + std::cout << a; // cout gives "NaN" + a = 123; // now NaN is not set + std::cout << a; // cout gives "123" + The NaN is set if there was a carry during calculations + a.Mul(very_big_value); // a will have a NaN set + The NaN is set if an argument is NaN too + b.SetNan(); + a.Add(b); // a will have NaN because b has NaN too + If you try to do something on a NaN object, the result is a NaN too + a.SetNan(); + a.Add(2); // a is still a NaN + The NaN is set if you use incorrect arguments + a.Ln(-10); // a will have the NaN flag + The only way to clear the NaN flag is to assign a correct value or other correct object, + supposing 'a' has NaN flag, to remove the flag you can either: + a = 10; + a.FromInt(30); + a.SetOne(); + a.FromBig(other_object_without_nan); + etc. + + +Version 0.8.4 (2009.05.08): + * fixed: UInt::DivInt() didn't check whether the divisor is zero + there was a hardware interruption when the divisor was zero + (now the method returns one) + * fixed: the problem with GCC optimization on x86_64 + sometimes when using -O2 or -O3 GCC doesn't set correctly + the stack pointer (actually the stack is used for other things) + and you can't use instructions like push/pop in assembler code. + All the asm code in x86_64 have been rewritten, now instructions + push/pop are not used, other thing which have access to stack + (like "m" (mask) constraints in Rcl2 and Rcr2) have also gone away, + now the library works well with -O2 and -O3 and the asm code + is a little faster + * added: UInt::PrintLog(const char * msg, std::ostream & output) + used (for debugging purposes) by macro TTMATH_LOG(msg) + (it is used in nearly all methods in UInt class) + * added: macro TTMATH_DEBUG_LOG: when defined then TTMATH_LOG() + put some debug information (to std::cout) + * added: ttmathuint_x86.h, ttmathuint_x86_64.h, ttmathuint_noasm.h, + all the methods which are using assembler code have been + rewritten to no-asm forms, now we have: + 1. asm for x86 file: ttmathuint_x86.h + 2. asm for x86_64 file: ttmathuint_x86_64.h + 3. no asm file: ttmathuint_noasm.h + (it's used when macro TTMATH_NOASM is defined) + The third form can be used on x86 and x86_64 as well and + on other platforms with a little effort. + + +Version 0.8.3 (2009.04.06): + * fixed: RclMoveAllWords() and RcrMoveAllWords() sometimes didn't return + the proper carry, (when 'bits' was greater than or equal to 'value_size') + this had impact on Rcl() and Rcr(), they also returned the wrong carry + * fixed: UInt::Div() didn't return a correct result when the divisor was equal 1 + there was an error in UInt::DivInt() - when the divisor was 1 it returned + zero and the carry was set + * fixed: there was a TTMATH_REREFENCE_ASSERT error in Big::PowUInt() caused by: start.Mul(start) + * fixed: Big::Add incorrectly rounded 'this' when both exponents were equal + it caused that sometimes when adding a zero the result has changed + this had impact among other things on FromString() method + "0,8" had different binary representation from "0,80" + * fixed: template Big::FromBig(const Big & another) + didn't correctly set the exponent (when the mantisses had different size - + when 'man' was different from 'another_man') + this had impact on operator= too + sample: + Big<2,3> a = 100; + Big<3,5> b; + b = a; // b had a wrong value + * fixed: Big::Pow(const Big & pow) + it's using PowInt() only when pow.exponent is in range (-man*TTMATH_BITS_PER_UINT; 0] + previously the powering 'hung' on an input like this: "(1+ 1e-10000) ^ 10e100000000" + (there was 10e100000000 iterations in PowInt()) + * fixed: in function DegToRad(const ValueType & x, ErrorCode * err = 0) it is better + to make division first and then mutliplication -- the result is more + accurate especially when x is: 90,180,270 or 360 + * fixed: the parser didn't correctly treat operators for changing the base + (radix) -- operators '#' and '&', e.g.: + '#sin(1)' was equal '0' -- there was a zero from '#' and then + it was multipied by 'sin(1)' + the parser didn't check whether Big::FromString() has actually + read a proper value -- the method Big::FromString() didn't have + something to report such a situation + * fixed: Big::FromString() when the base is 10, the method reads the scientific + part only if such a part it correctly supplied, e.g: + '1234e10', '1234e+10', '1234e-5' + previous '1234e' was treated as: '1234e0' (now parsing stops on 'e' and + the 'e' can be parsed by other parsers, e.g. the mathematical + parser -- now in the parser would be: '1234e' = '1234 * e' = '3354,3597...' ) + * changed: renamed: Big::PowUInt(UInt pow) -> Big::Pow(UInt pow) + it returns 2 when there is: 0^0 + * changed: renamed: Big::PowInt(Int pow) -> Big::Pow(Int pow) + it returns 2 when there is: 0^0 or 0^(-something) + * changed: renamed: Big::PowBUInt() -> PowUInt(), Big::PowBInt() -> Big::PowInt() + they return 2 when the arguments are incorrect (like above) + * changed: UInt::SetBitInWord(uint & value, uint bit) is taking the first argument by a reference now, + the specific bit is set in the 'value' and the method returns the last state of the bit (zero or one) + * changed: UInt::SetBit(uint bit_index) - it's using TTMATH_ASSERT now + * changed: the size of built-in variables (constants) in ttmathbig.h + now they consist of 256 32bit words + macro TTMATH_BUILTIN_VARIABLES_SIZE is equal: 256u on a 32bit platform and 128ul on a 64bit platform + * changed: the asm code in ttmathuint.h and ttmathuint64.h has been completely rewritten + now UInt<> is faster about 15-30% than UInt<> from 0.8.2 + this has impact on Big<> too - it's faster about 10% now + * changed: in the parser: the form with operators '#' and '&' is as follows: + [-|+][#|&]numeric_value + previous was: [-|+][#|&][-|+]numeric_value + * changed: in the parser: the short form of multiplication has the same + priority as the normal multiplication, e.g.: + '2x^3' = 2 * (x^3) + previous the priority was greater than powering priority + previous: '2x^3' = (2*x) ^ 3 + * added: UInt::GetBit(uint bit_index) - returning the state of the specific bit + * added: Big::operator=(double) and Big::Big(double) + * added: UInt::Pow(UInt pow) and Int::Pow(Int pow) + * added: global template functions in ttmath.h: + ValueType GradToRad(const ValueType & x, ErrorCode * err = 0) + ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0) + ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0) + ValueType DegToGrad(const ValueType & d, const ValueType & m, + const ValueType & s, ErrorCode * err = 0) + ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0) + * added: Parser::SetDegRadGrad(int angle) - 0 deg, 1 rad (default), 2 grad + this affects following functions (in the parser only): sin, cos, tan, cot, + asin, acos, atan, acot + * added: functions to the parser: gradtorad(grad), radtograd(rad), degtograd(deg), + degtograd(d,m,s), gradtodeg(grad) + * added: UInt::FromString, added a parametr 'after_source' + which is pointing at the end of the parsed string + * added: Int::FromString(): parameter 'const char ** after_source = 0' + if exists it's pointing at the end of the parsed string + * added: to UInt::FromString(), Int::FromString(), Big::FromString(): + parameter 'bool * value_read = 0' - (if exists) tells + whether something has actually been read (at least one digit) + * added: Objects::IsDefined(const std::string & name) + returning true if such an object is defined + * removed: Big::FromString() this method doesn't longer recognize operators + for changing the base ('#' and '&') + + +Version 0.8.2 (2008.06.18): + * added: UInt::BitNot2() this method has been proposed by + Arek + * changed: Int::FromInt(const Int & p), + Int::FromInt(sint value) (it returns zero now) + Int::operator=(uint i) + Int::Int(uint i) + * added: Int::FromUInt(const UInt & p), + Int::FromUInt(uint value) + and appropriate constructors and assignment + operators as well + * changed: Big::FromInt(Int value), + * added: Big::FromUInt(UInt value), + Big::operator=(const UInt & value) + Big::Big(const UInt & value) + * changed: the parser is allowed to recognize values which + begin with a dot, e.g '.5' is treated as '0.5' + * added: a method Big::FromDouble(double) which converts from + standard double into a Big + * added: uint Big::ToDouble(double&) - converting into double + * added: Big::FromBig() and an operator= and a contructor + for converting from another kind of a Big class + * added: to the parser: avg(), sum() + * added: 'decimal_point' parameter into Big::ToString(...) + * fixed: Big::operator>> didn't use TTMATH_COMMA_CHARACTER_2 macro + * added: a short form of multiplication (without the '*' character) + e.g. '5y', (it's used only if the second parameter + is a variable or function) + * changed: variables and functions are case-sensitive now + * added: variables and functions can have underline characters + in their names + * changed: 'max_digit_after_comma' in Big::ToString() + remove the -2 state + * added: 'remove_trailing_zeroes' in Big::ToString() + it's either true or false + * fixed/changed: the way of using Big::SetSign() + the method do not check whether there is a zero or not now + (even if there's a zero the method can set a sign bit) + I changed this due to some prior errors + (errors corrected in revision 17, 49 and 58) + + +Version 0.8.1 (2007.04.17): + * fixed: Big::PowFrac(..) didn't return a correct error code + (when 'this' was negative) + * added: Root(x; index) (and to the parser as well) + * added: macro: TTMATH_PRERELEASE_VER (can be either zero or one) + * added: UInt::MulInt(int, UInt::&) + * added: Big::MulUInt(uint) + * changed: Big::MulInt(sint) + * added: Big::ToUInt(uint &) + * changed: Big::ToInt(sint&) + * changed: Factorial() it uses Big::MulUInt() at the beginning + (faster now especially more on a 32bit platform) + * added: doxygen.cfg for generating a documentation from the doxygen + * changed: UInt::Rcl(uint c=0) and UInt::Rcr(uint c=0) into + UInt::Rcl2(uint bits, uint c) and UInt::Rcr2(uint bits, uint c) + now they can move more than one bit and they are only private + * fixed: UInt::Rcl(uint bits, uint c) and UInt::Rcr(uint bits, uint c) + didn't correctly return a carry if the 'bits' were equal + to 'value_size*TTMATH_BITS_PER_UINT' + * changed: UInt::Rcl(uint bits, uint c) and UInt::Rcr(uint bits, uint c) + into UInt::Rcl(uint bits, uint c=0) and + UInt::Rcr(uint bits, uint c=0) + they are faster now when the bits is greater than a half of + the TTMATH_BITS_PER_UINT + * changed: UInt::CompensationToLeft() it's faster now + * changed: more small changes where there were UInt::Rcl(uint c=0) and + UInt::Rcr(uint c=0) used + * changed: as the Big type uses UInt::Rcl() and UInt::Rcr() a lot then + it is much faster now (about 5-25%) + * added: ASinh(), ACosh(), ATanh() /ATgh()/, ACoth() /ACtgh()/ + and to the parser as well + * added: UInt::BitAnd(), UInt::BitOr(), UInt::BitXor(), UInt::BitNot(), + Big::BitAnd(), Big::BitOr(), Big::BitXor() + * added: to the parser: bitand(), bitor(), bitxor() + /band(), bor(), bxor()/ + * changed: the way of parsing operators in the mathematical parser + (the parser is not too much greedy now) + + +Version 0.8.0 (2007.03.28): + * added: into the parser: SetFactorialMax() + * added: DegToDeg(deg, min, sec), DegToRad(deg), DegToRad(deg, min, sec), + RadToDeg(rad), Ceil(x), Floor(x), Sqrt(x), Sinh(x), Cosh(x), + Tanh(x) /Tgh(x)/, Coth(x) /Ctgh(x)/ + * changed: class Objects in ttmathobjects.h has been completely rewritten, + we can change the names of user-defined variables or functions, + and the names are case-sensitive now + * added: class History which is used in functions which take a lot of time + during calculating e.g. Factorial(x) + * added: Tg(x) a wrapper for Tan(x) + * changed: CTan(x) is Cot(x) now + * added: Ctg(x) a wrapper for Cot(x) + * added: ATg(x) a wrapper for ATan(x) + * changed: ACTan(x) is ACot(x) now + * added: ACtg(x) a wrapper for ACot(x) + * added: UInt::PrintTable() (for debugging etc.) + * changed: the methods Big::SetPi() Big::SetE() and Big::SetLn2() have + been rewritten, now they have 128 32bit words (it's about + 1232 valid decimal digits) + * fixed: previous values from Big::SetPi() Big::SetE() and + Big::SetLn2() were not too much accurate (last 2-3 words were wrong) + * added: Big::SetLn10() (128 32bit words as well) + * added: macro TTMATH_BUILTIN_VARIABLES_SIZE which is equal 128u on + 32bit platforms and 64ul on 64bit platforms (128/2=64) + * added: macros TTMATH_PLATFORM32 and TTMATH_PLATFORM64 + * changed: a small optimisation in UInt::Mul2Big() + * added: at the end of ttmath.h: #include "ttmathparser.h" + this is for convenience for a programmer, he can only use #include + with ttmath.h even if he uses the parser + * added: to samples: big.cpp, parser.cpp + * added/changes/fixed: in copy-constructors and operators= in Int, + Uint and Big (more info in the commit log) + * renamed: Big::SetDotOne() into Big::Set05() + * changes: a few small optimisations in Big + * deleted: the word 'virtual' from destructors: UInt, Int, Big + (types in this library are not projected to be base-classes for + another ones derived from them) + * and more small changes (look at the commit log) + + +Version 0.7.2 (2007.03.09): + * added: Big::Mod - the remainder from a division + * added: Big::Sgn - the 'sign' from the value (-1,0,1) + * added: global functions Mod and Sgn too + * added: checking whether a user gives a correct value of a variable or function + (user-defined variables/functions in the mathematical parser) + * added: into the parser: logical operators: > < >= <= == != && || + * added: into the parser: logical functions: and() or() not() if() + * added: ErrorCode::err_unknown_operator when the parser couldn't read an operator + + +Version 0.7.1 (2007.02.27): + * fixed: the error 'overflow during printing' which was caused + by Big::FromInt(Int value) (the sign has to be set at the end) + * fixed: many small errors + * added: ATan (arctan), ACTan (arc ctan) functions + + +Version 0.7.0 (2007.02.24): + * finished: support for 64bit platforms + * added: ASin (arcsin), ACos (arccos) functions + + +Version 0.6.4 (2007.01.29): + * fixed: the problem with a sign in the mathematical parser /-(1) was 1/ + * added: UInt::AddInt and UInt::SubInt + * changed: UInt::AddOne and UInt::SubOne (much faster now) + * added: UInt::SetBitInWord + * changed: UInt::SetBit (much faster now) + UInt::AddTwoUints renamed to UInt::AddTwoInts + UInt::FindLeadingBit32 renamed to UInt::FindLeadingBitInWord + UInt::Mul64 renamed to UInt::MulTwoWords + UInt::Div64 renamed to UInt::DivTwoWords + * added: UInt::SetBitInWord + * and more small changes in UInt type + * start adding support for Amd64 (not finished yet) (added ttmathuint64.h) + + +Version 0.6.3 (2007.01.22): + * changed: position of arguments (x and base) in logarithm functions are swapped + * changed: it's possible to use any multiplication algorithms in the same time + (macros UINT_MUL_VERSION_'X' have gone) + * added: ExceptionInfo, ReferenceError and RuntimeError classes + * changed: the mess in macros has been cleaned up + * added: TTMATH_RELEASE macro + + +Version 0.6.2 (2007.01.10): + * added: New division algorithm (radix b) where b is 2^32 diff --git a/src/libghost/ttmath/COPYRIGHT b/src/libghost/ttmath/COPYRIGHT new file mode 100644 index 0000000..f03126c --- /dev/null +++ b/src/libghost/ttmath/COPYRIGHT @@ -0,0 +1,28 @@ +Copyright (c) 2006-2010, Tomasz Sowa +All rights reserved. + +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. + + * Neither the name Tomasz Sowa nor the names of contributors to this + project may be used to endorse or promote products derived + from this software without specific prior written permission. + +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 COPYRIGHT OWNER 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. diff --git a/src/libghost/ttmath/README b/src/libghost/ttmath/README new file mode 100644 index 0000000..ea5bc1c --- /dev/null +++ b/src/libghost/ttmath/README @@ -0,0 +1,23 @@ +A bignum library for C++ + +TTMath is a small library which allows one to perform arithmetic operations +with big unsigned integer, big signed integer and big floating point numbers. +It provides standard mathematical operations like adding, subtracting, +multiplying, dividing. With the library also goes a mathematical parser to +help you solving mathematical expressions. + +TTMath is developed under the BSD licence which means that it is free for +both personal and commercial use. + +The main goal of the library is to allow one to use big values in the same +way as the standard types like int or float. It does not need to be compiled +first because the whole library is written as the C++ templates. This means +only C++ developers can use this library and one thing they have to do is +to use 'include' directive of the preprocessor. How big the values can be +is set at compile time. + +Author: Tomasz Sowa +WWW: http://www.ttmath.org + +Contributors: +Christian Kaiser diff --git a/src/libghost/ttmath/samples/Makefile b/src/libghost/ttmath/samples/Makefile new file mode 100644 index 0000000..3303ccd --- /dev/null +++ b/src/libghost/ttmath/samples/Makefile @@ -0,0 +1,46 @@ +CC = g++ +CFLAGS = -Wall -pedantic -s -O2 -I.. + + +.SUFFIXES: .cpp .o + +.cpp.o: + $(CC) -c $(CFLAGS) $< + + +all: uint int big big2 parser + + +uint: uint.o + $(CC) -o uint $(CFLAGS) uint.o + +int: int.o + $(CC) -o int $(CFLAGS) int.o + +big: big.o + $(CC) -o big $(CFLAGS) big.o + +big2: big2.o + $(CC) -o big2 $(CFLAGS) big2.o + +parser: parser.o + $(CC) -o parser $(CFLAGS) parser.o + + +uint.o: uint.cpp +int.o: int.cpp +big.o: big.cpp +big2.o: big2.cpp +parser.o: parser.cpp + + +clean: + rm -f *.o + rm -f *.s + rm -f uint + rm -f int + rm -f big + rm -f big2 + rm -f parser +# on MS Windows can automatically be added suffixes .exe to the names of output programs + rm -f *.exe diff --git a/src/libghost/ttmath/samples/big.cpp b/src/libghost/ttmath/samples/big.cpp new file mode 100644 index 0000000..8e9fa6a --- /dev/null +++ b/src/libghost/ttmath/samples/big.cpp @@ -0,0 +1,100 @@ +#include +#include + +// for convenience we're defining MyBig type +// this type has 2 words for its mantissa and 1 word for its exponent +// (on a 32bit platform one word means a word of 32 bits, +// and on a 64bit platform one word means a word of 64 bits) + +// Big +typedef ttmath::Big<1,2> MyBig; + + +void SimpleCalculating(const MyBig & a, const MyBig & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const MyBig & a, const MyBig & b) +{ +MyBig atemp; + + std::cout << "Calculating with a carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + std::cout << "a + b = (carry)" << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry)" << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry)" << std::endl; + + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (carry or division by zero) " << std::endl; + +} + + +int main() +{ +MyBig a,b; + + // conversion from 'const char *' + a = "123456.543456"; + b = "98767878.124322"; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMax(); + + // conversion from double + b = 456.32; + + // Look at the value 'a' and the product from a+b and a-b + // Don't worry this is the nature of floating point numbers + CalculatingWithCarry(a,b); +} + +/* +the result (on 32 bit platform): + +Simple calculating +a = 123456.543456 +b = 98767878.124322 +a + b = 98891334.667778 +a - b = -98644421.580866 +a * b = 12193540837712.2708 +a / b = 0.00124996654580957646 +Calculating with a carry +a = 1.624801256066640878e+646457012 +b = 456.319999999999993 +a + b = 1.624801256066640878e+646457012 +a - b = 1.624801256066640878e+646457012 +a * b = (carry) +a / b = 3.560661939136222174e+646457009 +*/ diff --git a/src/libghost/ttmath/samples/big2.cpp b/src/libghost/ttmath/samples/big2.cpp new file mode 100644 index 0000000..fcb74bf --- /dev/null +++ b/src/libghost/ttmath/samples/big2.cpp @@ -0,0 +1,113 @@ +#include +#include + + +// this is a similar example to big.cpp +// but now we're using TTMATH_BITS() macro +// this macro returns how many words we need to store +// the given number of bits + +// TTMATH_BITS(64) +// on a 32bit platform the macro returns 2 (2*32=64) +// on a 64bit platform the macro returns 1 + +// TTMATH_BITS(128) +// on a 32bit platform the macro returns 4 (4*32=128) +// on a 64bit platform the macro returns 2 (2*64=128) + +// Big +typedef ttmath::Big MyBig; + +// consequently on a 32bit platform we define: Big<2, 4> +// and on a 64bit platform: Big<1, 2> +// and the calculations will be the same on both platforms + + +void SimpleCalculating(const MyBig & a, const MyBig & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const MyBig & a, const MyBig & b) +{ +MyBig atemp; + + std::cout << "Calculating with a carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + std::cout << "a + b = (carry)" << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry)" << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry)" << std::endl; + + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (carry or division by zero) " << std::endl; + +} + + +int main() +{ +MyBig a,b; + + // conversion from 'const char *' + a = "123456.543456"; + b = "98767878.124322"; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMax(); + + // conversion from double + b = 456.32; + + // Look at the value 'a' and the product from a+b and a-b + // Don't worry this is the nature of floating point numbers + CalculatingWithCarry(a,b); +} + +/* +the result (the same on a 32 or 64bit platform): + +Simple calculating +a = 123456.543456 +b = 98767878.124322 +a + b = 98891334.667778 +a - b = -98644421.580866 +a * b = 12193540837712.270763536832 +a / b = 0.001249966545809576460596448526166860913 +Calculating with a carry +a = 2.3495345545711177736883282090959505003e+2776511644261678604 +b = 456.3199999999999931787897367030382156 +a + b = 2.3495345545711177736883282090959505003e+2776511644261678604 +a - b = 2.3495345545711177736883282090959505003e+2776511644261678604 +a * b = (carry) +a / b = 5.1488748127873374141170361292780486452e+2776511644261678601 +*/ diff --git a/src/libghost/ttmath/samples/int.cpp b/src/libghost/ttmath/samples/int.cpp new file mode 100644 index 0000000..13760d2 --- /dev/null +++ b/src/libghost/ttmath/samples/int.cpp @@ -0,0 +1,92 @@ +#include +#include + + +void SimpleCalculating(const ttmath::Int<2> & a, const ttmath::Int<2> & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const ttmath::Int<2> & a, const ttmath::Int<2> & b) +{ +ttmath::Int<2> atemp; + + std::cout << "Calculating with a carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + std::cout << "a + b = (carry) " << atemp << std::endl; + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry) " << atemp << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry: the result is too big) " << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (division by zero) " << std::endl; + +} + +int main() +{ +// on 32bit platforms: 'a' and 'b' have 2-words (two 32bit words) +// it means a,b are from <-2^63, 2^63 - 1> +ttmath::Int<2> a,b; + + // conversion from int + a = 123456; + + // conversion from 'const char *' + b = "98767878"; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMax(); + + // conversion from 'int' + b = 10; + + CalculatingWithCarry(a,b); +} + +/* +the result (on 32 bit platform): + +Simple calculating +a = 123456 +b = 98767878 +a + b = 98891334 +a - b = -98644422 +a * b = 12193487146368 +a / b = 0 +Calculating with a carry +a = 9223372036854775807 +b = 10 +a + b = (carry) -9223372036854775799 +a - b = 9223372036854775797 +a * b = (carry) the result is too big) +a / b = 922337203685477580 +*/ diff --git a/src/libghost/ttmath/samples/parser.cpp b/src/libghost/ttmath/samples/parser.cpp new file mode 100644 index 0000000..6cbf192 --- /dev/null +++ b/src/libghost/ttmath/samples/parser.cpp @@ -0,0 +1,39 @@ +#include +#include + + +// for convenience we're defining MyBig type +// this type has 2 words for its mantissa and 1 word for its exponent +// (on a 32bit platform one word means a word of 32 bits, +// and on a 64bit platform one word means a word of 64 bits) +typedef ttmath::Big<1,2> MyBig; + + +int main() +{ +ttmath::Parser parser; + +// the sine function takes its parameter as being in radians, +// the product from the arcus tangent will be in radians as well +const char equation[] = " (34 + 24) * 123 - 34.32 ^ 6 * sin(2.56) - atan(10)"; + + ttmath::ErrorCode err = parser.Parse(equation); + + if( err == ttmath::err_ok ) + std::cout << parser.stack[0].value << std::endl; + else + std::cout << "Error: " + << static_cast(err) + << std::endl; +} + +/* +the result (on 32 bit platform): +-897705014.52573107 +*/ + + +/* +the result (on 64 bit platform): +-897705014.5257310676097719585259773124 +*/ diff --git a/src/libghost/ttmath/samples/uint.cpp b/src/libghost/ttmath/samples/uint.cpp new file mode 100644 index 0000000..f6b0df4 --- /dev/null +++ b/src/libghost/ttmath/samples/uint.cpp @@ -0,0 +1,93 @@ +#include +#include + + +void SimpleCalculating(const ttmath::UInt<2> & a, const ttmath::UInt<2> & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const ttmath::UInt<2> & a, const ttmath::UInt<2> & b) +{ +ttmath::UInt<2> atemp; + + std::cout << "Calculating with a carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + // if there was a carry then atemp.Add(...) would have returned 1 + std::cout << "a + b = (carry: the result is too big) " << atemp << std::endl; + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry: 'a' was smaller than 'b') " << atemp << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry: the result is too big) " << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (division by zero) " << std::endl; + +} + +int main() +{ +// on 32bit platforms: 'a' and 'b' have 2-words (two 32bit words) +// it means a,b are from <0, 2^64 - 1> +ttmath::UInt<2> a,b; + + // conversion from 'const char *' + a = "123456"; + + // conversion from int + b = 9876; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMax(); + + // conversion from 'int' + b = 5; + + CalculatingWithCarry(a,b); +} + +/* +the result (on 32 bit platform): + +Simple calculating +a = 123456 +b = 9876 +a + b = 133332 +a - b = 113580 +a * b = 1219251456 +a / b = 12 +Calculating with a carry +a = 18446744073709551615 +b = 5 +a + b = (carry: the result is too big) 4 +a - b = 18446744073709551610 +a * b = (carry: the result is too big) +a / b = 3689348814741910323 +*/ diff --git a/src/libghost/ttmath/ttmath/ttmath.h b/src/libghost/ttmath/ttmath/ttmath.h new file mode 100644 index 0000000..8bd24f5 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmath.h @@ -0,0 +1,2835 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmathmathtt +#define headerfilettmathmathtt + +/*! + \file ttmath.h + \brief Mathematics functions. +*/ + +#ifdef _MSC_VER +//warning C4127: conditional expression is constant +#pragma warning( disable: 4127 ) +//warning C4702: unreachable code +#pragma warning( disable: 4702 ) +//warning C4800: forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable: 4800 ) +#endif + + +#include "ttmathbig.h" +#include "ttmathobjects.h" + + +namespace ttmath +{ + /* + * + * functions defined here are used only with Big<> types + * + * + */ + + + /* + * + * functions for rounding + * + * + */ + + + /*! + this function skips the fraction from x + e.g 2.2 = 2 + 2.7 = 2 + -2.2 = 2 + -2.7 = 2 + */ + template + ValueType SkipFraction(const ValueType & x) + { + ValueType result( x ); + result.SkipFraction(); + + return result; + } + + + /*! + this function rounds to the nearest integer value + e.g 2.2 = 2 + 2.7 = 3 + -2.2 = -2 + -2.7 = -3 + */ + template + ValueType Round(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result( x ); + uint c = result.Round(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + /*! + this function returns a value representing the smallest integer + that is greater than or equal to x + + Ceil(-3.7) = -3 + Ceil(-3.1) = -3 + Ceil(-3.0) = -3 + Ceil(4.0) = 4 + Ceil(4.2) = 5 + Ceil(4.8) = 5 + */ + template + ValueType Ceil(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result(x); + uint c = 0; + + result.SkipFraction(); + + if( result != x ) + { + // x is with fraction + // if x is negative we don't have to do anything + if( !x.IsSign() ) + { + ValueType one; + one.SetOne(); + + c += result.Add(one); + } + } + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function returns a value representing the largest integer + that is less than or equal to x + + Floor(-3.6) = -4 + Floor(-3.1) = -4 + Floor(-3) = -3 + Floor(2) = 2 + Floor(2.3) = 2 + Floor(2.8) = 2 + */ + template + ValueType Floor(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result(x); + uint c = 0; + + result.SkipFraction(); + + if( result != x ) + { + // x is with fraction + // if x is positive we don't have to do anything + if( x.IsSign() ) + { + ValueType one; + one.SetOne(); + + c += result.Sub(one); + } + } + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + /* + * + * logarithms and the exponent + * + * + */ + + + /*! + this function calculates the natural logarithm (logarithm with the base 'e') + */ + template + ValueType Ln(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result; + uint state = result.Ln(x); + + if( err ) + { + switch( state ) + { + case 0: + *err = err_ok; + break; + case 1: + *err = err_overflow; + break; + case 2: + *err = err_improper_argument; + break; + default: + *err = err_internal_error; + break; + } + } + + + return result; + } + + + /*! + this function calculates the logarithm + */ + template + ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0) + { + if( x.IsNan() || base.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // default NaN + } + + ValueType result; + uint state = result.Log(x, base); + + if( err ) + { + switch( state ) + { + case 0: + *err = err_ok; + break; + case 1: + *err = err_overflow; + break; + case 2: + case 3: + *err = err_improper_argument; + break; + default: + *err = err_internal_error; + break; + } + } + + return result; + } + + + /*! + this function calculates the expression e^x + */ + template + ValueType Exp(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result; + uint c = result.Exp(x); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + * + * trigonometric functions + * + */ + + + /* + this namespace consists of auxiliary functions + (something like 'private' in a class) + */ + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Sine + (you don't have to call this function) + */ + template + uint PrepareSin(ValueType & x, bool & change_sign) + { + ValueType temp; + + change_sign = false; + + if( x.IsSign() ) + { + // we're using the formula 'sin(-x) = -sin(x)' + change_sign = !change_sign; + x.ChangeSign(); + } + + // we're reducing the period 2*PI + // (for big values there'll always be zero) + temp.Set2Pi(); + + if( x.Mod(temp) ) + return 1; + + + // we're setting 'x' as being in the range of <0, 0.5PI> + + temp.SetPi(); + + if( x > temp ) + { + // x is in (pi, 2*pi> + x.Sub( temp ); + change_sign = !change_sign; + } + + temp.Set05Pi(); + + if( x > temp ) + { + // x is in (0.5pi, pi> + x.Sub( temp ); + x = temp - x; + } + + return 0; + } + + + /*! + an auxiliary function for calculating the Sine + (you don't have to call this function) + + it returns Sin(x) where 'x' is from <0, PI/2> + we're calculating the Sin with using Taylor series in zero or PI/2 + (depending on which point of these two points is nearer to the 'x') + + Taylor series: + sin(x) = sin(a) + cos(a)*(x-a)/(1!) + - sin(a)*((x-a)^2)/(2!) - cos(a)*((x-a)^3)/(3!) + + sin(a)*((x-a)^4)/(4!) + ... + + when a=0 it'll be: + sin(x) = (x)/(1!) - (x^3)/(3!) + (x^5)/(5!) - (x^7)/(7!) + (x^9)/(9!) ... + + and when a=PI/2: + sin(x) = 1 - ((x-PI/2)^2)/(2!) + ((x-PI/2)^4)/(4!) - ((x-PI/2)^6)/(6!) ... + */ + template + ValueType Sin0pi05(const ValueType & x) + { + ValueType result; + ValueType numerator, denominator; + ValueType d_numerator, d_denominator; + ValueType one, temp, old_result; + + // temp = pi/4 + temp.Set05Pi(); + temp.exponent.SubOne(); + + one.SetOne(); + + if( x < temp ) + { + // we're using the Taylor series with a=0 + result = x; + numerator = x; + denominator = one; + + // d_numerator = x^2 + d_numerator = x; + d_numerator.Mul(x); + + d_denominator = 2; + } + else + { + // we're using the Taylor series with a=PI/2 + result = one; + numerator = one; + denominator = one; + + // d_numerator = (x-pi/2)^2 + ValueType pi05; + pi05.Set05Pi(); + + temp = x; + temp.Sub( pi05 ); + d_numerator = temp; + d_numerator.Mul( temp ); + + d_denominator = one; + } + + uint c = 0; + bool addition = false; + + old_result = result; + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + // we're starting from a second part of the formula + c += numerator. Mul( d_numerator ); + c += denominator. Mul( d_denominator ); + c += d_denominator.Add( one ); + c += denominator. Mul( d_denominator ); + c += d_denominator.Add( one ); + temp = numerator; + c += temp.Div(denominator); + + if( c ) + // Sin is from <-1,1> and cannot make an overflow + // but the carry can be from the Taylor series + // (then we only break our calculations) + break; + + if( addition ) + result.Add( temp ); + else + result.Sub( temp ); + + + addition = !addition; + + // we're testing whether the result has changed after adding + // the next part of the Taylor formula, if not we end the loop + // (it means 'x' is zero or 'x' is PI/2 or this part of the formula + // is too small) + if( result == old_result ) + break; + + old_result = result; + } + + return result; + } + + } // namespace auxiliaryfunctions + + + + /*! + this function calculates the Sine + */ + template + ValueType Sin(ValueType x, ErrorCode * err = 0) + { + using namespace auxiliaryfunctions; + + ValueType one, result; + bool change_sign; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( err ) + *err = err_ok; + + if( PrepareSin( x, change_sign ) ) + { + // x is too big, we cannnot reduce the 2*PI period + // prior to version 0.8.5 the result was zero + + // result has NaN flag set by default + + if( err ) + *err = err_overflow; // maybe another error code? err_improper_argument? + + return result; // NaN is set by default + } + + result = Sin0pi05( x ); + + one.SetOne(); + + // after calculations there can be small distortions in the result + if( result > one ) + result = one; + else + if( result.IsSign() ) + // we've calculated the sin from <0, pi/2> and the result + // should be positive + result.SetZero(); + + if( change_sign ) + result.ChangeSign(); + + return result; + } + + + /*! + this function calulates the Cosine + we're using the formula cos(x) = sin(x + PI/2) + */ + template + ValueType Cos(ValueType x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType pi05; + pi05.Set05Pi(); + + uint c = x.Add( pi05 ); + + if( c ) + { + if( err ) + *err = err_overflow; + + return ValueType(); // result is undefined (NaN is set by default) + } + + return Sin(x, err); + } + + + /*! + this function calulates the Tangent + we're using the formula tan(x) = sin(x) / cos(x) + + it takes more time than calculating the Tan directly + from for example Taylor series but should be a bit preciser + because Tan receives its values from -infinity to +infinity + and when we calculate it from any series then we can make + a greater mistake than calculating 'sin/cos' + */ + template + ValueType Tan(const ValueType & x, ErrorCode * err = 0) + { + ValueType result = Cos(x, err); + + if( err && *err != err_ok ) + return result; + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + result.SetNan(); + + return result; + } + + return Sin(x, err) / result; + } + + + /*! + this function calulates the Tangent + look at the description of Tan(...) + + (the abbreviation of Tangent can be 'tg' as well) + */ + template + ValueType Tg(const ValueType & x, ErrorCode * err = 0) + { + return Tan(x, err); + } + + + /*! + this function calulates the Cotangent + we're using the formula tan(x) = cos(x) / sin(x) + + (why do we make it in this way? + look at information in Tan() function) + */ + template + ValueType Cot(const ValueType & x, ErrorCode * err = 0) + { + ValueType result = Sin(x, err); + + if( err && *err != err_ok ) + return result; + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + result.SetNan(); + + return result; + } + + return Cos(x, err) / result; + } + + + /*! + this function calulates the Cotangent + look at the description of Cot(...) + + (the abbreviation of Cotangent can be 'ctg' as well) + */ + template + ValueType Ctg(const ValueType & x, ErrorCode * err = 0) + { + return Cot(x, err); + } + + + /* + * + * inverse trigonometric functions + * + * + */ + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Arc Sine + + we're calculating asin from the following formula: + asin(x) = x + (1*x^3)/(2*3) + (1*3*x^5)/(2*4*5) + (1*3*5*x^7)/(2*4*6*7) + ... + where abs(x) <= 1 + + we're using this formula when x is from <0, 1/2> + */ + template + ValueType ASin_0(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, nominator_x, denominator_add, denominator_x; + ValueType two, result(x), x2(x); + ValueType nominator_temp, denominator_temp, old_result = result; + uint c = 0; + + x2.Mul(x); + two = 2; + + nominator.SetOne(); + denominator = two; + nominator_add = nominator; + denominator_add = denominator; + nominator_x = x; + denominator_x = 3; + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + c += nominator_x.Mul(x2); + nominator_temp = nominator_x; + c += nominator_temp.Mul(nominator); + denominator_temp = denominator; + c += denominator_temp.Mul(denominator_x); + c += nominator_temp.Div(denominator_temp); + + // if there is a carry somewhere we only break the calculating + // the result should be ok -- it's from <-pi/2, pi/2> + if( c ) + break; + + result.Add(nominator_temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + + + c += nominator_add.Add(two); + c += denominator_add.Add(two); + c += nominator.Mul(nominator_add); + c += denominator.Mul(denominator_add); + c += denominator_x.Add(two); + } + + return result; + } + + + + /*! + an auxiliary function for calculating the Arc Sine + + we're calculating asin from the following formula: + asin(x) = pi/2 - sqrt(2)*sqrt(1-x) * asin_temp + asin_temp = 1 + (1*(1-x))/((2*3)*(2)) + (1*3*(1-x)^2)/((2*4*5)*(4)) + (1*3*5*(1-x)^3)/((2*4*6*7)*(8)) + ... + + where abs(x) <= 1 + + we're using this formula when x is from (1/2, 1> + */ + template + ValueType ASin_1(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, nominator_x, nominator_x_add, denominator_add, denominator_x; + ValueType denominator2; + ValueType one, two, result; + ValueType nominator_temp, denominator_temp, old_result; + uint c = 0; + + two = 2; + + one.SetOne(); + nominator = one; + result = one; + old_result = result; + denominator = two; + nominator_add = nominator; + denominator_add = denominator; + nominator_x = one; + nominator_x.Sub(x); + nominator_x_add = nominator_x; + denominator_x = 3; + denominator2 = two; + + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + nominator_temp = nominator_x; + c += nominator_temp.Mul(nominator); + denominator_temp = denominator; + c += denominator_temp.Mul(denominator_x); + c += denominator_temp.Mul(denominator2); + c += nominator_temp.Div(denominator_temp); + + // if there is a carry somewhere we only break the calculating + // the result should be ok -- it's from <-pi/2, pi/2> + if( c ) + break; + + result.Add(nominator_temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + + c += nominator_x.Mul(nominator_x_add); + c += nominator_add.Add(two); + c += denominator_add.Add(two); + c += nominator.Mul(nominator_add); + c += denominator.Mul(denominator_add); + c += denominator_x.Add(two); + c += denominator2.Mul(two); + } + + + nominator_x_add.exponent.AddOne(); // *2 + one.exponent.SubOne(); // =0.5 + nominator_x_add.Pow(one); // =sqrt(nominator_x_add) + result.Mul(nominator_x_add); + + one.Set05Pi(); + one.Sub(result); + + return one; + } + + + } // namespace auxiliaryfunctions + + + /*! + this function calculates the Arc Sine + x is from <-1,1> + */ + template + ValueType ASin(ValueType x, ErrorCode * err = 0) + { + using namespace auxiliaryfunctions; + + ValueType result, one; + one.SetOne(); + bool change_sign = false; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( x.GreaterWithoutSignThan(one) ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( x.IsSign() ) + { + change_sign = true; + x.Abs(); + } + + one.exponent.SubOne(); // =0.5 + + // asin(-x) = -asin(x) + if( x.GreaterWithoutSignThan(one) ) + result = ASin_1(x); + else + result = ASin_0(x); + + if( change_sign ) + result.ChangeSign(); + + if( err ) + *err = err_ok; + + return result; + } + + + /*! + this function calculates the Arc Cosine + + we're using the formula: + acos(x) = pi/2 - asin(x) + */ + template + ValueType ACos(const ValueType & x, ErrorCode * err = 0) + { + ValueType temp; + + temp.Set05Pi(); + temp.Sub(ASin(x, err)); + + return temp; + } + + + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Arc Tangent + + arc tan (x) where x is in <0; 0.5) + (x can be in (-0.5 ; 0.5) too) + + we're using the Taylor series expanded in zero: + atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ... + */ + template + ValueType ATan0(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, denominator_add, temp; + ValueType result, old_result; + bool adding = false; + uint c = 0; + + result = x; + old_result = result; + nominator = x; + nominator_add = x; + nominator_add.Mul(x); + + denominator.SetOne(); + denominator_add = 2; + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + c += nominator.Mul(nominator_add); + c += denominator.Add(denominator_add); + + temp = nominator; + c += temp.Div(denominator); + + if( c ) + // the result should be ok + break; + + if( adding ) + result.Add(temp); + else + result.Sub(temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + adding = !adding; + } + + return result; + } + + + /*! + an auxiliary function for calculating the Arc Tangent + + where x is in <0 ; 1> + */ + template + ValueType ATan01(const ValueType & x) + { + ValueType half; + half.Set05(); + + /* + it would be better if we chose about sqrt(2)-1=0.41... instead of 0.5 here + + because as you can see below: + when x = sqrt(2)-1 + abs(x) = abs( (x-1)/(1+x) ) + so when we're calculating values around x + then they will be better converged to each other + + for example if we have x=0.4999 then during calculating ATan0(0.4999) + we have to make about 141 iterations but when we have x=0.5 + then during calculating ATan0( (x-1)/(1+x) ) we have to make + only about 89 iterations (both for Big<3,9>) + + in the future this 0.5 can be changed + */ + if( x.SmallerWithoutSignThan(half) ) + return ATan0(x); + + + /* + x>=0.5 and x<=1 + (x can be even smaller than 0.5) + + y = atac(x) + x = tan(y) + + tan(y-b) = (tan(y)-tab(b)) / (1+tan(y)*tan(b)) + y-b = atan( (tan(y)-tab(b)) / (1+tan(y)*tan(b)) ) + y = b + atan( (x-tab(b)) / (1+x*tan(b)) ) + + let b = pi/4 + tan(b) = tan(pi/4) = 1 + y = pi/4 + atan( (x-1)/(1+x) ) + + so + atac(x) = pi/4 + atan( (x-1)/(1+x) ) + when x->1 (x converges to 1) the (x-1)/(1+x) -> 0 + and we can use ATan0() function here + */ + + ValueType n(x),d(x),one,result; + + one.SetOne(); + n.Sub(one); + d.Add(one); + n.Div(d); + + result = ATan0(n); + + n.Set05Pi(); + n.exponent.SubOne(); // =pi/4 + result.Add(n); + + return result; + } + + + /*! + an auxiliary function for calculating the Arc Tangent + where x > 1 + + we're using the formula: + atan(x) = pi/2 - atan(1/x) for x>0 + */ + template + ValueType ATanGreaterThanPlusOne(const ValueType & x) + { + ValueType temp, atan; + + temp.SetOne(); + + if( temp.Div(x) ) + { + // if there was a carry here that means x is very big + // and atan(1/x) fast converged to 0 + atan.SetZero(); + } + else + atan = ATan01(temp); + + temp.Set05Pi(); + temp.Sub(atan); + + return temp; + } + + } // namespace auxiliaryfunctions + + + /*! + this function calculates the Arc Tangent + */ + template + ValueType ATan(ValueType x) + { + using namespace auxiliaryfunctions; + + ValueType one, result; + one.SetOne(); + bool change_sign = false; + + if( x.IsNan() ) + return result; // NaN is set by default + + // if x is negative we're using the formula: + // atan(-x) = -atan(x) + if( x.IsSign() ) + { + change_sign = true; + x.Abs(); + } + + if( x.GreaterWithoutSignThan(one) ) + result = ATanGreaterThanPlusOne(x); + else + result = ATan01(x); + + if( change_sign ) + result.ChangeSign(); + + return result; + } + + + /*! + this function calculates the Arc Tangent + look at the description of ATan(...) + + (the abbreviation of Arc Tangent can be 'atg' as well) + */ + template + ValueType ATg(const ValueType & x) + { + return ATan(x); + } + + + /*! + this function calculates the Arc Cotangent + + we're using the formula: + actan(x) = pi/2 - atan(x) + */ + template + ValueType ACot(const ValueType & x) + { + ValueType result; + + result.Set05Pi(); + result.Sub(ATan(x)); + + return result; + } + + + /*! + this function calculates the Arc Cotangent + look at the description of ACot(...) + + (the abbreviation of Arc Cotangent can be 'actg' as well) + */ + template + ValueType ACtg(const ValueType & x) + { + return ACot(x); + } + + + /* + * + * hyperbolic functions + * + * + */ + + + /*! + this function calculates the Hyperbolic Sine + + we're using the formula sinh(x)= ( e^x - e^(-x) ) / 2 + */ + template + ValueType Sinh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType ex, emx; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + c += ex.Sub(emx); + c += ex.exponent.SubOne(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return ex; + } + + + /*! + this function calculates the Hyperbolic Cosine + + we're using the formula cosh(x)= ( e^x + e^(-x) ) / 2 + */ + template + ValueType Cosh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType ex, emx; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + c += ex.Add(emx); + c += ex.exponent.SubOne(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return ex; + } + + + /*! + this function calculates the Hyperbolic Tangent + + we're using the formula tanh(x)= ( e^x - e^(-x) ) / ( e^x + e^(-x) ) + */ + template + ValueType Tanh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType ex, emx, nominator, denominator; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + nominator = ex; + c += nominator.Sub(emx); + denominator = ex; + c += denominator.Add(emx); + + c += nominator.Div(denominator); + + if( err ) + *err = c ? err_overflow : err_ok; + + return nominator; + } + + + /*! + this function calculates the Hyperbolic Tangent + look at the description of Tanh(...) + + (the abbreviation of Hyperbolic Tangent can be 'tgh' as well) + */ + template + ValueType Tgh(const ValueType & x, ErrorCode * err = 0) + { + return Tanh(x, err); + } + + /*! + this function calculates the Hyperbolic Cotangent + + we're using the formula coth(x)= ( e^x + e^(-x) ) / ( e^x - e^(-x) ) + */ + template + ValueType Coth(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + if( x.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + ValueType ex, emx, nominator, denominator; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + nominator = ex; + c += nominator.Add(emx); + denominator = ex; + c += denominator.Sub(emx); + + c += nominator.Div(denominator); + + if( err ) + *err = c ? err_overflow : err_ok; + + return nominator; + } + + + /*! + this function calculates the Hyperbolic Cotangent + look at the description of Coth(...) + + (the abbreviation of Hyperbolic Cotangent can be 'ctgh' as well) + */ + template + ValueType Ctgh(const ValueType & x, ErrorCode * err = 0) + { + return Coth(x, err); + } + + + /* + * + * inverse hyperbolic functions + * + * + */ + + + /*! + inverse hyperbolic sine + + asinh(x) = ln( x + sqrt(x^2 + 1) ) + */ + template + ValueType ASinh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType xx(x), one, result; + uint c = 0; + one.SetOne(); + + c += xx.Mul(x); + c += xx.Add(one); + one.exponent.SubOne(); // one=0.5 + // xx is >= 1 + c += xx.PowFrac(one); // xx=sqrt(xx) + c += xx.Add(x); + c += result.Ln(xx); // xx > 0 + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic cosine + + acosh(x) = ln( x + sqrt(x^2 - 1) ) x in <1, infinity) + */ + template + ValueType ACosh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType xx(x), one, result; + uint c = 0; + one.SetOne(); + + if( x < one ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += xx.Mul(x); + c += xx.Sub(one); + // xx is >= 0 + // we can't call a PowFrac when the 'x' is zero + // if x is 0 the sqrt(0) is 0 + if( !xx.IsZero() ) + { + one.exponent.SubOne(); // one=0.5 + c += xx.PowFrac(one); // xx=sqrt(xx) + } + c += xx.Add(x); + c += result.Ln(xx); // xx >= 1 + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic tangent + + atanh(x) = 0.5 * ln( (1+x) / (1-x) ) x in (-1, 1) + */ + template + ValueType ATanh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType nominator(x), denominator, one, result; + uint c = 0; + one.SetOne(); + + if( !x.SmallerWithoutSignThan(one) ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += nominator.Add(one); + denominator = one; + c += denominator.Sub(x); + c += nominator.Div(denominator); + c += result.Ln(nominator); + c += result.exponent.SubOne(); + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic tantent + */ + template + ValueType ATgh(const ValueType & x, ErrorCode * err = 0) + { + return ATanh(x, err); + } + + + /*! + inverse hyperbolic cotangent + + acoth(x) = 0.5 * ln( (x+1) / (x-1) ) x in (-infinity, -1) or (1, infinity) + */ + template + ValueType ACoth(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType nominator(x), denominator(x), one, result; + uint c = 0; + one.SetOne(); + + if( !x.GreaterWithoutSignThan(one) ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += nominator.Add(one); + c += denominator.Sub(one); + c += nominator.Div(denominator); + c += result.Ln(nominator); + c += result.exponent.SubOne(); + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic cotantent + */ + template + ValueType ACtgh(const ValueType & x, ErrorCode * err = 0) + { + return ACoth(x, err); + } + + + + + + /* + * + * functions for converting between degrees, radians and gradians + * + * + */ + + + /*! + this function converts degrees to radians + + it returns: x * pi / 180 + */ + template + ValueType DegToRad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + // it is better to make division first and then multiplication + // the result is more accurate especially when x is: 90,180,270 or 360 + temp = 180; + c += result.Div(temp); + + temp.SetPi(); + c += result.Mul(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts radians to degrees + + it returns: x * 180 / pi + */ + template + ValueType RadToDeg(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, delimiter; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = 180; + c += result.Mul(x); + + delimiter.SetPi(); + c += result.Div(delimiter); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees in the long format into one value + + long format: (degrees, minutes, seconds) + minutes and seconds must be greater than or equal zero + + result: + if d>=0 : result= d + ((s/60)+m)/60 + if d<0 : result= d - ((s/60)+m)/60 + + ((s/60)+m)/60 = (s+60*m)/3600 (second version is faster because + there's only one division) + + for example: + DegToDeg(10, 30, 0) = 10.5 + DegToDeg(10, 24, 35.6)=10.4098(8) + */ + template + ValueType DegToDeg( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType delimiter, multipler; + uint c = 0; + + if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + return delimiter ; // NaN is set by default + } + + multipler = 60; + delimiter = 3600; + + c += multipler.Mul(m); + c += multipler.Add(s); + c += multipler.Div(delimiter); + + if( d.IsSign() ) + multipler.ChangeSign(); + + c += multipler.Add(d); + + if( err ) + *err = c ? err_overflow : err_ok; + + return multipler; + } + + + /*! + this function converts degrees in the long format to radians + */ + template + ValueType DegToRad( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType temp_deg = DegToDeg(d,m,s,err); + + if( err && *err!=err_ok ) + return temp_deg; + + return DegToRad(temp_deg, err); + } + + + /*! + this function converts gradians to radians + + it returns: x * pi / 200 + */ + template + ValueType GradToRad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + // it is better to make division first and then multiplication + // the result is more accurate especially when x is: 100,200,300 or 400 + temp = 200; + c += result.Div(temp); + + temp.SetPi(); + c += result.Mul(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts radians to gradians + + it returns: x * 200 / pi + */ + template + ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, delimiter; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = 200; + c += result.Mul(x); + + delimiter.SetPi(); + c += result.Div(delimiter); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees to gradians + + it returns: x * 200 / 180 + */ + template + ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + temp = 200; + c += result.Mul(temp); + + temp = 180; + c += result.Div(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees in the long format to gradians + */ + template + ValueType DegToGrad( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType temp_deg = DegToDeg(d,m,s,err); + + if( err && *err!=err_ok ) + return temp_deg; + + return DegToGrad(temp_deg, err); + } + + + /*! + this function converts degrees to gradians + + it returns: x * 180 / 200 + */ + template + ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + temp = 180; + c += result.Mul(temp); + + temp = 200; + c += result.Div(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + + /* + * + * another functions + * + * + */ + + + /*! + this function calculates the square root + + Sqrt(9) = 3 + */ + template + ValueType Sqrt(ValueType x, ErrorCode * err = 0) + { + if( x.IsNan() || x.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + uint c = x.Sqrt(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return x; + } + + + + namespace auxiliaryfunctions + { + + template + bool RootCheckIndexSign(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( index.IsSign() ) + { + // index cannot be negative + if( err ) + *err = err_improper_argument; + + x.SetNan(); + + return true; + } + + return false; + } + + + template + bool RootCheckIndexZero(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( index.IsZero() ) + { + if( x.IsZero() ) + { + // there isn't root(0;0) - we assume it's not defined + if( err ) + *err = err_improper_argument; + + x.SetNan(); + + return true; + } + + // root(x;0) is 1 (if x!=0) + x.SetOne(); + + if( err ) + *err = err_ok; + + return true; + } + + return false; + } + + + template + bool RootCheckIndexOne(const ValueType & index, ErrorCode * err) + { + ValueType one; + one.SetOne(); + + if( index == one ) + { + //root(x;1) is x + // we do it because if we used the PowFrac function + // we would lose the precision + if( err ) + *err = err_ok; + + return true; + } + + return false; + } + + + template + bool RootCheckIndexTwo(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( index == 2 ) + { + x = Sqrt(x, err); + + return true; + } + + return false; + } + + + template + bool RootCheckIndexFrac(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( !index.IsInteger() ) + { + // index must be integer + if( err ) + *err = err_improper_argument; + + x.SetNan(); + + return true; + } + + return false; + } + + + template + bool RootCheckXZero(ValueType & x, ErrorCode * err) + { + if( x.IsZero() ) + { + // root(0;index) is zero (if index!=0) + // RootCheckIndexZero() must be called beforehand + x.SetZero(); + + if( err ) + *err = err_ok; + + return true; + } + + return false; + } + + + template + bool RootCheckIndex(ValueType & x, const ValueType & index, ErrorCode * err, bool * change_sign) + { + *change_sign = false; + + if( index.Mod2() ) + { + // index is odd (1,3,5...) + if( x.IsSign() ) + { + *change_sign = true; + x.Abs(); + } + } + else + { + // index is even + // x cannot be negative + if( x.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + x.SetNan(); + + return true; + } + } + + return false; + } + + + template + uint RootCorrectInteger(ValueType & old_x, ValueType & x, const ValueType & index) + { + if( !old_x.IsInteger() || x.IsInteger() || !index.exponent.IsSign() ) + return 0; + + // old_x is integer, + // x is not integer, + // index is relatively small (index.exponent<0 or index.exponent<=0) + // (because we're using a special powering algorithm Big::PowUInt()) + + uint c = 0; + + ValueType temp(x); + c += temp.Round(); + + ValueType temp_round(temp); + c += temp.PowUInt(index); + + if( temp == old_x ) + x = temp_round; + + return (c==0)? 0 : 1; + } + + + + } // namespace auxiliaryfunctions + + + + /*! + indexth Root of x + index must be integer and not negative <0;1;2;3....) + + if index==0 the result is one + if x==0 the result is zero and we assume root(0;0) is not defined + + if index is even (2;4;6...) the result is x^(1/index) and x>0 + if index is odd (1;2;3;...) the result is either + -(abs(x)^(1/index)) if x<0 or + x^(1/index)) if x>0 + + (for index==1 the result is equal x) + */ + template + ValueType Root(ValueType x, const ValueType & index, ErrorCode * err = 0) + { + using namespace auxiliaryfunctions; + + if( x.IsNan() || index.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + if( RootCheckIndexSign(x, index, err) ) return x; + if( RootCheckIndexZero(x, index, err) ) return x; + if( RootCheckIndexOne ( index, err) ) return x; + if( RootCheckIndexTwo (x, index, err) ) return x; + if( RootCheckIndexFrac(x, index, err) ) return x; + if( RootCheckXZero (x, err) ) return x; + + // index integer and index!=0 + // x!=0 + + ValueType old_x(x); + bool change_sign; + + if( RootCheckIndex(x, index, err, &change_sign ) ) return x; + + ValueType temp; + uint c = 0; + + // we're using the formula: root(x ; n) = exp( ln(x) / n ) + c += temp.Ln(x); + c += temp.Div(index); + c += x.Exp(temp); + + if( change_sign ) + { + // x is different from zero + x.SetSign(); + } + + c += RootCorrectInteger(old_x, x, index); + + if( err ) + *err = c ? err_overflow : err_ok; + + return x; + } + + + + /*! + absolute value of x + e.g. -2 = 2 + 2 = 2 + */ + template + ValueType Abs(const ValueType & x) + { + ValueType result( x ); + result.Abs(); + + return result; + } + + + /*! + it returns the sign of the value + e.g. -2 = -1 + 0 = 0 + 10 = 1 + */ + template + ValueType Sgn(ValueType x) + { + x.Sgn(); + + return x; + } + + + /*! + the remainder from a division + + e.g. + mod( 12.6 ; 3) = 0.6 because 12.6 = 3*4 + 0.6 + mod(-12.6 ; 3) = -0.6 bacause -12.6 = 3*(-4) + (-0.6) + mod( 12.6 ; -3) = 0.6 + mod(-12.6 ; -3) = -0.6 + */ + template + ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0) + { + if( a.IsNan() || b.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + uint c = a.Mod(b); + + if( err ) + *err = c ? err_overflow : err_ok; + + return a; + } + + + + namespace auxiliaryfunctions + { + + /*! + this function is used to store factorials in a given container + 'more' means how many values should be added at the end + + e.g. + std::vector fact; + SetFactorialSequence(fact, 3); + // now the container has three values: 1 1 2 + + SetFactorialSequence(fact, 2); + // now the container has five values: 1 1 2 6 24 + */ + template + void SetFactorialSequence(std::vector & fact, uint more = 20) + { + if( more == 0 ) + more = 1; + + uint start = static_cast(fact.size()); + fact.resize(fact.size() + more); + + if( start == 0 ) + { + fact[0] = 1; + ++start; + } + + for(uint i=start ; i + ValueType SetBernoulliNumbersSum(CGamma & cgamma, const ValueType & n_, uint m, + const volatile StopCalculating * stop = 0) + { + ValueType k_, temp, temp2, temp3, sum; + + sum.SetZero(); + + for(uint k=0 ; kWasStopSignal() ) + return ValueType(); // NaN + + if( k>1 && (k & 1) == 1 ) // for that k the Bernoulli number is zero + continue; + + k_ = k; + + temp = n_; // n_ is equal 2 + temp.Pow(k_); + // temp = 2^k + + temp2 = cgamma.fact[m]; + temp3 = cgamma.fact[k]; + temp3.Mul(cgamma.fact[m-k]); + temp2.Div(temp3); + // temp2 = (m k) = m! / ( k! * (m-k)! ) + + temp.Mul(temp2); + temp.Mul(cgamma.bern[k]); + + sum.Add(temp); + // sum += 2^k * (m k) * B(k) + + if( sum.IsNan() ) + break; + } + + return sum; + } + + + /*! + an auxiliary function used to calculate Bernoulli numbers + start is >= 2 + + we use the recurrence formula: + B(m) = 1 / (2*(1 - 2^m)) * sum(m) + where sum(m) is calculated by SetBernoulliNumbersSum() + */ + template + bool SetBernoulliNumbersMore(CGamma & cgamma, uint start, const volatile StopCalculating * stop = 0) + { + ValueType denominator, temp, temp2, temp3, m_, sum, sum2, n_, k_; + + const uint n = 2; + n_ = n; + + // start is >= 2 + for(uint m=start ; mWasStopSignal() ) + { + cgamma.bern.resize(m); // valid numbers are in [0, m-1] + return false; + } + + cgamma.bern[m].Div(denominator); + } + } + + return true; + } + + + /*! + this function is used to calculate Bernoulli numbers, + returns false if there was a stop signal, + 'more' means how many values should be added at the end + + e.g. + typedef Big<1,2> MyBig; + CGamma cgamma; + SetBernoulliNumbers(cgamma, 3); + // now we have three first Bernoulli numbers: 1 -0.5 0.16667 + + SetBernoulliNumbers(cgamma, 4); + // now we have 7 Bernoulli numbers: 1 -0.5 0.16667 0 -0.0333 0 0.0238 + */ + template + bool SetBernoulliNumbers(CGamma & cgamma, uint more = 20, const volatile StopCalculating * stop = 0) + { + if( more == 0 ) + more = 1; + + uint start = static_cast(cgamma.bern.size()); + cgamma.bern.resize(cgamma.bern.size() + more); + + if( start == 0 ) + { + cgamma.bern[0].SetOne(); + ++start; + } + + if( cgamma.bern.size() == 1 ) + return true; + + if( start == 1 ) + { + cgamma.bern[1].Set05(); + cgamma.bern[1].ChangeSign(); + ++start; + } + + // we should have sufficient factorials in cgamma.fact + if( cgamma.fact.size() < cgamma.bern.size() ) + SetFactorialSequence(cgamma.fact, static_cast(cgamma.bern.size() - cgamma.fact.size())); + + + return SetBernoulliNumbersMore(cgamma, start, stop); + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + we calculate a sum: + sum(n) = sum_{m=2} { B(m) / ( (m^2 - m) * n^(m-1) ) } = 1/(12*n) - 1/(360*n^3) + 1/(1260*n^5) + ... + B(m) means a mth Bernoulli number + the sum starts from m=2, we calculate as long as the value will not change after adding a next part + */ + template + ValueType GammaFactorialHighSum(const ValueType & n, CGamma & cgamma, ErrorCode & err, + const volatile StopCalculating * stop) + { + ValueType temp, temp2, denominator, sum, oldsum; + + sum.SetZero(); + + for(uint m=2 ; mWasStopSignal() ) + { + err = err_interrupt; + return ValueType(); // NaN + } + + temp = (m-1); + denominator = n; + denominator.Pow(temp); + // denominator = n ^ (m-1) + + temp = m; + temp2 = temp; + temp.Mul(temp2); + temp.Sub(temp2); + // temp = m^2 - m + + denominator.Mul(temp); + // denominator = (m^2 - m) * n ^ (m-1) + + if( m >= cgamma.bern.size() ) + { + if( !SetBernoulliNumbers(cgamma, m - cgamma.bern.size() + 1 + 3, stop) ) // 3 more than needed + { + // there was the stop signal + err = err_interrupt; + return ValueType(); // NaN + } + } + + temp = cgamma.bern[m]; + temp.Div(denominator); + + oldsum = sum; + sum.Add(temp); + + if( sum.IsNan() || oldsum==sum ) + break; + } + + return sum; + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + we calculate a helper function GammaFactorialHigh() by using Stirling's series: + n! = (n/e)^n * sqrt(2*pi*n) * exp( sum(n) ) + where n is a real number (not only an integer) and is sufficient large (greater than TTMATH_GAMMA_BOUNDARY) + and sum(n) is calculated by GammaFactorialHighSum() + */ + template + ValueType GammaFactorialHigh(const ValueType & n, CGamma & cgamma, ErrorCode & err, + const volatile StopCalculating * stop) + { + ValueType temp, temp2, temp3, denominator, sum; + + temp.Set2Pi(); + temp.Mul(n); + temp2 = Sqrt(temp); + // temp2 = sqrt(2*pi*n) + + temp = n; + temp3.SetE(); + temp.Div(temp3); + temp.Pow(n); + // temp = (n/e)^n + + sum = GammaFactorialHighSum(n, cgamma, err, stop); + temp3.Exp(sum); + // temp3 = exp(sum) + + temp.Mul(temp2); + temp.Mul(temp3); + + return temp; + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + Gamma(x) = GammaFactorialHigh(x-1) + */ + template + ValueType GammaPlusHigh(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + ValueType one; + + one.SetOne(); + n.Sub(one); + + return GammaFactorialHigh(n, cgamma, err, stop); + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + we use this function when n is integer and a small value (from 0 to TTMATH_GAMMA_BOUNDARY] + we use the formula: + gamma(n) = (n-1)! = 1 * 2 * 3 * ... * (n-1) + */ + template + ValueType GammaPlusLowIntegerInt(uint n, CGamma & cgamma) + { + TTMATH_ASSERT( n > 0 ) + + if( n - 1 < static_cast(cgamma.fact.size()) ) + return cgamma.fact[n - 1]; + + ValueType res; + uint start = 2; + + if( cgamma.fact.size() < 2 ) + { + res.SetOne(); + } + else + { + start = static_cast(cgamma.fact.size()); + res = cgamma.fact[start-1]; + } + + for(uint i=start ; i + ValueType GammaPlusLowInteger(const ValueType & n, CGamma & cgamma) + { + sint n_; + + n.ToInt(n_); + + return GammaPlusLowIntegerInt(n_, cgamma); + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + we use this function when n is a small value (from 0 to TTMATH_GAMMA_BOUNDARY] + we use a recurrence formula: + gamma(z+1) = z * gamma(z) + then: gamma(z) = gamma(z+1) / z + + e.g. + gamma(3.89) = gamma(2001.89) / ( 3.89 * 4.89 * 5.89 * ... * 1999.89 * 2000.89 ) + */ + template + ValueType GammaPlusLow(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + ValueType one, denominator, temp, boundary; + + if( n.IsInteger() ) + return GammaPlusLowInteger(n, cgamma); + + one.SetOne(); + denominator = n; + boundary = TTMATH_GAMMA_BOUNDARY; + + while( n < boundary ) + { + n.Add(one); + denominator.Mul(n); + } + + n.Add(one); + + // now n is sufficient big + temp = GammaPlusHigh(n, cgamma, err, stop); + temp.Div(denominator); + + return temp; + } + + + /*! + an auxiliary function used to calculate the Gamma() function + */ + template + ValueType GammaPlus(const ValueType & n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + if( n > TTMATH_GAMMA_BOUNDARY ) + return GammaPlusHigh(n, cgamma, err, stop); + + return GammaPlusLow(n, cgamma, err, stop); + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + this function is used when n is negative + we use the reflection formula: + gamma(1-z) * gamma(z) = pi / sin(pi*z) + then: gamma(z) = pi / (sin(pi*z) * gamma(1-z)) + + */ + template + ValueType GammaMinus(const ValueType & n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + ValueType pi, denominator, temp, temp2; + + if( n.IsInteger() ) + { + // gamma function is not defined when n is negative and integer + err = err_improper_argument; + return temp; // NaN + } + + pi.SetPi(); + + temp = pi; + temp.Mul(n); + temp2 = Sin(temp); + // temp2 = sin(pi * n) + + temp.SetOne(); + temp.Sub(n); + temp = GammaPlus(temp, cgamma, err, stop); + // temp = gamma(1 - n) + + temp.Mul(temp2); + pi.Div(temp); + + return pi; + } + + } // namespace auxiliaryfunctions + + + + /*! + this function calculates the Gamma function + + it's multithread safe, you should create a CGamma<> object and use it whenever you call the Gamma() + e.g. + typedef Big<1,2> MyBig; + MyBig x=234, y=345.53; + CGamma cgamma; + std::cout << Gamma(x, cgamma) << std::endl; + std::cout << Gamma(y, cgamma) << std::endl; + in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers), + and they will be reused in next calls to the function + + each thread should have its own CGamma<> object, and you can use these objects with Factorial() function too + */ + template + ValueType Gamma(const ValueType & n, CGamma & cgamma, ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + using namespace auxiliaryfunctions; + + ValueType result; + ErrorCode err_tmp; + + if( n.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( cgamma.history.Get(n, result, err_tmp) ) + { + if( err ) + *err = err_tmp; + + return result; + } + + err_tmp = err_ok; + + if( n.IsSign() ) + { + result = GammaMinus(n, cgamma, err_tmp, stop); + } + else + if( n.IsZero() ) + { + err_tmp = err_improper_argument; + result.SetNan(); + } + else + { + result = GammaPlus(n, cgamma, err_tmp, stop); + } + + if( result.IsNan() && err_tmp==err_ok ) + err_tmp = err_overflow; + + if( err ) + *err = err_tmp; + + if( stop && !stop->WasStopSignal() ) + cgamma.history.Add(n, result, err_tmp); + + return result; + } + + + /*! + this function calculates the Gamma function + + note: this function should be used only in a single-thread environment + */ + template + ValueType Gamma(const ValueType & n, ErrorCode * err = 0) + { + // warning: this static object is not thread safe + static CGamma cgamma; + + return Gamma(n, cgamma, err); + } + + + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the factorial function + + we use the formula: + x! = gamma(x+1) + */ + template + ValueType Factorial2(ValueType x, + CGamma * cgamma = 0, + ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + ValueType result, one; + + if( x.IsNan() || x.IsSign() || !x.IsInteger() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN set by default + } + + one.SetOne(); + x.Add(one); + + if( cgamma ) + return Gamma(x, *cgamma, err, stop); + + return Gamma(x, err); + } + + } // namespace auxiliaryfunctions + + + + /*! + the factorial from given 'x' + e.g. + Factorial(4) = 4! = 1*2*3*4 + + it's multithread safe, you should create a CGamma<> object and use it whenever you call the Factorial() + e.g. + typedef Big<1,2> MyBig; + MyBig x=234, y=54345; + CGamma cgamma; + std::cout << Factorial(x, cgamma) << std::endl; + std::cout << Factorial(y, cgamma) << std::endl; + in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers), + and they will be reused in next calls to the function + + each thread should have its own CGamma<> object, and you can use these objects with Gamma() function too + */ + template + ValueType Factorial(const ValueType & x, CGamma & cgamma, ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + return auxiliaryfunctions::Factorial2(x, &cgamma, err, stop); + } + + + /*! + the factorial from given 'x' + e.g. + Factorial(4) = 4! = 1*2*3*4 + + note: this function should be used only in a single-thread environment + */ + template + ValueType Factorial(const ValueType & x, ErrorCode * err = 0) + { + return auxiliaryfunctions::Factorial2(x, (CGamma*)0, err, 0); + } + + + /*! + this method prepares some coefficients: factorials and Bernoulli numbers + stored in 'fact' and 'bern' objects + + we're defining the method here because we're using Gamma() function which + is not available in ttmathobjects.h + + read the doc info in ttmathobjects.h file where CGamma<> struct is declared + */ + template + void CGamma::InitAll() + { + ValueType x = TTMATH_GAMMA_BOUNDARY + 1; + + // history.Remove(x) removes only one object + // we must be sure that there are not others objects with the key 'x' + while( history.Remove(x) ) + { + } + + // the simplest way to initialize is to call the Gamma function with (TTMATH_GAMMA_BOUNDARY + 1) + // when x is larger then fewer coefficients we need + Gamma(x, *this); + } + + + +} // namespace + + +/*! + this is for convenience for the user + he can only use '#include ' even if he uses the parser +*/ +#include "ttmathparser.h" + + +#ifdef _MSC_VER +//warning C4127: conditional expression is constant +#pragma warning( default: 4127 ) +//warning C4702: unreachable code +#pragma warning( default: 4702 ) +//warning C4800: forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( default: 4800 ) +#endif + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathbig.h b/src/libghost/ttmath/ttmath/ttmathbig.h new file mode 100644 index 0000000..771f9c8 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathbig.h @@ -0,0 +1,5236 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + +#ifndef headerfilettmathbig +#define headerfilettmathbig + +/*! + \file ttmathbig.h + \brief A Class for representing floating point numbers +*/ + +#include "ttmathint.h" +#include "ttmaththreads.h" + +#include + +#ifdef TTMATH_MULTITHREADS +#include +#endif + +namespace ttmath +{ + + +/*! + \brief Big implements the floating point numbers +*/ +template +class Big +{ + +/* + value = mantissa * 2^exponent + + exponent - an integer value with a sign + mantissa - an integer value without a sing + + mantissa must be pushed into the left side that is the highest bit from + mantissa must be one (of course if there's another value than zero) -- this job + (pushing bits into the left side) making Standardizing() method + + for example: + if we want to store value one (1) into our Big object we must: + set mantissa to 1 + set exponent to 0 + set info to 0 + and call method Standardizing() +*/ + + +public: + +Int exponent; +UInt mantissa; +unsigned char info; + + +/*! + Sign + the mask of a bit from 'info' which means that there is a sign + (when the bit is set) +*/ +#define TTMATH_BIG_SIGN 128 + + +/*! + Not a number + if this bit is set that there is not a valid number +*/ +#define TTMATH_BIG_NAN 64 + + +/*! + Zero + if this bit is set that there is value zero + mantissa should be zero and exponent should be zero too + (the Standardizing() method does this) +*/ +#define TTMATH_BIG_ZERO 32 + + + /*! + this method sets NaN if there was a carry (and returns 1 in such a case) + + c can be 0, 1 or other value different from zero + */ + uint CheckCarry(uint c) + { + if( c != 0 ) + { + SetNan(); + return 1; + } + + return 0; + } + +public: + + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + static const char * LibTypeStr() + { + return UInt::LibTypeStr(); + } + + + /*! + returning the currect type of the library + */ + static LibTypeCode LibType() + { + return UInt::LibType(); + } + + + + /*! + this method moves all bits from mantissa into its left side + (suitably changes the exponent) or if the mantissa is zero + it sets the exponent to zero as well + (and clears the sign bit and sets the zero bit) + + it can return a carry + the carry will be when we don't have enough space in the exponent + + you don't have to use this method if you don't change the mantissa + and exponent directly + */ + uint Standardizing() + { + if( mantissa.IsTheHighestBitSet() ) + { + ClearInfoBit(TTMATH_BIG_ZERO); + return 0; + } + + if( CorrectZero() ) + return 0; + + uint comp = mantissa.CompensationToLeft(); + + return exponent.Sub( comp ); + } + + +private: + + /*! + if the mantissa is equal zero this method sets exponent to zero and + info without the sign + + it returns true if there was the correction + */ + bool CorrectZero() + { + if( mantissa.IsZero() ) + { + SetInfoBit(TTMATH_BIG_ZERO); + ClearInfoBit(TTMATH_BIG_SIGN); + exponent.SetZero(); + + return true; + } + else + { + ClearInfoBit(TTMATH_BIG_ZERO); + } + + return false; + } + + +public: + + /*! + this method clears a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + void ClearInfoBit(unsigned char bit) + { + info = info & (~bit); + } + + + /*! + this method sets a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + + */ + void SetInfoBit(unsigned char bit) + { + info = info | bit; + } + + + /*! + this method returns true if a specific bit in the 'info' variable is set + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + bool IsInfoBit(unsigned char bit) const + { + return (info & bit) != 0; + } + + + /*! + this method sets zero + */ + void SetZero() + { + info = TTMATH_BIG_ZERO; + exponent.SetZero(); + mantissa.SetZero(); + + /* + we don't have to compensate zero + */ + } + + + /*! + this method sets one + */ + void SetOne() + { + FromUInt(1); + } + + + /*! + this method sets value 0.5 + */ + void Set05() + { + FromUInt(1); + exponent.SubOne(); + } + + + /*! + this method sets NaN flag (Not a Number) + when this flag is set that means there is no a valid number + */ + void SetNan() + { + SetInfoBit(TTMATH_BIG_NAN); + } + + +private: + + /*! + this method sets the mantissa of the value of pi + */ + void SetMantissaPi() + { + // this is a static table which represents the value of Pi (mantissa of it) + // (first is the highest word) + // we must define this table as 'unsigned int' because + // both on 32bit and 64bit platforms this table is 32bit + static const unsigned int temp_table[] = { + 0xc90fdaa2, 0x2168c234, 0xc4c6628b, 0x80dc1cd1, 0x29024e08, 0x8a67cc74, 0x020bbea6, 0x3b139b22, + 0x514a0879, 0x8e3404dd, 0xef9519b3, 0xcd3a431b, 0x302b0a6d, 0xf25f1437, 0x4fe1356d, 0x6d51c245, + 0xe485b576, 0x625e7ec6, 0xf44c42e9, 0xa637ed6b, 0x0bff5cb6, 0xf406b7ed, 0xee386bfb, 0x5a899fa5, + 0xae9f2411, 0x7c4b1fe6, 0x49286651, 0xece45b3d, 0xc2007cb8, 0xa163bf05, 0x98da4836, 0x1c55d39a, + 0x69163fa8, 0xfd24cf5f, 0x83655d23, 0xdca3ad96, 0x1c62f356, 0x208552bb, 0x9ed52907, 0x7096966d, + 0x670c354e, 0x4abc9804, 0xf1746c08, 0xca18217c, 0x32905e46, 0x2e36ce3b, 0xe39e772c, 0x180e8603, + 0x9b2783a2, 0xec07a28f, 0xb5c55df0, 0x6f4c52c9, 0xde2bcbf6, 0x95581718, 0x3995497c, 0xea956ae5, + 0x15d22618, 0x98fa0510, 0x15728e5a, 0x8aaac42d, 0xad33170d, 0x04507a33, 0xa85521ab, 0xdf1cba64, + 0xecfb8504, 0x58dbef0a, 0x8aea7157, 0x5d060c7d, 0xb3970f85, 0xa6e1e4c7, 0xabf5ae8c, 0xdb0933d7, + 0x1e8c94e0, 0x4a25619d, 0xcee3d226, 0x1ad2ee6b, 0xf12ffa06, 0xd98a0864, 0xd8760273, 0x3ec86a64, + 0x521f2b18, 0x177b200c, 0xbbe11757, 0x7a615d6c, 0x770988c0, 0xbad946e2, 0x08e24fa0, 0x74e5ab31, + 0x43db5bfc, 0xe0fd108e, 0x4b82d120, 0xa9210801, 0x1a723c12, 0xa787e6d7, 0x88719a10, 0xbdba5b26, + 0x99c32718, 0x6af4e23c, 0x1a946834, 0xb6150bda, 0x2583e9ca, 0x2ad44ce8, 0xdbbbc2db, 0x04de8ef9, + 0x2e8efc14, 0x1fbecaa6, 0x287c5947, 0x4e6bc05d, 0x99b2964f, 0xa090c3a2, 0x233ba186, 0x515be7ed, + 0x1f612970, 0xcee2d7af, 0xb81bdd76, 0x2170481c, 0xd0069127, 0xd5b05aa9, 0x93b4ea98, 0x8d8fddc1, + 0x86ffb7dc, 0x90a6c08f, 0x4df435c9, 0x34028492, 0x36c3fab4, 0xd27c7026, 0xc1d4dcb2, 0x602646de, + 0xc9751e76, 0x3dba37bd, 0xf8ff9406, 0xad9e530e, 0xe5db382f, 0x413001ae, 0xb06a53ed, 0x9027d831, + 0x179727b0, 0x865a8918, 0xda3edbeb, 0xcf9b14ed, 0x44ce6cba, 0xced4bb1b, 0xdb7f1447, 0xe6cc254b, + 0x33205151, 0x2bd7af42, 0x6fb8f401, 0x378cd2bf, 0x5983ca01, 0xc64b92ec, 0xf032ea15, 0xd1721d03, + 0xf482d7ce, 0x6e74fef6, 0xd55e702f, 0x46980c82, 0xb5a84031, 0x900b1c9e, 0x59e7c97f, 0xbec7e8f3, + 0x23a97a7e, 0x36cc88be, 0x0f1d45b7, 0xff585ac5, 0x4bd407b2, 0x2b4154aa, 0xcc8f6d7e, 0xbf48e1d8, + 0x14cc5ed2, 0x0f8037e0, 0xa79715ee, 0xf29be328, 0x06a1d58b, 0xb7c5da76, 0xf550aa3d, 0x8a1fbff0, + 0xeb19ccb1, 0xa313d55c, 0xda56c9ec, 0x2ef29632, 0x387fe8d7, 0x6e3c0468, 0x043e8f66, 0x3f4860ee, + 0x12bf2d5b, 0x0b7474d6, 0xe694f91e, 0x6dbe1159, 0x74a3926f, 0x12fee5e4, 0x38777cb6, 0xa932df8c, + 0xd8bec4d0, 0x73b931ba, 0x3bc832b6, 0x8d9dd300, 0x741fa7bf, 0x8afc47ed, 0x2576f693, 0x6ba42466, + 0x3aab639c, 0x5ae4f568, 0x3423b474, 0x2bf1c978, 0x238f16cb, 0xe39d652d, 0xe3fdb8be, 0xfc848ad9, + 0x22222e04, 0xa4037c07, 0x13eb57a8, 0x1a23f0c7, 0x3473fc64, 0x6cea306b, 0x4bcbc886, 0x2f8385dd, + 0xfa9d4b7f, 0xa2c087e8, 0x79683303, 0xed5bdd3a, 0x062b3cf5, 0xb3a278a6, 0x6d2a13f8, 0x3f44f82d, + 0xdf310ee0, 0x74ab6a36, 0x4597e899, 0xa0255dc1, 0x64f31cc5, 0x0846851d, 0xf9ab4819, 0x5ded7ea1, + 0xb1d510bd, 0x7ee74d73, 0xfaf36bc3, 0x1ecfa268, 0x359046f4, 0xeb879f92, 0x4009438b, 0x481c6cd7, + 0x889a002e, 0xd5ee382b, 0xc9190da6, 0xfc026e47, 0x9558e447, 0x5677e9aa, 0x9e3050e2, 0x765694df, + 0xc81f56e8, 0x80b96e71, 0x60c980dd, 0x98a573ea, 0x4472065a, 0x139cd290, 0x6cd1cb72, 0x9ec52a53 // last one was: 0x9ec52a52 + //0x86d44014, ... + // (the last word 0x9ec52a52 was rounded up because the next one is 0x86d44014 -- first bit is one 0x8..) + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + // the value of PI is comming from the website http://zenwerx.com/pi.php + // 3101 digits were taken from this website + // (later the digits were compared with: + // http://www.eveandersson.com/pi/digits/1000000 and http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html ) + // and they were set into Big<1,400> type (using operator=(const char*) on a 32bit platform) + // and then the first 256 words were taken into this table + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + } + +public: + + + /*! + this method sets the value of pi + */ + void SetPi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + } + + + /*! + this method sets the value of 0.5 * pi + */ + void Set05Pi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 1; + } + + + /*! + this method sets the value of 2 * pi + */ + void Set2Pi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 3; + } + + + /*! + this method sets the value of e + (the base of the natural logarithm) + */ + void SetE() + { + static const unsigned int temp_table[] = { + 0xadf85458, 0xa2bb4a9a, 0xafdc5620, 0x273d3cf1, 0xd8b9c583, 0xce2d3695, 0xa9e13641, 0x146433fb, + 0xcc939dce, 0x249b3ef9, 0x7d2fe363, 0x630c75d8, 0xf681b202, 0xaec4617a, 0xd3df1ed5, 0xd5fd6561, + 0x2433f51f, 0x5f066ed0, 0x85636555, 0x3ded1af3, 0xb557135e, 0x7f57c935, 0x984f0c70, 0xe0e68b77, + 0xe2a689da, 0xf3efe872, 0x1df158a1, 0x36ade735, 0x30acca4f, 0x483a797a, 0xbc0ab182, 0xb324fb61, + 0xd108a94b, 0xb2c8e3fb, 0xb96adab7, 0x60d7f468, 0x1d4f42a3, 0xde394df4, 0xae56ede7, 0x6372bb19, + 0x0b07a7c8, 0xee0a6d70, 0x9e02fce1, 0xcdf7e2ec, 0xc03404cd, 0x28342f61, 0x9172fe9c, 0xe98583ff, + 0x8e4f1232, 0xeef28183, 0xc3fe3b1b, 0x4c6fad73, 0x3bb5fcbc, 0x2ec22005, 0xc58ef183, 0x7d1683b2, + 0xc6f34a26, 0xc1b2effa, 0x886b4238, 0x611fcfdc, 0xde355b3b, 0x6519035b, 0xbc34f4de, 0xf99c0238, + 0x61b46fc9, 0xd6e6c907, 0x7ad91d26, 0x91f7f7ee, 0x598cb0fa, 0xc186d91c, 0xaefe1309, 0x85139270, + 0xb4130c93, 0xbc437944, 0xf4fd4452, 0xe2d74dd3, 0x64f2e21e, 0x71f54bff, 0x5cae82ab, 0x9c9df69e, + 0xe86d2bc5, 0x22363a0d, 0xabc52197, 0x9b0deada, 0x1dbf9a42, 0xd5c4484e, 0x0abcd06b, 0xfa53ddef, + 0x3c1b20ee, 0x3fd59d7c, 0x25e41d2b, 0x669e1ef1, 0x6e6f52c3, 0x164df4fb, 0x7930e9e4, 0xe58857b6, + 0xac7d5f42, 0xd69f6d18, 0x7763cf1d, 0x55034004, 0x87f55ba5, 0x7e31cc7a, 0x7135c886, 0xefb4318a, + 0xed6a1e01, 0x2d9e6832, 0xa907600a, 0x918130c4, 0x6dc778f9, 0x71ad0038, 0x092999a3, 0x33cb8b7a, + 0x1a1db93d, 0x7140003c, 0x2a4ecea9, 0xf98d0acc, 0x0a8291cd, 0xcec97dcf, 0x8ec9b55a, 0x7f88a46b, + 0x4db5a851, 0xf44182e1, 0xc68a007e, 0x5e0dd902, 0x0bfd64b6, 0x45036c7a, 0x4e677d2c, 0x38532a3a, + 0x23ba4442, 0xcaf53ea6, 0x3bb45432, 0x9b7624c8, 0x917bdd64, 0xb1c0fd4c, 0xb38e8c33, 0x4c701c3a, + 0xcdad0657, 0xfccfec71, 0x9b1f5c3e, 0x4e46041f, 0x388147fb, 0x4cfdb477, 0xa52471f7, 0xa9a96910, + 0xb855322e, 0xdb6340d8, 0xa00ef092, 0x350511e3, 0x0abec1ff, 0xf9e3a26e, 0x7fb29f8c, 0x183023c3, + 0x587e38da, 0x0077d9b4, 0x763e4e4b, 0x94b2bbc1, 0x94c6651e, 0x77caf992, 0xeeaac023, 0x2a281bf6, + 0xb3a739c1, 0x22611682, 0x0ae8db58, 0x47a67cbe, 0xf9c9091b, 0x462d538c, 0xd72b0374, 0x6ae77f5e, + 0x62292c31, 0x1562a846, 0x505dc82d, 0xb854338a, 0xe49f5235, 0xc95b9117, 0x8ccf2dd5, 0xcacef403, + 0xec9d1810, 0xc6272b04, 0x5b3b71f9, 0xdc6b80d6, 0x3fdd4a8e, 0x9adb1e69, 0x62a69526, 0xd43161c1, + 0xa41d570d, 0x7938dad4, 0xa40e329c, 0xcff46aaa, 0x36ad004c, 0xf600c838, 0x1e425a31, 0xd951ae64, + 0xfdb23fce, 0xc9509d43, 0x687feb69, 0xedd1cc5e, 0x0b8cc3bd, 0xf64b10ef, 0x86b63142, 0xa3ab8829, + 0x555b2f74, 0x7c932665, 0xcb2c0f1c, 0xc01bd702, 0x29388839, 0xd2af05e4, 0x54504ac7, 0x8b758282, + 0x2846c0ba, 0x35c35f5c, 0x59160cc0, 0x46fd8251, 0x541fc68c, 0x9c86b022, 0xbb709987, 0x6a460e74, + 0x51a8a931, 0x09703fee, 0x1c217e6c, 0x3826e52c, 0x51aa691e, 0x0e423cfc, 0x99e9e316, 0x50c1217b, + 0x624816cd, 0xad9a95f9, 0xd5b80194, 0x88d9c0a0, 0xa1fe3075, 0xa577e231, 0x83f81d4a, 0x3f2fa457, + 0x1efc8ce0, 0xba8a4fe8, 0xb6855dfe, 0x72b0a66e, 0xded2fbab, 0xfbe58a30, 0xfafabe1c, 0x5d71a87e, + 0x2f741ef8, 0xc1fe86fe, 0xa6bbfde5, 0x30677f0d, 0x97d11d49, 0xf7a8443d, 0x0822e506, 0xa9f4614e, + 0x011e2a94, 0x838ff88c, 0xd68c8bb7, 0xc51eef6d, 0x49ea8ab4, 0xf2c3df5b, 0xb4e0735a, 0xb0d68749 + // 0x2fe26dd4, ... + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 words were taken, + // the calculating was made by using ExpSurrounding0(1) method + // which took 1420 iterations + // (the result was compared with e taken from http://antwrp.gsfc.nasa.gov/htmltest/gifcity/e.2mil) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + this method sets the value of ln(2) + the natural logarithm from 2 + */ + void SetLn2() + { + static const unsigned int temp_table[] = { + 0xb17217f7, 0xd1cf79ab, 0xc9e3b398, 0x03f2f6af, 0x40f34326, 0x7298b62d, 0x8a0d175b, 0x8baafa2b, + 0xe7b87620, 0x6debac98, 0x559552fb, 0x4afa1b10, 0xed2eae35, 0xc1382144, 0x27573b29, 0x1169b825, + 0x3e96ca16, 0x224ae8c5, 0x1acbda11, 0x317c387e, 0xb9ea9bc3, 0xb136603b, 0x256fa0ec, 0x7657f74b, + 0x72ce87b1, 0x9d6548ca, 0xf5dfa6bd, 0x38303248, 0x655fa187, 0x2f20e3a2, 0xda2d97c5, 0x0f3fd5c6, + 0x07f4ca11, 0xfb5bfb90, 0x610d30f8, 0x8fe551a2, 0xee569d6d, 0xfc1efa15, 0x7d2e23de, 0x1400b396, + 0x17460775, 0xdb8990e5, 0xc943e732, 0xb479cd33, 0xcccc4e65, 0x9393514c, 0x4c1a1e0b, 0xd1d6095d, + 0x25669b33, 0x3564a337, 0x6a9c7f8a, 0x5e148e82, 0x074db601, 0x5cfe7aa3, 0x0c480a54, 0x17350d2c, + 0x955d5179, 0xb1e17b9d, 0xae313cdb, 0x6c606cb1, 0x078f735d, 0x1b2db31b, 0x5f50b518, 0x5064c18b, + 0x4d162db3, 0xb365853d, 0x7598a195, 0x1ae273ee, 0x5570b6c6, 0x8f969834, 0x96d4e6d3, 0x30af889b, + 0x44a02554, 0x731cdc8e, 0xa17293d1, 0x228a4ef9, 0x8d6f5177, 0xfbcf0755, 0x268a5c1f, 0x9538b982, + 0x61affd44, 0x6b1ca3cf, 0x5e9222b8, 0x8c66d3c5, 0x422183ed, 0xc9942109, 0x0bbb16fa, 0xf3d949f2, + 0x36e02b20, 0xcee886b9, 0x05c128d5, 0x3d0bd2f9, 0x62136319, 0x6af50302, 0x0060e499, 0x08391a0c, + 0x57339ba2, 0xbeba7d05, 0x2ac5b61c, 0xc4e9207c, 0xef2f0ce2, 0xd7373958, 0xd7622658, 0x901e646a, + 0x95184460, 0xdc4e7487, 0x156e0c29, 0x2413d5e3, 0x61c1696d, 0xd24aaebd, 0x473826fd, 0xa0c238b9, + 0x0ab111bb, 0xbd67c724, 0x972cd18b, 0xfbbd9d42, 0x6c472096, 0xe76115c0, 0x5f6f7ceb, 0xac9f45ae, + 0xcecb72f1, 0x9c38339d, 0x8f682625, 0x0dea891e, 0xf07afff3, 0xa892374e, 0x175eb4af, 0xc8daadd8, + 0x85db6ab0, 0x3a49bd0d, 0xc0b1b31d, 0x8a0e23fa, 0xc5e5767d, 0xf95884e0, 0x6425a415, 0x26fac51c, + 0x3ea8449f, 0xe8f70edd, 0x062b1a63, 0xa6c4c60c, 0x52ab3316, 0x1e238438, 0x897a39ce, 0x78b63c9f, + 0x364f5b8a, 0xef22ec2f, 0xee6e0850, 0xeca42d06, 0xfb0c75df, 0x5497e00c, 0x554b03d7, 0xd2874a00, + 0x0ca8f58d, 0x94f0341c, 0xbe2ec921, 0x56c9f949, 0xdb4a9316, 0xf281501e, 0x53daec3f, 0x64f1b783, + 0x154c6032, 0x0e2ff793, 0x33ce3573, 0xfacc5fdc, 0xf1178590, 0x3155bbd9, 0x0f023b22, 0x0224fcd8, + 0x471bf4f4, 0x45f0a88a, 0x14f0cd97, 0x6ea354bb, 0x20cdb5cc, 0xb3db2392, 0x88d58655, 0x4e2a0e8a, + 0x6fe51a8c, 0xfaa72ef2, 0xad8a43dc, 0x4212b210, 0xb779dfe4, 0x9d7307cc, 0x846532e4, 0xb9694eda, + 0xd162af05, 0x3b1751f3, 0xa3d091f6, 0x56658154, 0x12b5e8c2, 0x02461069, 0xac14b958, 0x784934b8, + 0xd6cce1da, 0xa5053701, 0x1aa4fb42, 0xb9a3def4, 0x1bda1f85, 0xef6fdbf2, 0xf2d89d2a, 0x4b183527, + 0x8fd94057, 0x89f45681, 0x2b552879, 0xa6168695, 0xc12963b0, 0xff01eaab, 0x73e5b5c1, 0x585318e7, + 0x624f14a5, 0x1a4a026b, 0x68082920, 0x57fd99b6, 0x6dc085a9, 0x8ac8d8ca, 0xf9eeeea9, 0x8a2400ca, + 0xc95f260f, 0xd10036f9, 0xf91096ac, 0x3195220a, 0x1a356b2a, 0x73b7eaad, 0xaf6d6058, 0x71ef7afb, + 0x80bc4234, 0x33562e94, 0xb12dfab4, 0x14451579, 0xdf59eae0, 0x51707062, 0x4012a829, 0x62c59cab, + 0x347f8304, 0xd889659e, 0x5a9139db, 0x14efcc30, 0x852be3e8, 0xfc99f14d, 0x1d822dd6, 0xe2f76797, + 0xe30219c8, 0xaa9ce884, 0x8a886eb3, 0xc87b7295, 0x988012e8, 0x314186ed, 0xbaf86856, 0xccd3c3b6, + 0xee94e62f, 0x110a6783, 0xd2aae89c, 0xcc3b76fc, 0x435a0ce1, 0x34c2838f, 0xd571ec6c, 0x1366a993 // last one was: 0x1366a992 + //0xcbb9ac40, ... + // (the last word 0x1366a992 was rounded up because the next one is 0xcbb9ac40 -- first bit is one 0xc..) + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 words were taken, + // the calculating was made by using LnSurrounding1(2) method + // which took 4035 iterations + // (the result was compared with ln(2) taken from http://ja0hxv.calico.jp/pai/estart.html) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT); + info = 0; + } + + + /*! + this method sets the value of ln(10) + the natural logarithm from 10 + + I introduced this constant especially to make the conversion ToString() + being faster. In fact the method ToString() is keeping values of logarithms + it has calculated but it must calculate the logarithm at least once. + If a program, which uses this library, is running for a long time this + would be ok, but for programs which are running shorter, for example for + CGI applications which only once are printing values, this would be much + inconvenience. Then if we're printing with base (radix) 10 and the mantissa + of our value is smaller than or equal to TTMATH_BUILTIN_VARIABLES_SIZE + we don't calculate the logarithm but take it from this constant. + */ + void SetLn10() + { + static const unsigned int temp_table[] = { + 0x935d8ddd, 0xaaa8ac16, 0xea56d62b, 0x82d30a28, 0xe28fecf9, 0xda5df90e, 0x83c61e82, 0x01f02d72, + 0x962f02d7, 0xb1a8105c, 0xcc70cbc0, 0x2c5f0d68, 0x2c622418, 0x410be2da, 0xfb8f7884, 0x02e516d6, + 0x782cf8a2, 0x8a8c911e, 0x765aa6c3, 0xb0d831fb, 0xef66ceb0, 0x4ab3c6fa, 0x5161bb49, 0xd219c7bb, + 0xca67b35b, 0x23605085, 0x8e93368d, 0x44789c4f, 0x5b08b057, 0xd5ede20f, 0x469ea58e, 0x9305e981, + 0xe2478fca, 0xad3aee98, 0x9cd5b42e, 0x6a271619, 0xa47ecb26, 0x978c5d4f, 0xdb1d28ea, 0x57d4fdc0, + 0xe40bf3cc, 0x1e14126a, 0x45765cde, 0x268339db, 0xf47fa96d, 0xeb271060, 0xaf88486e, 0xa9b7401e, + 0x3dfd3c51, 0x748e6d6e, 0x3848c8d2, 0x5faf1bca, 0xe88047f1, 0x7b0d9b50, 0xa949eaaa, 0xdf69e8a5, + 0xf77e3760, 0x4e943960, 0xe38a5700, 0xffde2db1, 0xad6bfbff, 0xd821ba0a, 0x4cb0466d, 0x61ba648e, + 0xef99c8e5, 0xf6974f36, 0x3982a78c, 0xa45ddfc8, 0x09426178, 0x19127a6e, 0x3b70fcda, 0x2d732d47, + 0xb5e4b1c8, 0xc0e5a10a, 0xaa6604a5, 0x324ec3dc, 0xbc64ea80, 0x6e198566, 0x1f1d366c, 0x20663834, + 0x4d5e843f, 0x20642b97, 0x0a62d18e, 0x478f7bd5, 0x8fcd0832, 0x4a7b32a6, 0xdef85a05, 0xeb56323a, + 0x421ef5e0, 0xb00410a0, 0xa0d9c260, 0x794a976f, 0xf6ff363d, 0xb00b6b33, 0xf42c58de, 0xf8a3c52d, + 0xed69b13d, 0xc1a03730, 0xb6524dc1, 0x8c167e86, 0x99d6d20e, 0xa2defd2b, 0xd006f8b4, 0xbe145a2a, + 0xdf3ccbb3, 0x189da49d, 0xbc1261c8, 0xb3e4daad, 0x6a36cecc, 0xb2d5ae5b, 0x89bf752f, 0xb5dfb353, + 0xff3065c4, 0x0cfceec8, 0x1be5a9a9, 0x67fddc57, 0xc4b83301, 0x006bf062, 0x4b40ed7a, 0x56c6cdcd, + 0xa2d6fe91, 0x388e9e3e, 0x48a93f5f, 0x5e3b6eb4, 0xb81c4a5b, 0x53d49ea6, 0x8e668aea, 0xba83c7f8, + 0xfb5f06c3, 0x58ac8f70, 0xfa9d8c59, 0x8c574502, 0xbaf54c96, 0xc84911f0, 0x0482d095, 0x1a0af022, + 0xabbab080, 0xec97efd3, 0x671e4e0e, 0x52f166b6, 0xcd5cd226, 0x0dc67795, 0x2e1e34a3, 0xf799677f, + 0x2c1d48f1, 0x2944b6c5, 0x2ba1307e, 0x704d67f9, 0x1c1035e4, 0x4e927c63, 0x03cf12bf, 0xe2cd2e31, + 0xf8ee4843, 0x344d51b0, 0xf37da42b, 0x9f0b0fd9, 0x134fb2d9, 0xf815e490, 0xd966283f, 0x23962766, + 0xeceab1e4, 0xf3b5fc86, 0x468127e2, 0xb606d10d, 0x3a45f4b6, 0xb776102d, 0x2fdbb420, 0x80c8fa84, + 0xd0ff9f45, 0xc58aef38, 0xdb2410fd, 0x1f1cebad, 0x733b2281, 0x52ca5f36, 0xddf29daa, 0x544334b8, + 0xdeeaf659, 0x4e462713, 0x1ed485b4, 0x6a0822e1, 0x28db471c, 0xa53938a8, 0x44c3bef7, 0xf35215c8, + 0xb382bc4e, 0x3e4c6f15, 0x6285f54c, 0x17ab408e, 0xccbf7f5e, 0xd16ab3f6, 0xced2846d, 0xf457e14f, + 0xbb45d9c5, 0x646ad497, 0xac697494, 0x145de32e, 0x93907128, 0xd263d521, 0x79efb424, 0xd64651d6, + 0xebc0c9f0, 0xbb583a44, 0xc6412c84, 0x85bb29a6, 0x4d31a2cd, 0x92954469, 0xa32b1abd, 0xf7f5202c, + 0xa4aa6c93, 0x2e9b53cf, 0x385ab136, 0x2741f356, 0x5de9c065, 0x6009901c, 0x88abbdd8, 0x74efcf73, + 0x3f761ad4, 0x35f3c083, 0xfd6b8ee0, 0x0bef11c7, 0xc552a89d, 0x58ce4a21, 0xd71e54f2, 0x4157f6c7, + 0xd4622316, 0xe98956d7, 0x450027de, 0xcbd398d8, 0x4b98b36a, 0x0724c25c, 0xdb237760, 0xe9324b68, + 0x7523e506, 0x8edad933, 0x92197f00, 0xb853a326, 0xb330c444, 0x65129296, 0x34bc0670, 0xe177806d, + 0xe338dac4, 0x5537492a, 0xe19add83, 0xcf45000f, 0x5b423bce, 0x6497d209, 0xe30e18a1, 0x3cbf0687, + 0x67973103, 0xd9485366, 0x81506bba, 0x2e93a9a4, 0x7dd59d3f, 0xf17cd746, 0x8c2075be, 0x552a4348 // last one was: 0x552a4347 + // 0xb4a638ef, ... + //(the last word 0x552a4347 was rounded up because the next one is 0xb4a638ef -- first bit is one 0xb..) + // 256 32bit words for the mantissa -- about 2464 valid digits (decimal) + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 32bit words were taken, + // the calculating was made by using LnSurrounding1(10) method + // which took 22080 iterations + // (the result was compared with ln(10) taken from http://ja0hxv.calico.jp/pai/estart.html) + // (the formula used in LnSurrounding1(x) converges badly when + // the x is greater than one but in fact we can use it, only the + // number of iterations will be greater) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + this method sets the maximum value which can be held in this type + */ + void SetMax() + { + info = 0; + mantissa.SetMax(); + exponent.SetMax(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + this method sets the minimum value which can be held in this type + */ + void SetMin() + { + info = 0; + + mantissa.SetMax(); + exponent.SetMax(); + SetSign(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + testing whether there is a value zero or not + */ + bool IsZero() const + { + return IsInfoBit(TTMATH_BIG_ZERO); + } + + + /*! + this method returns true when there's the sign set + also we don't check the NaN flag + */ + bool IsSign() const + { + return IsInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method returns true when there is not a valid number + */ + bool IsNan() const + { + return IsInfoBit(TTMATH_BIG_NAN); + } + + + + /*! + this method clears the sign + (there'll be an absolute value) + + e.g. + -1 -> 1 + 2 -> 2 + */ + void Abs() + { + ClearInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method remains the 'sign' of the value + e.g. -2 = -1 + 0 = 0 + 10 = 1 + */ + void Sgn() + { + // we have to check the NaN flag, because the next SetOne() method would clear it + if( IsNan() ) + return; + + if( IsSign() ) + { + SetOne(); + SetSign(); + } + else + if( IsZero() ) + SetZero(); + else + SetOne(); + } + + + + /*! + this method sets the sign + + e.g. + -1 -> -1 + 2 -> -2 + + we do not check whether there is a zero or not, if you're using this method + you must be sure that the value is (or will be afterwards) different from zero + */ + void SetSign() + { + SetInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method changes the sign + when there is a value of zero then the sign is not changed + + e.g. + -1 -> 1 + 2 -> -2 + */ + void ChangeSign() + { + // we don't have to check the NaN flag here + + if( IsZero() ) + return; + + if( IsSign() ) + ClearInfoBit(TTMATH_BIG_SIGN); + else + SetInfoBit(TTMATH_BIG_SIGN); + } + + + +private: + + /*! + this method does the half-to-even rounding (banker's rounding) + + if is_half is: + true - that means the rest was equal the half (0.5 decimal) + false - that means the rest was greater than a half (greater than 0.5 decimal) + + if the rest was less than a half then don't call this method + (the rounding should does nothing then) + */ + uint RoundHalfToEven(bool is_half, bool rounding_up = true) + { + uint c = 0; + + if( !is_half || mantissa.IsTheLowestBitSet() ) + { + if( rounding_up ) + { + if( mantissa.AddOne() ) + { + mantissa.Rcr(1, 1); + c = exponent.AddOne(); + } + } + else + { + #ifdef TTMATH_DEBUG + uint c_from_zero = + #endif + mantissa.SubOne(); + + // we're using rounding_up=false in Add() when the mantissas have different signs + // mantissa can be zero only when previous mantissa was equal to ss2.mantissa + // but in such a case 'last_bit_set' will not be set and consequently 'do_rounding' will be false + TTMATH_ASSERT( c_from_zero == 0 ) + } + } + + return c; + } + + + + + + /*! + * + * basic mathematic functions + * + */ + +private: + + + /*! + an auxiliary method for adding + */ + void AddCheckExponents( Big & ss2, + Int & exp_offset, + bool & last_bit_set, + bool & rest_zero, + bool & do_adding, + bool & do_rounding) + { + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + if( exp_offset == mantissa_size_in_bits ) + { + last_bit_set = ss2.mantissa.IsTheHighestBitSet(); + rest_zero = ss2.mantissa.AreFirstBitsZero(man*TTMATH_BITS_PER_UINT - 1); + do_rounding = true; // we'are only rounding + } + else + if( exp_offset < mantissa_size_in_bits ) + { + uint moved = exp_offset.ToInt(); // how many times we must move ss2.mantissa + rest_zero = true; + + if( moved > 0 ) + { + last_bit_set = static_cast( ss2.mantissa.GetBit(moved-1) ); + + if( moved > 1 ) + rest_zero = ss2.mantissa.AreFirstBitsZero(moved - 1); + + // (2) moving 'exp_offset' times + ss2.mantissa.Rcr(moved, 0); + } + + do_adding = true; + do_rounding = true; + } + + // if exp_offset is greater than mantissa_size_in_bits then we do nothing + // ss2 is too small for taking into consideration in the sum + } + + + /*! + an auxiliary method for adding + */ + uint AddMantissas( Big & ss2, + bool & last_bit_set, + bool & rest_zero, + bool & rounding_up) + { + uint c = 0; + + if( IsSign() == ss2.IsSign() ) + { + // values have the same signs + if( mantissa.Add(ss2.mantissa) ) + { + // we have one bit more from addition (carry) + // now rest_zero means the old rest_zero with the old last_bit_set + rest_zero = (!last_bit_set && rest_zero); + last_bit_set = mantissa.Rcr(1,1); + c += exponent.AddOne(); + } + + rounding_up = true; + } + else + { + // values have different signs + // there shouldn't be a carry here because + // (1) (2) guarantee that the mantissa of this + // is greater than or equal to the mantissa of the ss2 + + #ifdef TTMATH_DEBUG + uint c_temp = + #endif + mantissa.Sub(ss2.mantissa); + + TTMATH_ASSERT( c_temp == 0 ) + } + + return c; + } + + +public: + + + /*! + Addition this = this + ss2 + + it returns carry if the sum is too big + */ + uint Add(Big ss2, bool round = true) + { + bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up; + Int exp_offset( exponent ); + uint c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // (1) abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + // !! use Swap here (not implemented yet) + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( ss2.IsZero() ) + return 0; + + last_bit_set = rest_zero = do_adding = do_rounding = rounding_up = false; + AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding); + + if( do_adding ) + c += AddMantissas(ss2, last_bit_set, rest_zero, rounding_up); + + if( !round || !last_bit_set ) + do_rounding = false; + + if( do_rounding ) + c += RoundHalfToEven(rest_zero, rounding_up); + + if( do_adding || do_rounding ) + c += Standardizing(); + + return CheckCarry(c); + } + + + + /*! + Subtraction this = this - ss2 + + it returns carry if the result is too big + */ + uint Sub(Big ss2, bool round = true) + { + ss2.ChangeSign(); + + return Add(ss2, round); + } + + + /*! + bitwise AND + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitAnd(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + { + // the second value is too small + SetZero(); + return 0; + } + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitAnd(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + /*! + bitwise OR + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitOr(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( IsZero() ) + { + *this = ss2; + return 0; + } + + if( ss2.IsZero() ) + return 0; + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + // the second value is too small + return 0; + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitOr(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + /*! + bitwise XOR + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitXor(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( ss2.IsZero() ) + return 0; + + if( IsZero() ) + { + *this = ss2; + return 0; + } + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + // the second value is too small + return 0; + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitXor(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + + /*! + Multiplication this = this * ss2 (ss2 is uint) + + ss2 without a sign + */ + uint MulUInt(uint ss2) + { + UInt man_result; + uint i,c = 0; + + if( IsNan() ) + return 1; + + if( IsZero() ) + return 0; + + if( ss2 == 0 ) + { + SetZero(); + return 0; + } + + // man_result = mantissa * ss2.mantissa + mantissa.MulInt(ss2, man_result); + + sint bit = UInt::FindLeadingBitInWord(man_result.table[man]); // man - last word + + if( bit!=-1 && uint(bit) > (TTMATH_BITS_PER_UINT/2) ) + { + // 'i' will be from 0 to TTMATH_BITS_PER_UINT + i = man_result.CompensationToLeft(); + c = exponent.Add( TTMATH_BITS_PER_UINT - i ); + + for(i=0 ; i0 && (tab[len-1] & TTMATH_UINT_HIGHEST_BIT)!=0 ) + + for(i=0 ; i & ss2, bool round = true) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt man_result; + uint c = 0; + uint i; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + + // man_result = mantissa * ss2.mantissa + mantissa.MulBig(ss2.mantissa, man_result); + + // 'i' will be from 0 to man*TTMATH_BITS_PER_UINT + // because mantissa and ss2.mantissa are standardized + // (the highest bit in man_result is set to 1 or + // if there is a zero value in man_result the method CompensationToLeft() + // returns 0 but we'll correct this at the end in Standardizing() method) + i = man_result.CompensationToLeft(); + uint exp_add = man * TTMATH_BITS_PER_UINT - i; + + if( exp_add ) + c += exponent.Add( exp_add ); + + c += exponent.Add( ss2.exponent ); + + for(i=0 ; i & ss2, bool round = true) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt man1; + UInt man2; + uint i,c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + + if( IsZero() ) + return 0; + + for(i=0 ; i & ss2) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + uint c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + + if( !SmallerWithoutSignThan(ss2) ) + { + Big temp(*this); + + c = temp.Div(ss2); + temp.SkipFraction(); + c += temp.Mul(ss2); + c += Sub(temp); + + if( !SmallerWithoutSignThan( ss2 ) ) + c += 1; + } + + return CheckCarry(c); + } + + + + + /*! + power this = this ^ pow + (pow without a sign) + + binary algorithm (r-to-l) + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments (0^0) + */ + template + uint Pow(UInt pow) + { + if( IsNan() ) + return 1; + + if( IsZero() ) + { + if( pow.IsZero() ) + { + // we don't define zero^zero + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; + } + + Big start(*this), start_temp; + Big result; + result.SetOne(); + uint c = 0; + + while( !c ) + { + if( pow.table[0] & 1 ) + c += result.Mul(start); + + pow.Rcr(1); + + if( pow.IsZero() ) + break; + + start_temp = start; + c += start.Mul(start_temp); + } + + *this = result; + + return CheckCarry(c); + } + + + /*! + power this = this ^ pow + p can be negative + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + template + uint Pow(Int pow) + { + if( IsNan() ) + return 1; + + if( !pow.IsSign() ) + return Pow( UInt(pow) ); + + if( IsZero() ) + { + // if 'p' is negative then + // 'this' must be different from zero + SetNan(); + return 2; + } + + uint c = pow.ChangeSign(); + + Big t(*this); + c += t.Pow( UInt(pow) ); // here can only be a carry (return:1) + + SetOne(); + c += Div(t); + + return CheckCarry(c); + } + + + /*! + this method returns: 'this' mod 2 + (either zero or one) + + this method is much faster than using Mod( object_with_value_two ) + */ + uint Mod2() const + { + if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) ) + return 0; + + sint exp_int = exponent.ToInt(); + // 'exp_int' is negative (or zero), we set it as positive + exp_int = -exp_int; + + return mantissa.GetBit(exp_int); + } + + + + /*! + power this = this ^ abs([pow]) + pow is treated as a value without a sign and without a fraction + if pow has a sign then the method pow.Abs() is used + if pow has a fraction the fraction is skipped (not used in calculation) + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments (0^0) + */ + uint PowUInt(Big pow) + { + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + { + if( pow.IsZero() ) + { + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; + } + + if( pow.IsSign() ) + pow.Abs(); + + Big start(*this), start_temp; + Big result; + Big one; + Int e_one; + uint c = 0; + + e_one.SetOne(); + one.SetOne(); + result = one; + + while( !c ) + { + if( pow.Mod2() ) + c += result.Mul(start); + + c += pow.exponent.Sub( e_one ); // !! may use SubOne() here? + + if( pow < one ) + break; + + start_temp = start; + c += start.Mul(start_temp); + } + + *this = result; + + return CheckCarry(c); + } + + + /*! + power this = this ^ [pow] + pow is treated as a value without a fraction + pow can be negative + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + uint PowInt(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( !pow.IsSign() ) + return PowUInt(pow); + + if( IsZero() ) + { + // if 'pow' is negative then + // 'this' must be different from zero + SetNan(); + return 2; + } + + Big temp(*this); + uint c = temp.PowUInt(pow); // here can only be a carry (result:1) + + SetOne(); + c += Div(temp); + + return CheckCarry(c); + } + + + /*! + power this = this ^ pow + this must be greater than zero (this > 0) + pow can be negative and with fraction + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument ('this' <= 0) + */ + uint PowFrac(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + Big temp; + uint c = temp.Ln(*this); + + if( c != 0 ) // can be 2 from Ln() + { + SetNan(); + return c; + } + + c += temp.Mul(pow); + c += Exp(temp); + + return CheckCarry(c); + } + + + + /*! + power this = this ^ pow + pow can be negative and with fraction + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument ('this' or 'pow') + */ + uint Pow(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + { + // 0^pow will be 0 only for pow>0 + if( pow.IsSign() || pow.IsZero() ) + { + SetNan(); + return 2; + } + + SetZero(); + + return 0; + } + + if( pow.exponent>-int(man*TTMATH_BITS_PER_UINT) && pow.exponent<=0 ) + { + if( pow.IsInteger() ) + return PowInt( pow ); + } + + return PowFrac(pow); + } + + + /*! + this function calculates the square root + e.g. let this=9 then this.Sqrt() gives 3 + + return: 0 - ok + 1 - carry + 2 - improper argument (this<0 or NaN) + */ + uint Sqrt() + { + if( IsNan() || IsSign() ) + { + SetNan(); + return 2; + } + + if( IsZero() ) + return 0; + + Big old(*this); + Big ln; + uint c = 0; + + // we're using the formula: sqrt(x) = e ^ (ln(x) / 2) + c += ln.Ln(*this); + c += ln.exponent.SubOne(); // ln = ln / 2 + c += Exp(ln); + + // above formula doesn't give accurate results for some integers + // e.g. Sqrt(81) would not be 9 but a value very closed to 9 + // we're rounding the result, calculating result*result and comparing + // with the old value, if they are equal then the result is an integer too + + if( !c && old.IsInteger() && !IsInteger() ) + { + Big temp(*this); + c += temp.Round(); + + Big temp2(temp); + c += temp.Mul(temp2); + + if( temp == old ) + *this = temp2; + } + + return CheckCarry(c); + } + + +private: + +#ifdef TTMATH_CONSTANTSGENERATOR +public: +#endif + + /*! + Exponent this = exp(x) = e^x where x is in (-1,1) + + we're using the formula exp(x) = 1 + (x)/(1!) + (x^2)/(2!) + (x^3)/(3!) + ... + */ + void ExpSurrounding0(const Big & x, uint * steps = 0) + { + TTMATH_REFERENCE_ASSERT( x ) + + Big denominator, denominator_i; + Big one, old_value, next_part; + Big numerator = x; + + SetOne(); + one.SetOne(); + denominator.SetOne(); + denominator_i.SetOne(); + + uint i; + old_value = *this; + + // we begin from 1 in order to not test at the beginning + #ifdef TTMATH_CONSTANTSGENERATOR + for(i=1 ; true ; ++i) + #else + for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + #endif + { + bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' + + next_part = numerator; + + if( next_part.Div( denominator ) ) + // if there is a carry here we only break the loop + // however the result we return as good + // it means there are too many parts of the formula + break; + + // there shouldn't be a carry here + Add( next_part ); + + if( testing ) + { + if( old_value == *this ) + // we've added next few parts of the formula but the result + // is still the same then we break the loop + break; + else + old_value = *this; + } + + // we set the denominator and the numerator for a next part of the formula + if( denominator_i.Add(one) ) + // if there is a carry here the result we return as good + break; + + if( denominator.Mul(denominator_i) ) + break; + + if( numerator.Mul(x) ) + break; + } + + if( steps ) + *steps = i; + } + +public: + + + /*! + Exponent this = exp(x) = e^x + + we're using the fact that our value is stored in form of: + x = mantissa * 2^exponent + then + e^x = e^(mantissa* 2^exponent) or + e^x = (e^mantissa)^(2^exponent) + + 'Exp' returns a carry if we can't count the result ('x' is too big) + */ + uint Exp(const Big & x) + { + uint c = 0; + + if( x.IsNan() ) + return CheckCarry(1); + + if( x.IsZero() ) + { + SetOne(); + return 0; + } + + // m will be the value of the mantissa in range (-1,1) + Big m(x); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT); + + // 'e_' will be the value of '2^exponent' + // e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; and + // e_.exponent.Add(1) mean: + // e_.mantissa.table[0] = 1; + // e_.Standardizing(); + // e_.exponent.Add(man*TTMATH_BITS_PER_UINT) + // (we must add 'man*TTMATH_BITS_PER_UINT' because we've taken it from the mantissa) + Big e_(x); + e_.mantissa.SetZero(); + e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; + c += e_.exponent.Add(1); + e_.Abs(); + + /* + now we've got: + m - the value of the mantissa in range (-1,1) + e_ - 2^exponent + + e_ can be as: + ...2^-2, 2^-1, 2^0, 2^1, 2^2 ... + ...1/4 , 1/2 , 1 , 2 , 4 ... + + above one e_ is integer + + if e_ is greater than 1 we calculate the exponent as: + e^(m * e_) = ExpSurrounding0(m) ^ e_ + and if e_ is smaller or equal one we calculate the exponent in this way: + e^(m * e_) = ExpSurrounding0(m* e_) + because if e_ is smaller or equal 1 then the product of m*e_ is smaller or equal m + */ + + if( e_ <= 1 ) + { + m.Mul(e_); + ExpSurrounding0(m); + } + else + { + ExpSurrounding0(m); + c += PowUInt(e_); + } + + return CheckCarry(c); + } + + + + +private: + +#ifdef TTMATH_CONSTANTSGENERATOR +public: +#endif + + /*! + Natural logarithm this = ln(x) where x in range <1,2) + + we're using the formula: + ln x = 2 * [ (x-1)/(x+1) + (1/3)((x-1)/(x+1))^3 + (1/5)((x-1)/(x+1))^5 + ... ] + */ + void LnSurrounding1(const Big & x, uint * steps = 0) + { + Big old_value, next_part, denominator, one, two, x1(x), x2(x); + + one.SetOne(); + + if( x == one ) + { + // LnSurrounding1(1) is 0 + SetZero(); + return; + } + + two = 2; + + x1.Sub(one); + x2.Add(one); + + x1.Div(x2); + x2 = x1; + x2.Mul(x1); + + denominator.SetOne(); + SetZero(); + + old_value = *this; + uint i; + + + #ifdef TTMATH_CONSTANTSGENERATOR + for(i=1 ; true ; ++i) + #else + // we begin from 1 in order to not test at the beginning + for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + #endif + { + bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' + + next_part = x1; + + if( next_part.Div(denominator) ) + // if there is a carry here we only break the loop + // however the result we return as good + // it means there are too many parts of the formula + break; + + // there shouldn't be a carry here + Add(next_part); + + if( testing ) + { + if( old_value == *this ) + // we've added next (step_test) parts of the formula but the result + // is still the same then we break the loop + break; + else + old_value = *this; + } + + if( x1.Mul(x2) ) + // if there is a carry here the result we return as good + break; + + if( denominator.Add(two) ) + break; + } + + // this = this * 2 + // ( there can't be a carry here because we calculate the logarithm between <1,2) ) + exponent.AddOne(); + + if( steps ) + *steps = i; + } + + + + +public: + + + /*! + Natural logarithm this = ln(x) + (a logarithm with the base equal 'e') + + we're using the fact that our value is stored in form of: + x = mantissa * 2^exponent + then + ln(x) = ln (mantissa * 2^exponent) = ln (mantissa) + (exponent * ln (2)) + + the mantissa we'll show as a value from range <1,2) because the logarithm + is decreasing too fast when 'x' is going to 0 + + return values: + 0 - ok + 1 - overflow (carry) + 2 - incorrect argument (x<=0) + */ + uint Ln(const Big & x) + { + TTMATH_REFERENCE_ASSERT( x ) + + if( x.IsNan() ) + return CheckCarry(1); + + if( x.IsSign() || x.IsZero() ) + { + SetNan(); + return 2; + } + + // m will be the value of the mantissa in range <1,2) + Big m(x); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT - 1); + + LnSurrounding1(m); + + Big exponent_temp; + exponent_temp.FromInt( x.exponent ); + + // we must add 'man*TTMATH_BITS_PER_UINT-1' because we've taken it from the mantissa + uint c = exponent_temp.Add(man*TTMATH_BITS_PER_UINT-1); + + Big ln2; + ln2.SetLn2(); + c += exponent_temp.Mul(ln2); + c += Add(exponent_temp); + + return CheckCarry(c); + } + + + + /*! + Logarithm from 'x' with a 'base' + + we're using the formula: + Log(x) with 'base' = ln(x) / ln(base) + + return values: + 0 - ok + 1 - overflow + 2 - incorrect argument (x<=0) + 3 - incorrect base (a<=0 lub a=1) + */ + uint Log(const Big & x, const Big & base) + { + TTMATH_REFERENCE_ASSERT( base ) + TTMATH_REFERENCE_ASSERT( x ) + + if( x.IsNan() || base.IsNan() ) + return CheckCarry(1); + + if( x.IsSign() || x.IsZero() ) + { + SetNan(); + return 2; + } + + Big denominator;; + denominator.SetOne(); + + if( base.IsSign() || base.IsZero() || base==denominator ) + { + SetNan(); + return 3; + } + + if( x == denominator ) // (this is: if x == 1) + { + // log(1) is 0 + SetZero(); + return 0; + } + + // another error values we've tested at the beginning + // there can only be a carry + uint c = Ln(x); + + c += denominator.Ln(base); + c += Div(denominator); + + return CheckCarry(c); + } + + + + + /*! + * + * converting methods + * + */ + + + /*! + converting from another type of a Big object + */ + template + uint FromBig(const Big & another) + { + info = another.info; + + if( IsNan() ) + return 1; + + if( exponent.FromInt(another.exponent) ) + { + SetNan(); + return 1; + } + + uint man_len_min = (man < another_man)? man : another_man; + uint i; + uint c = 0; + + for( i = 0 ; i another_man )' and 'if( man < another_man )' and there'll be no such situation here + #ifdef _MSC_VER + #pragma warning( disable: 4307 ) + #endif + + if( man > another_man ) + { + uint man_diff = (man - another_man) * TTMATH_BITS_PER_UINT; + c += exponent.SubInt(man_diff, 0); + } + else + if( man < another_man ) + { + uint man_diff = (another_man - man) * TTMATH_BITS_PER_UINT; + c += exponent.AddInt(man_diff, 0); + } + + #ifdef _MSC_VER + #pragma warning( default: 4307 ) + #endif + + // mantissa doesn't have to be standardized (either the highest bit is set or all bits are equal zero) + CorrectZero(); + + return CheckCarry(c); + } + + + /*! + this method converts 'this' into 'result' + + if the value is too big this method returns a carry (1) + */ + uint ToUInt(uint & result, bool test_sign = true) const + { + result = 0; + + if( IsZero() ) + return 0; + + if( test_sign && IsSign() ) + // the result should be positive + return 1; + + sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); + + if( exponent > maxbit + sint(TTMATH_BITS_PER_UINT) ) + // if exponent > (maxbit + sint(TTMATH_BITS_PER_UINT)) the value can't be passed + // into the 'sint' type (it's too big) + return 1; + + if( exponent <= maxbit ) + // our value is from the range of (-1,1) and we return zero + return 0; + + UInt mantissa_temp(mantissa); + // exponent is from a range of (maxbit, maxbit + sint(TTMATH_BITS_PER_UINT) > + sint how_many_bits = exponent.ToInt(); + + // how_many_bits is negative, we'll make it positive + how_many_bits = -how_many_bits; + + // we're taking into account only the last word in a mantissa table + mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 ); + result = mantissa_temp.table[ man-1 ]; + + return 0; + } + + + + /*! + this method converts 'this' into 'result' + + if the value is too big this method returns a carry (1) + */ + uint ToInt(sint & result) const + { + result = 0; + uint result_uint; + + if( ToUInt(result_uint, false) ) + return 1; + + result = static_cast( result_uint ); + + // the exception for the minimal value + if( IsSign() && result_uint == TTMATH_UINT_HIGHEST_BIT ) + return 0; + + if( (result_uint & TTMATH_UINT_HIGHEST_BIT) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result = -result; + + return 0; + } + + + /*! + this method converts 'this' into 'result' + + if the value is too big this method returns a carry (1) + */ + template + uint ToInt(Int & result) const + { + result.SetZero(); + + if( IsZero() ) + return 0; + + sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); + + if( exponent > maxbit + sint(int_size*TTMATH_BITS_PER_UINT) ) + // if exponent > (maxbit + sint(int_size*TTMATH_BITS_PER_UINT)) the value can't be passed + // into the 'Int' type (it's too big) + return 1; + + if( exponent <= maxbit ) + // our value is from range (-1,1) and we return zero + return 0; + + sint how_many_bits = exponent.ToInt(); + + if( how_many_bits < 0 ) + { + how_many_bits = -how_many_bits; + uint index = how_many_bits / TTMATH_BITS_PER_UINT; + + UInt mantissa_temp(mantissa); + mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 ); + + for(uint i=index, a=0 ; i min; + min.SetMin(); + + if( result == min ) + return 0; + } + + if( (result.table[int_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result.ChangeSign(); + + return 0; + } + + + /*! + a method for converting 'uint' to this class + */ + void FromUInt(uint value) + { + info = 0; + + for(uint i=0 ; i> 20; + uint m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21); + uint m2 = temp.u[0] << 11; + + if( e == 2047 ) + { + // If E=2047 and F is nonzero, then V=NaN ("Not a number") + // If E=2047 and F is zero and S is 1, then V=-Infinity + // If E=2047 and F is zero and S is 0, then V=Infinity + + // we do not support -Infinity and +Infinity + // we assume that there is always NaN + + SetNan(); + } + else + if( e > 0 ) + { + // If 0 m; + m.table[1] = m1; + m.table[0] = m2; + uint moved = m.CompensationToLeft(); + + FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0, + e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0, + m.table[1], m.table[2]); + } + else + { + // If E=0 and F is zero and S is 1, then V=-0 + // If E=0 and F is zero and S is 0, then V=0 + + // we do not support -0 or 0, only is one 0 + SetZero(); + } + } + } + + +private: + + void FromDouble_SetExpAndMan(bool is_sign, int e, uint mhighest, uint m1, uint m2) + { + exponent = e; + + if( man > 1 ) + { + mantissa.table[man-1] = m1 | mhighest; + mantissa.table[sint(man-2)] = m2; + // although man>1 we're using casting into sint + // to get rid from a warning which generates Microsoft Visual: + // warning C4307: '*' : integral constant overflow + + for(uint i=0 ; i> 52; + uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11; + + if( e == 2047 ) + { + // If E=2047 and F is nonzero, then V=NaN ("Not a number") + // If E=2047 and F is zero and S is 1, then V=-Infinity + // If E=2047 and F is zero and S is 0, then V=Infinity + + // we do not support -Infinity and +Infinity + // we assume that there is always NaN + + SetNan(); + } + else + if( e > 0 ) + { + // If 0= 1024 - e_correction ) + { + // +/- infinity + result = ToDouble_SetDouble( 0, 2047, 0, true); + + return 1; + } + else + if( exponent <= -1023 - 52 - e_correction ) + { + // too small value - we assume that there'll be a zero + result = 0; + + // and return a carry + return 1; + } + + sint e = exponent.ToInt() + e_correction; + + if( e <= -1023 ) + { + // -1023-52 < e <= -1023 (unnormalized value) + result = ToDouble_SetDouble( IsSign(), 0, -(e + 1023)); + } + else + { + // -1023 < e < 1024 + result = ToDouble_SetDouble( IsSign(), e + 1023, -1); + } + + return 0; + } + +private: + +#ifdef TTMATH_PLATFORM32 + + // 32bit platforms + double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const + { + union + { + double d; + uint u[2]; // two 32bit words + } temp; + + temp.u[0] = temp.u[1] = 0; + + if( is_sign ) + temp.u[1] |= 0x80000000u; + + temp.u[1] |= (e << 20) & 0x7FF00000u; + + if( nan ) + { + temp.u[0] |= 1; + return temp.d; + } + + if( infinity ) + return temp.d; + + UInt<2> m; + m.table[1] = mantissa.table[man-1]; + m.table[0] = ( man > 1 ) ? mantissa.table[sint(man-2)] : 0; + // although man>1 we're using casting into sint + // to get rid from a warning which generates Microsoft Visual: + // warning C4307: '*' : integral constant overflow + + m.Rcr( 12 + move ); + m.table[1] &= 0xFFFFFu; // cutting the 20 bit (when 'move' was -1) + + temp.u[1] |= m.table[1]; + temp.u[0] |= m.table[0]; + + return temp.d; + } + +#else + + // 64bit platforms + double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const + { + union + { + double d; + uint u; // 64bit word + } temp; + + temp.u = 0; + + if( is_sign ) + temp.u |= 0x8000000000000000ul; + + temp.u |= (e << 52) & 0x7FF0000000000000ul; + + if( nan ) + { + temp.u |= 1; + return temp.d; + } + + if( infinity ) + return temp.d; + + uint m = mantissa.table[man-1]; + + m >>= ( 12 + move ); + m &= 0xFFFFFFFFFFFFFul; // cutting the 20 bit (when 'move' was -1) + temp.u |= m; + + return temp.d; + } + +#endif + + +public: + + + /*! + an operator= for converting 'sint' to this class + */ + Big & operator=(sint value) + { + FromInt(value); + + return *this; + } + + + /*! + an operator= for converting 'uint' to this class + */ + Big & operator=(uint value) + { + FromUInt(value); + + return *this; + } + + + /*! + an operator= for converting 'double' to this class + */ + Big & operator=(double value) + { + FromDouble(value); + + return *this; + } + + + /*! + a constructor for converting 'sint' to this class + */ + Big(sint value) + { + FromInt(value); + } + + /*! + a constructor for converting 'uint' to this class + */ + Big(uint value) + { + FromUInt(value); + } + + + /*! + a constructor for converting 'double' to this class + */ + Big(double value) + { + FromDouble(value); + } + + +#ifdef TTMATH_PLATFORM64 + + /*! + in 64bit platforms we must define additional operators and contructors + in order to allow a user initializing the objects in this way: + Big<...> type = 20; + or + Big<...> type; + type = 30; + + decimal constants such as 20, 30 etc. are integer literal of type int, + if the value is greater it can even be long int, + 0 is an octal integer of type int + (ISO 14882 p2.13.1 Integer literals) + */ + + /*! + an operator= for converting 'signed int' to this class + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + + + */ + Big & operator=(signed int value) + { + FromInt(sint(value)); + + return *this; + } + + + /*! + an operator= for converting 'unsigned int' to this class + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big & operator=(unsigned int value) + { + FromUInt(uint(value)); + + return *this; + } + + + /*! + a constructor for converting 'signed int' to this class + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big(signed int value) + { + FromInt(sint(value)); + } + + /*! + a constructor for converting 'unsigned int' to this class + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big(unsigned int value) + { + FromUInt(uint(value)); + } + +#endif + +private: + + /*! + an auxiliary method for converting from UInt and Int + + we assume that there'll never be a carry here + (we have an exponent and the value in Big can be bigger than + that one from the UInt) + */ + template + void FromUIntOrInt(const UInt & value, sint compensation) + { + uint minimum_size = (int_size < man)? int_size : man; + exponent = (sint(int_size)-sint(man)) * sint(TTMATH_BITS_PER_UINT) - compensation; + + // copying the highest words + uint i; + for(i=1 ; i<=minimum_size ; ++i) + mantissa.table[man-i] = value.table[int_size-i]; + + // setting the rest of mantissa.table into zero (if some has left) + for( ; i<=man ; ++i) + mantissa.table[man-i] = 0; + + // the highest bit is either one or zero (when the whole mantissa is zero) + // we can only call CorrectZero() + CorrectZero(); + } + + +public: + + + /*! + a method for converting from 'UInt' to this class + */ + template + void FromUInt(UInt value) + { + info = 0; + sint compensation = (sint)value.CompensationToLeft(); + + return FromUIntOrInt(value, compensation); + } + + + /*! + a method for converting from 'Int' to this class + */ + template + void FromInt(Int value) + { + info = 0; + bool is_sign = false; + + if( value.IsSign() ) + { + value.ChangeSign(); + is_sign = true; + } + + sint compensation = (sint)value.CompensationToLeft(); + FromUIntOrInt(value, compensation); + + if( is_sign ) + SetSign(); + } + + + /*! + an operator= for converting from 'Int' to this class + */ + template + Big & operator=(const Int & value) + { + FromInt(value); + + return *this; + } + + + /*! + a constructor for converting from 'Int' to this class + */ + template + Big(const Int & value) + { + FromInt(value); + } + + + /*! + an operator= for converting from 'UInt' to this class + */ + template + Big & operator=(const UInt & value) + { + FromUInt(value); + + return *this; + } + + + /*! + a constructor for converting from 'UInt' to this class + */ + template + Big(const UInt & value) + { + FromUInt(value); + } + + + /*! + an operator= for converting from 'Big' to this class + */ + template + Big & operator=(const Big & value) + { + FromBig(value); + + return *this; + } + + + /*! + a constructor for converting from 'Big' to this class + */ + template + Big(const Big & value) + { + FromBig(value); + } + + + /*! + a default constructor + + we don't set any of the members to zero + only NaN flag is set + */ + Big() + { + info = TTMATH_BIG_NAN; + + /* + we're directly setting 'info' (instead of calling SetNan()) + in order to get rid of a warning saying that 'info' is uninitialized + */ + } + + + /*! + a destructor + */ + ~Big() + { + } + + + /*! + the default assignment operator + */ + Big & operator=(const Big & value) + { + info = value.info; + exponent = value.exponent; + mantissa = value.mantissa; + + return *this; + } + + + /*! + a constructor for copying from another object of this class + */ + + Big(const Big & value) + { + operator=(value); + } + + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + + output: + return value: + 0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value + 1 - if there is a carry (it shoudn't be in a normal situation - if it is that means there + is somewhere an error in the library) + */ + uint ToString( std::string & result, + uint base = 10, + bool scient = false, + sint scient_from = 15, + sint round = -1, + bool trim_zeroes = true, + wchar_t comma = '.' ) const + { + Conv conv; + + conv.base = base; + conv.scient = scient; + conv.scient_from = scient_from; + conv.round = round; + conv.trim_zeroes = trim_zeroes; + conv.comma = static_cast(comma); + + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString( std::wstring & result, + uint base = 10, + bool scient = false, + sint scient_from = 15, + sint round = -1, + bool trim_zeroes = true, + wchar_t comma = '.' ) const + { + Conv conv; + + conv.base = base; + conv.scient = scient; + conv.scient_from = scient_from; + conv.round = round; + conv.trim_zeroes = trim_zeroes; + conv.comma = static_cast(comma); + + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString(std::string & result, const Conv & conv) const + { + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString(std::wstring & result, const Conv & conv) const + { + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::string ToString(const Conv & conv) const + { + std::string result; + ToStringBase(result, conv); + + return result; + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::string ToString() const + { + Conv conv; + + return ToString(conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::wstring ToWString(const Conv & conv) const + { + std::wstring result; + ToStringBase(result, conv); + + return result; + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::wstring ToWString() const + { + Conv conv; + + return ToWString(conv); + } + + +private: + + + /*! + an auxiliary method for converting into the string + */ + template + uint ToStringBase(string_type & result, const Conv & conv) const + { + static char error_overflow_msg[] = "overflow"; + static char error_nan_msg[] = "NaN"; + result.erase(); + + if( IsNan() ) + { + Misc::AssignString(result, error_nan_msg); + return 0; + } + + if( conv.base<2 || conv.base>16 ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + if( IsZero() ) + { + result = '0'; + + return 0; + } + + /* + since 'base' is greater or equal 2 that 'new_exp' of type 'Int' should + hold the new value of exponent but we're using 'Int' because + if the value for example would be 'max()' then we couldn't show it + + max() -> 11111111 * 2 ^ 11111111111 (bin)(the mantissa and exponent have all bits set) + if we were using 'Int' we couldn't show it in this format: + 1,1111111 * 2 ^ 11111111111 (bin) + because we have to add something to the mantissa and because + mantissa is full we can't do it and it'll be a carry + (look at ToString_SetCommaAndExponent(...)) + + when the base would be greater than two (for example 10) + we could use 'Int' here + */ + Int new_exp; + + if( ToString_CreateNewMantissaAndExponent(result, conv, new_exp) ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + + if( ToString_SetCommaAndExponent(result, conv, new_exp) ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + if( IsSign() ) + result.insert(result.begin(), '-'); + + + // converted successfully + return 0; + } + + + + /*! + in the method 'ToString_CreateNewMantissaAndExponent()' we're using + type 'Big' and we should have the ability to use some + necessary methods from that class (methods which are private here) + */ + friend class Big; + + + /*! + an auxiliary method for converting into the string + + input: + base - the base in range <2,16> + + output: + return values: + 0 - ok + 1 - if there was a carry + new_man - the new mantissa for 'base' + new_exp - the new exponent for 'base' + + mathematic part: + + the value is stored as: + value = mantissa * 2^exponent + we want to show 'value' as: + value = new_man * base^new_exp + + then 'new_man' we'll print using the standard method from UInt<> type for printing + and 'new_exp' is the offset of the comma operator in a system of a base 'base' + + value = mantissa * 2^exponent + value = mantissa * 2^exponent * (base^new_exp / base^new_exp) + value = mantissa * (2^exponent / base^new_exp) * base^new_exp + + look at the part (2^exponent / base^new_exp), there'll be good if we take + a 'new_exp' equal that value when the (2^exponent / base^new_exp) will be equal one + + on account of the 'base' is not as power of 2 (can be from 2 to 16), + this formula will not be true for integer 'new_exp' then in our case we take + 'base^new_exp' _greater_ than '2^exponent' + + if 'base^new_exp' were smaller than '2^exponent' the new mantissa could be + greater than the max value of the container UInt + + value = mantissa * (2^exponent / base^new_exp) * base^new_exp + let M = mantissa * (2^exponent / base^new_exp) then + value = M * base^new_exp + + in our calculation we treat M as floating value showing it as: + M = mm * 2^ee where ee will be <= 0 + + next we'll move all bits of mm into the right when ee is equal zero + abs(ee) must not be too big that only few bits from mm we can leave + + then we'll have: + M = mmm * 2^0 + 'mmm' is the new_man which we're looking for + + + new_exp we calculate in this way: + 2^exponent <= base^new_exp + new_exp >= log base (2^exponent) <- logarithm with the base 'base' from (2^exponent) + + but we need new_exp as integer then we test: + if new_exp is greater than zero and with fraction we add one to new_exp + new_exp = new_exp + 1 (if new_exp>0 and with fraction) + and at the end we take the integer part: + new_exp = int(new_exp) + */ + template + uint ToString_CreateNewMantissaAndExponent( string_type & new_man, const Conv & conv, + Int & new_exp) const + { + uint c = 0; + + if( conv.base<2 || conv.base>16 ) + return 1; + + // the speciality for base equal 2 + if( conv.base == 2 ) + return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp); + + // the speciality for base equal 4 + if( conv.base == 4 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 2); + + // the speciality for base equal 8 + if( conv.base == 8 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 3); + + // the speciality for base equal 16 + if( conv.base == 16 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 4); + + + // this = mantissa * 2^exponent + + // temp = +1 * 2^exponent + // we're using a bigger type than 'big' (look below) + Big temp; + temp.info = 0; + temp.exponent = exponent; + temp.mantissa.SetOne(); + c += temp.Standardizing(); + + // new_exp_ = log base (2^exponent) + // if new_exp_ is positive and with fraction then we add one + Big new_exp_; + c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated + + // adding some epsilon value (to get rid of some floating point errors) + temp.Set05(); + temp.exponent.SubOne(); // temp = 0.5/2 = 0.25 + c += new_exp_.Add(temp); + + if( !new_exp_.IsSign() && !new_exp_.IsInteger() ) + { + // new_exp_ > 0 and with fraction + temp.SetOne(); + c += new_exp_.Add( temp ); + } + + // new_exp_ = int(new_exp_) + new_exp_.SkipFraction(); + + + // because 'base^new_exp' is >= '2^exponent' then + // because base is >= 2 then we've got: + // 'new_exp_' must be smaller or equal 'new_exp' + // and we can pass it into the Int type + // (in fact we're using a greater type then it'll be ok) + c += new_exp_.ToInt(new_exp); + + // base_ = base + Big base_(conv.base); + + // base_ = base_ ^ new_exp_ + c += base_.Pow( new_exp_ ); + // if we hadn't used a bigger type than 'Big' then the result + // of this formula 'Pow(...)' would have been with an overflow + + // temp = mantissa * 2^exponent / base_^new_exp_ + // the sign don't interest us here + temp.mantissa = mantissa; + temp.exponent = exponent; + c += temp.Div(base_, false); // dividing without rounding + + // moving all bits of the mantissa into the right + // (how many times to move depend on the exponent) + c += temp.ToString_MoveMantissaIntoRight(); + + // because we took 'new_exp' as small as it was + // possible ([log base (2^exponent)] + 1) that after the division + // (temp.Div( base_ )) the value of exponent should be equal zero or + // minimum smaller than zero then we've got the mantissa which has + // maximum valid bits + temp.mantissa.ToString(new_man, conv.base); + + // base rounding + if( conv.base_round ) + c += ToString_BaseRound(new_man, conv, new_exp); + + return (c==0)? 0 : 1; + } + + + /*! + this method calculates the logarithm + it is used by ToString_CreateNewMantissaAndExponent() method + + it's not too complicated + because x=+1*2^exponent (mantissa is one) then during the calculation + the Ln(x) will not be making the long formula from LnSurrounding1() + and only we have to calculate 'Ln(base)' but it'll be calculated + only once, the next time we will get it from the 'history' + + x is greater than 0 + base is in <2,16> range + */ + uint ToString_Log(const Big & x, uint base) + { + TTMATH_REFERENCE_ASSERT( x ) + TTMATH_ASSERT( base>=2 && base<=16 ) + + Big temp; + temp.SetOne(); + + if( x == temp ) + { + // log(1) is 0 + SetZero(); + + return 0; + } + + // there can be only a carry + // because the 'x' is in '1+2*exponent' form then + // the long formula from LnSurrounding1() will not be calculated + // (LnSurrounding1() will return one immediately) + uint c = Ln(x); + + if( base==10 && man<=TTMATH_BUILTIN_VARIABLES_SIZE ) + { + // for the base equal 10 we're using SelLn10() instead of calculating it + // (only if we have the constant sufficient big) + temp.SetLn10(); + } + else + { + c += ToString_LogBase(base, temp); + } + + c += Div( temp ); + + return (c==0)? 0 : 1; + } + + +#ifndef TTMATH_MULTITHREADS + + /*! + this method calculates the logarithm of 'base' + it's used in single thread environment + */ + uint ToString_LogBase(uint base, Big & result) + { + TTMATH_ASSERT( base>=2 && base<=16 ) + + // this guardians are initialized before the program runs (static POD types) + static int guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static Big log_history[15]; + uint index = base - 2; + uint c = 0; + + if( guardians[index] == 0 ) + { + Big base_(base); + c += log_history[index].Ln(base_); + guardians[index] = 1; + } + + result = log_history[index]; + + return (c==0)? 0 : 1; + } + +#else + + /*! + this method calculates the logarithm of 'base' + it's used in multi-thread environment + */ + uint ToString_LogBase(uint base, Big & result) + { + TTMATH_ASSERT( base>=2 && base<=16 ) + + // this guardians are initialized before the program runs (static POD types) + volatile static sig_atomic_t guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static Big * plog_history; + uint index = base - 2; + uint c = 0; + + // double-checked locking + if( guardians[index] == 0 ) + { + ThreadLock thread_lock; + + // locking + if( thread_lock.Lock() ) + { + static Big log_history[15]; + + if( guardians[index] == 0 ) + { + plog_history = log_history; + + Big base_(base); + c += log_history[index].Ln(base_); + guardians[index] = 1; + } + } + else + { + // there was a problem with locking, we store the result directly in 'result' object + Big base_(base); + c += result.Ln(base_); + + return (c==0)? 0 : 1; + } + + // automatically unlocking + } + + result = plog_history[index]; + + return (c==0)? 0 : 1; + } + +#endif + + /*! + an auxiliary method for converting into the string (private) + + this method moving all bits from mantissa into the right side + the exponent tell us how many times moving (the exponent is <=0) + */ + uint ToString_MoveMantissaIntoRight() + { + if( exponent.IsZero() ) + return 0; + + // exponent can't be greater than zero + // because we would cat the highest bits of the mantissa + if( !exponent.IsSign() ) + return 1; + + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + // if 'exponent' is <= than '-sint(man*TTMATH_BITS_PER_UINT)' + // it means that we must cut the whole mantissa + // (there'll not be any of the valid bits) + return 1; + + // e will be from (-man*TTMATH_BITS_PER_UINT, 0> + sint e = -( exponent.ToInt() ); + mantissa.Rcr(e,0); + + return 0; + } + + + /*! + a special method similar to the 'ToString_CreateNewMantissaAndExponent' + when the 'base' is equal 2 + + we use it because if base is equal 2 we don't have to make those + complicated calculations and the output is directly from the source + (there will not be any small distortions) + */ + template + uint ToString_CreateNewMantissaAndExponent_Base2( string_type & new_man, + Int & new_exp ) const + { + for( sint i=man-1 ; i>=0 ; --i ) + { + uint value = mantissa.table[i]; + + for( uint bit=0 ; bit + uint ToString_CreateNewMantissaAndExponent_BasePow2( string_type & new_man, + Int & new_exp, + uint bits) const + { + sint move; // how many times move the mantissa + UInt man_temp(mantissa); // man+1 for moving + new_exp = exponent; + new_exp.DivInt((sint)bits, move); + + if( move != 0 ) + { + // we're moving the man_temp to left-hand side + if( move < 0 ) + { + move = sint(bits) + move; + new_exp.SubOne(); // when move is < than 0 then new_exp is < 0 too + } + + man_temp.Rcl(move); + } + + + if( bits == 3 ) + { + // base 8 + // now 'move' is greater than or equal 0 + uint len = man*TTMATH_BITS_PER_UINT + move; + return ToString_CreateNewMantissaAndExponent_Base8(new_man, man_temp, len, bits); + } + else + { + // base 4 or 16 + return ToString_CreateNewMantissaAndExponent_Base4or16(new_man, man_temp, bits); + } + } + + + /*! + a special method used to calculate the new mantissa + when the 'base' is equal 8 + + bits is always 3 + + we can use this algorithm when the base is 4 or 16 too + but we have a faster method ToString_CreateNewMantissaAndExponent_Base4or16() + */ + template + uint ToString_CreateNewMantissaAndExponent_Base8( string_type & new_man, + UInt & man_temp, + uint len, + uint bits) const + { + uint shift = TTMATH_BITS_PER_UINT - bits; + uint mask = TTMATH_UINT_MAX_VALUE >> shift; + uint i; + + for( i=0 ; i(Misc::DigitToChar(digit))); + + man_temp.Rcr(bits); + } + + TTMATH_ASSERT( man_temp.IsZero() ) + + return 0; + } + + + /*! + a special method used to calculate the new mantissa + when the 'base' is equal 4 or 16 + + when the base is equal 4 or 16 the bits is 2 or 4 + and because TTMATH_BITS_PER_UINT (32 or 64) is divisible by 2 (or 4) + then we can get digits from the end of our mantissa + */ + template + uint ToString_CreateNewMantissaAndExponent_Base4or16( string_type & new_man, + UInt & man_temp, + uint bits) const + { + TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 2 == 0 ) + TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 4 == 0 ) + + uint shift = TTMATH_BITS_PER_UINT - bits; + uint mask = TTMATH_UINT_MAX_VALUE << shift; + uint digit; + + // table[man] - last word - is different from zero if we moved man_temp + digit = man_temp.table[man]; + + if( digit != 0 ) + new_man += static_cast(Misc::DigitToChar(digit)); + + + for( int i=man-1 ; i>=0 ; --i ) + { + uint shift_local = shift; + uint mask_local = mask; + + while( mask_local != 0 ) + { + digit = man_temp.table[i] & mask_local; + + if( shift_local != 0 ) + digit = digit >> shift_local; + + new_man += static_cast(Misc::DigitToChar(digit)); + mask_local = mask_local >> bits; + shift_local = shift_local - bits; + } + } + + return 0; + } + + + /*! + an auxiliary method for converting into the string + */ + template + bool ToString_RoundMantissaWouldBeInteger(string_type & new_man, const Conv & conv, Int & new_exp) const + { + // if new_exp is greater or equal to zero then we have an integer value, + // if new_exp is equal -1 then we have only one digit after the comma + // and after rounding it would be an integer value + if( !new_exp.IsSign() || new_exp == -1 ) + return true; + + if( new_man.size() >= TTMATH_UINT_HIGHEST_BIT || new_man.size() < 2 ) + return true; // oops, the mantissa is too large for calculating (or too small) - we are not doing the base rounding + + uint i = 0; + char_type digit; + + if( new_exp >= -sint(new_man.size()) ) + { + uint new_exp_abs = -new_exp.ToInt(); + i = new_man.size() - new_exp_abs; // start from the first digit after the comma operator + } + + if( Misc::CharToDigit(new_man[new_man.size()-1]) >= conv.base/2 ) + { + if( new_exp < -sint(new_man.size()) ) + { + // there are some zeroes after the comma operator + // (between the comma and the first digit from the mantissa) + // and the result value will never be an integer + return false; + } + + digit = static_cast( Misc::DigitToChar(conv.base-1) ); + } + else + { + digit = '0'; + } + + for( ; i < new_man.size()-1 ; ++i) + if( new_man[i] != digit ) + return false; // it will not be an integer + + return true; // it will be integer after rounding + } + + + /*! + an auxiliary method for converting into the string + + this method is used for base!=2, base!=4, base!=8 and base!=16 + we do the rounding when the value has fraction (is not an integer) + */ + template + uint ToString_BaseRound(string_type & new_man, const Conv & conv, Int & new_exp) const + { + // we must have minimum two characters + if( new_man.size() < 2 ) + return 0; + + // assert that there will not be an integer after rounding + if( ToString_RoundMantissaWouldBeInteger(new_man, conv, new_exp) ) + return 0; + + typename string_type::size_type i = new_man.length() - 1; + + // we're erasing the last character + uint digit = Misc::CharToDigit( new_man[i] ); + new_man.erase(i, 1); + uint c = new_exp.AddOne(); + + // if the last character is greater or equal 'base/2' + // we are adding one into the new mantissa + if( digit >= conv.base / 2 ) + ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); + + return c; + } + + + /*! + an auxiliary method for converting into the string + + this method addes one into the new mantissa + */ + template + void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const + { + if( new_man.empty() ) + return; + + sint i = sint( new_man.length() ) - 1; + bool was_carry = true; + + for( ; i>=0 && was_carry ; --i ) + { + // we can have the comma as well because + // we're using this method later in ToString_CorrectDigitsAfterComma_Round() + // (we're only ignoring it) + if( new_man[i] == static_cast(conv.comma) ) + continue; + + // we're adding one + uint digit = Misc::CharToDigit( new_man[i] ) + 1; + + if( digit == conv.base ) + digit = 0; + else + was_carry = false; + + new_man[i] = static_cast( Misc::DigitToChar(digit) ); + } + + if( i<0 && was_carry ) + new_man.insert( new_man.begin() , '1' ); + } + + + + /*! + an auxiliary method for converting into the string + + this method sets the comma operator and/or puts the exponent + into the string + */ + template + uint ToString_SetCommaAndExponent(string_type & new_man, const Conv & conv, Int & new_exp) const + { + uint carry = 0; + + if( new_man.empty() ) + return carry; + + Int scientific_exp( new_exp ); + + // 'new_exp' depends on the 'new_man' which is stored like this e.g: + // 32342343234 (the comma is at the end) + // we'd like to show it in this way: + // 3.2342343234 (the 'scientific_exp' is connected with this example) + + sint offset = sint( new_man.length() ) - 1; + carry += scientific_exp.Add( offset ); + // there shouldn't have been a carry because we're using + // a greater type -- 'Int' instead of 'Int' + + bool print_scientific = conv.scient; + + if( !print_scientific ) + { + if( scientific_exp > conv.scient_from || scientific_exp < -sint(conv.scient_from) ) + print_scientific = true; + } + + if( !print_scientific ) + ToString_SetCommaAndExponent_Normal(new_man, conv, new_exp); + else + // we're passing the 'scientific_exp' instead of 'new_exp' here + ToString_SetCommaAndExponent_Scientific(new_man, conv, scientific_exp); + + return (carry==0)? 0 : 1; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal(string_type & new_man, const Conv & conv, Int & new_exp ) const + { + if( !new_exp.IsSign() ) // it means: if( new_exp >= 0 ) + ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp); + else + ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, conv, new_exp); + + + ToString_Group_man(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal_AddingZero(string_type & new_man, + Int & new_exp) const + { + // we're adding zero characters at the end + // 'i' will be smaller than 'when_scientific' (or equal) + uint i = new_exp.ToInt(); + + if( new_man.length() + i > new_man.capacity() ) + // about 6 characters more (we'll need it for the comma or something) + new_man.reserve( new_man.length() + i + 6 ); + + for( ; i>0 ; --i) + new_man += '0'; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal_SetCommaInside( + string_type & new_man, + const Conv & conv, + Int & new_exp ) const + { + // new_exp is < 0 + + sint new_man_len = sint(new_man.length()); // 'new_man_len' with a sign + sint e = -( new_exp.ToInt() ); // 'e' will be positive + + if( new_exp > -new_man_len ) + { + // we're setting the comma within the mantissa + + sint index = new_man_len - e; + new_man.insert( new_man.begin() + index, static_cast(conv.comma)); + } + else + { + // we're adding zero characters before the mantissa + + uint how_many = e - new_man_len; + string_type man_temp(how_many+1, '0'); + + man_temp.insert( man_temp.begin()+1, static_cast(conv.comma)); + new_man.insert(0, man_temp); + } + + ToString_CorrectDigitsAfterComma(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Scientific( string_type & new_man, + const Conv & conv, + Int & scientific_exp ) const + { + if( new_man.empty() ) + return; + + if( new_man.size() > 1 ) + { + new_man.insert( new_man.begin()+1, static_cast(conv.comma) ); + ToString_CorrectDigitsAfterComma(new_man, conv); + } + + ToString_Group_man(new_man, conv); + + if( conv.base == 10 ) + { + new_man += 'e'; + + if( !scientific_exp.IsSign() ) + new_man += '+'; + } + else + { + // the 10 here is meant as the base 'base' + // (no matter which 'base' we're using there'll always be 10 here) + Misc::AddString(new_man, "*10^"); + } + + string_type temp_exp; + scientific_exp.ToString( temp_exp, conv.base ); + + new_man += temp_exp; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man(string_type & new_man, const Conv & conv) const + { + typedef typename string_type::size_type StrSize; + + if( conv.group == 0 ) + return; + + // first we're looking for the comma operator + StrSize index = new_man.find(static_cast(conv.comma), 0); + + if( index == string_type::npos ) + index = new_man.size(); + + ToString_Group_man_before_comma(new_man, conv, index); + ToString_Group_man_after_comma(new_man, conv, index+1); + } + + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man_before_comma( string_type & new_man, const Conv & conv, + typename string_type::size_type & index) const + { + typedef typename string_type::size_type StrSize; + uint group = 0; + + StrSize i = index; + + // adding group characters before the comma operator + // i>0 because on the first position we don't put any additional grouping characters + for( ; i>0 ; --i, ++group) + { + if( group >= 3 ) + { + group = 0; + new_man.insert(i, 1, static_cast(conv.group)); + ++index; + } + } + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man_after_comma(string_type & new_man, const Conv & conv, + typename string_type::size_type index) const + { + uint group = 0; + + for( ; index= 3 ) + { + group = 0; + new_man.insert(index, 1, static_cast(conv.group)); + ++index; + } + } + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma( string_type & new_man, + const Conv & conv ) const + { + if( conv.round >= 0 ) + ToString_CorrectDigitsAfterComma_Round(new_man, conv); + + if( conv.trim_zeroes ) + ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters( + string_type & new_man, + const Conv & conv) const + { + // minimum two characters + if( new_man.length() < 2 ) + return; + + // we're looking for the index of the last character which is not zero + uint i = uint( new_man.length() ) - 1; + for( ; i>0 && new_man[i]=='0' ; --i ); + + // if there is another character than zero at the end + // we're finishing + if( i == new_man.length() - 1 ) + return; + + // we must have a comma + // (the comma can be removed by ToString_CorrectDigitsAfterComma_Round + // which is called before) + if( new_man.find_last_of(static_cast(conv.comma), i) == string_type::npos ) + return; + + // if directly before the first zero is the comma operator + // we're cutting it as well + if( i>0 && new_man[i]==static_cast(conv.comma) ) + --i; + + new_man.erase(i+1, new_man.length()-i-1); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma_Round( + string_type & new_man, + const Conv & conv ) const + { + typedef typename string_type::size_type StrSize; + + // first we're looking for the comma operator + StrSize index = new_man.find(static_cast(conv.comma), 0); + + if( index == string_type::npos ) + // nothing was found (actually there can't be this situation) + return; + + // we're calculating how many digits there are at the end (after the comma) + // 'after_comma' will be greater than zero because at the end + // we have at least one digit + StrSize after_comma = new_man.length() - index - 1; + + // if 'max_digit_after_comma' is greater than 'after_comma' (or equal) + // we don't have anything for cutting + if( static_cast(conv.round) >= after_comma ) + return; + + uint last_digit = Misc::CharToDigit( new_man[ index + conv.round + 1 ], conv.base ); + + // we're cutting the rest of the string + new_man.erase(index + conv.round + 1, after_comma - conv.round); + + if( conv.round == 0 ) + { + // we're cutting the comma operator as well + // (it's not needed now because we've cut the whole rest after the comma) + new_man.erase(index, 1); + } + + if( last_digit >= conv.base / 2 ) + // we must round here + ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); + } + + + +public: + + /*! + a method for converting a string into its value + + it returns 1 if the value is too big -- we cannot pass it into the range + of our class Big (or if the base is incorrect) + + that means only digits before the comma operator can make this value too big, + all digits after the comma we can ignore + + 'source' - pointer to the string for parsing + + if 'after_source' is set that when this method finishes + it sets the pointer to the new first character after parsed value + + 'value_read' - if the pointer is provided that means the value_read will be true + only when a value has been actually read, there can be situation where only such + a string '-' or '+' will be parsed -- 'after_source' will be different from 'source' but + no value has been read (there are no digits) + on other words if 'value_read' is true -- there is at least one digit in the string + */ + uint FromString(const char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0) + { + Conv conv; + conv.base = base; + + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const wchar_t * source, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + Conv conv; + conv.base = base; + + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const char * source, const Conv & conv, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const wchar_t * source, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::string & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), base, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::wstring & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), base, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::string & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::wstring & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), conv, after_source, value_read); + } + +private: + + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * source, const Conv & conv, const char_type ** after_source = 0, bool * value_read = 0) + { + bool is_sign; + bool value_read_temp = false; + + if( conv.base<2 || conv.base>16 ) + { + SetNan(); + + if( after_source ) + *after_source = source; + + if( value_read ) + *value_read = value_read_temp; + + return 1; + } + + SetZero(); + FromString_TestSign( source, is_sign ); + + uint c = FromString_ReadPartBeforeComma( source, conv, value_read_temp ); + + if( FromString_TestCommaOperator(source, conv) ) + c += FromString_ReadPartAfterComma( source, conv, value_read_temp ); + + if( value_read_temp && conv.base == 10 ) + c += FromString_ReadScientificIfExists( source ); + + if( is_sign && !IsZero() ) + ChangeSign(); + + if( after_source ) + *after_source = source; + + if( value_read ) + *value_read = value_read_temp; + + return CheckCarry(c); + } + + + /*! + we're testing whether the value is with the sign + + (this method is used from 'FromString_ReadPartScientific' too) + */ + template + void FromString_TestSign( const char_type * & source, bool & is_sign ) + { + Misc::SkipWhiteCharacters(source); + + is_sign = false; + + if( *source == '-' ) + { + is_sign = true; + ++source; + } + else + if( *source == '+' ) + { + ++source; + } + } + + + /*! + we're testing whether there's a comma operator + */ + template + bool FromString_TestCommaOperator(const char_type * & source, const Conv & conv) + { + if( (*source == static_cast(conv.comma)) || + (*source == static_cast(conv.comma2) && conv.comma2 != 0 ) ) + { + ++source; + + return true; + } + + return false; + } + + + /*! + this method reads the first part of a string + (before the comma operator) + */ + template + uint FromString_ReadPartBeforeComma( const char_type * & source, const Conv & conv, bool & value_read ) + { + sint character; + Big temp; + Big base_( conv.base ); + + Misc::SkipWhiteCharacters( source ); + + for( ; true ; ++source ) + { + if( conv.group!=0 && *source==static_cast(conv.group) ) + continue; + + character = Misc::CharToDigit(*source, conv.base); + + if( character == -1 ) + break; + + value_read = true; + temp = character; + + if( Mul(base_) ) + return 1; + + if( Add(temp) ) + return 1; + } + + return 0; + } + + + /*! + this method reads the second part of a string + (after the comma operator) + */ + template + uint FromString_ReadPartAfterComma( const char_type * & source, const Conv & conv, bool & value_read ) + { + sint character; + uint c = 0, index = 1; + Big sum, part, power, old_value, base_( conv.base ); + + // we don't remove any white characters here + + // this is only to avoid getting a warning about an uninitialized object 'old_value' which GCC reports + // (in fact we will initialize it later when the condition 'testing' is fulfilled) + old_value.SetZero(); + + power.SetOne(); + sum.SetZero(); + + for( ; true ; ++source, ++index ) + { + if( conv.group!=0 && *source==static_cast(conv.group) ) + continue; + + character = Misc::CharToDigit(*source, conv.base); + + if( character == -1 ) + break; + + value_read = true; + + part = character; + + if( power.Mul( base_ ) ) + // there's no sens to add the next parts, but we can't report this + // as an error (this is only inaccuracy) + break; + + if( part.Div( power ) ) + break; + + // every 5 iteration we make a test whether the value will be changed or not + // (character must be different from zero to this test) + bool testing = (character != 0 && (index % 5) == 0); + + if( testing ) + old_value = sum; + + // there actually shouldn't be a carry here + c += sum.Add( part ); + + if( testing && old_value == sum ) + // after adding 'part' the value has not been changed + // there's no sense to add any next parts + break; + } + + // we could break the parsing somewhere in the middle of the string, + // but the result (value) still can be good + // we should set a correct value of 'source' now + for( ; Misc::CharToDigit(*source, conv.base) != -1 ; ++source ); + + c += Add(sum); + + return (c==0)? 0 : 1; + } + + + /*! + this method checks whether there is a scientific part: [e|E][-|+]value + + it is called when the base is 10 and some digits were read before + */ + template + uint FromString_ReadScientificIfExists(const char_type * & source) + { + uint c = 0; + + bool scientific_read = false; + const char_type * before_scientific = source; + + if( FromString_TestScientific(source) ) + c += FromString_ReadPartScientific( source, scientific_read ); + + if( !scientific_read ) + source = before_scientific; + + return (c==0)? 0 : 1; + } + + + + /*! + we're testing whether is there the character 'e' + + this character is only allowed when we're using the base equals 10 + */ + template + bool FromString_TestScientific(const char_type * & source) + { + Misc::SkipWhiteCharacters(source); + + if( *source=='e' || *source=='E' ) + { + ++source; + + return true; + } + + return false; + } + + + /*! + this method reads the exponent (after 'e' character) when there's a scientific + format of value and only when we're using the base equals 10 + */ + template + uint FromString_ReadPartScientific( const char_type * & source, bool & scientific_read ) + { + uint c = 0; + Big new_exponent, temp; + bool was_sign = false; + + FromString_TestSign( source, was_sign ); + c += FromString_ReadPartScientific_ReadExponent( source, new_exponent, scientific_read ); + + if( scientific_read ) + { + if( was_sign ) + new_exponent.ChangeSign(); + + temp = 10; + c += temp.Pow( new_exponent ); + c += Mul(temp); + } + + return (c==0)? 0 : 1; + } + + + /*! + this method reads the value of the extra exponent when scientific format is used + (only when base == 10) + */ + template + uint FromString_ReadPartScientific_ReadExponent( const char_type * & source, Big & new_exponent, bool & scientific_read ) + { + sint character; + Big base, temp; + + Misc::SkipWhiteCharacters(source); + + new_exponent.SetZero(); + base = 10; + + for( ; (character=Misc::CharToDigit(*source, 10)) != -1 ; ++source ) + { + scientific_read = true; + + temp = character; + + if( new_exponent.Mul(base) ) + return 1; + + if( new_exponent.Add(temp) ) + return 1; + } + + return 0; + } + + +public: + + + /*! + a constructor for converting a string into this class + */ + Big(const char * string) + { + FromString( string ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const wchar_t * string) + { + FromString( string ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const std::string & string) + { + FromString( string.c_str() ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const std::wstring & string) + { + FromString( string.c_str() ); + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const char * string) + { + FromString( string ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const wchar_t * string) + { + FromString( string ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const std::string & string) + { + FromString( string.c_str() ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const std::wstring & string) + { + FromString( string.c_str() ); + + return *this; + } + + + + /*! + * + * methods for comparing + * + */ + + + /*! + this method performs the formula 'abs(this) < abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool SmallerWithoutSignThan(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return true; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return false; + + // we're using the fact that all bits in mantissa are pushed + // into the left side -- Standardizing() + if( exponent == ss2.exponent ) + return mantissa < ss2.mantissa; + + return exponent < ss2.exponent; + } + + + /*! + this method performs the formula 'abs(this) > abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool GreaterWithoutSignThan(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return true; + + // we're using the fact that all bits in mantissa are pushed + // into the left side -- Standardizing() + if( exponent == ss2.exponent ) + return mantissa > ss2.mantissa; + + return exponent > ss2.exponent; + } + + + /*! + this method performs the formula 'abs(this) == abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool EqualWithoutSign(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return true; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return false; + + if( exponent==ss2.exponent && mantissa==ss2.mantissa ) + return true; + + return false; + } + + + bool operator<(const Big & ss2) const + { + if( IsSign() && !ss2.IsSign() ) + // this<0 and ss2>=0 + return true; + + if( !IsSign() && ss2.IsSign() ) + // this>=0 and ss2<0 + return false; + + // both signs are the same + + if( IsSign() ) + return ss2.SmallerWithoutSignThan( *this ); + + return SmallerWithoutSignThan( ss2 ); + } + + + bool operator==(const Big & ss2) const + { + if( IsSign() != ss2.IsSign() ) + return false; + + return EqualWithoutSign( ss2 ); + } + + + bool operator>(const Big & ss2) const + { + if( IsSign() && !ss2.IsSign() ) + // this<0 and ss2>=0 + return false; + + if( !IsSign() && ss2.IsSign() ) + // this>=0 and ss2<0 + return true; + + // both signs are the same + + if( IsSign() ) + return ss2.GreaterWithoutSignThan( *this ); + + return GreaterWithoutSignThan( ss2 ); + } + + + bool operator>=(const Big & ss2) const + { + return !operator<( ss2 ); + } + + + bool operator<=(const Big & ss2) const + { + return !operator>( ss2 ); + } + + + bool operator!=(const Big & ss2) const + { + return !operator==(ss2); + } + + + + + + /*! + * + * standard mathematical operators + * + */ + + + /*! + an operator for changing the sign + + this method is not changing 'this' but the changed value is returned + */ + Big operator-() const + { + Big temp(*this); + + temp.ChangeSign(); + + return temp; + } + + + Big operator-(const Big & ss2) const + { + Big temp(*this); + + temp.Sub(ss2); + + return temp; + } + + Big & operator-=(const Big & ss2) + { + Sub(ss2); + + return *this; + } + + + Big operator+(const Big & ss2) const + { + Big temp(*this); + + temp.Add(ss2); + + return temp; + } + + + Big & operator+=(const Big & ss2) + { + Add(ss2); + + return *this; + } + + + Big operator*(const Big & ss2) const + { + Big temp(*this); + + temp.Mul(ss2); + + return temp; + } + + + Big & operator*=(const Big & ss2) + { + Mul(ss2); + + return *this; + } + + + Big operator/(const Big & ss2) const + { + Big temp(*this); + + temp.Div(ss2); + + return temp; + } + + + Big & operator/=(const Big & ss2) + { + Div(ss2); + + return *this; + } + + + /*! + this method makes an integer value by skipping any fractions + + for example: + 10.7 will be 10 + 12.1 -- 12 + -20.2 -- 20 + -20.9 -- 20 + -0.7 -- 0 + 0.8 -- 0 + */ + void SkipFraction() + { + if( IsNan() || IsZero() ) + return; + + if( !exponent.IsSign() ) + // exponent >=0 -- the value don't have any fractions + return; + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + { + // the value is from (-1,1), we return zero + SetZero(); + return; + } + + // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) + sint e = exponent.ToInt(); + + mantissa.ClearFirstBits( -e ); + + // we don't have to standardize 'Standardizing()' the value because + // there's at least one bit in the mantissa + // (the highest bit which we didn't touch) + } + + + /*! + this method remains only a fraction from the value + + for example: + 30.56 will be 0.56 + -12.67 -- -0.67 + */ + void RemainFraction() + { + if( IsNan() || IsZero() ) + return; + + if( !exponent.IsSign() ) + { + // exponent >= 0 -- the value doesn't have any fractions + // we return zero + SetZero(); + return; + } + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + { + // the value is from (-1,1) + // we don't make anything with the value + return; + } + + // e will be from (-man*TTMATH_BITS_PER_UINT, 0) + sint e = exponent.ToInt(); + + sint how_many_bits_leave = sint(man*TTMATH_BITS_PER_UINT) + e; // there'll be a subtraction -- e is negative + mantissa.Rcl( how_many_bits_leave, 0); + + // there'll not be a carry because the exponent is too small + exponent.Sub( how_many_bits_leave ); + + // we must call Standardizing() here + Standardizing(); + } + + + + /*! + this method returns true if the value is integer + (there is no a fraction) + + (we don't check nan) + */ + bool IsInteger() const + { + if( IsZero() ) + return true; + + if( !exponent.IsSign() ) + // exponent >=0 -- the value don't have any fractions + return true; + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + // the value is from (-1,1) + return false; + + // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) + sint e = exponent.ToInt(); + e = -e; // e means how many bits we must check + + uint len = e / TTMATH_BITS_PER_UINT; + uint rest = e % TTMATH_BITS_PER_UINT; + uint i = 0; + + for( ; i 0 ) + { + uint rest_mask = TTMATH_UINT_MAX_VALUE >> (TTMATH_BITS_PER_UINT - rest); + if( (mantissa.table[i] & rest_mask) != 0 ) + return false; + } + + return true; + } + + + /*! + this method rounds to the nearest integer value + (it returns a carry if it was) + + for example: + 2.3 = 2 + 2.8 = 3 + + -2.3 = -2 + -2.8 = 3 + */ + uint Round() + { + Big half; + uint c; + + if( IsNan() ) + return 1; + + if( IsZero() ) + return 0; + + half.Set05(); + + if( IsSign() ) + { + // 'this' is < 0 + c = Sub( half ); + } + else + { + // 'this' is > 0 + c = Add( half ); + } + + SkipFraction(); + + return CheckCarry(c); + } + + + + /*! + * + * input/output operators for standard streams + * + */ + +private: + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const Big & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const Big & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const Big & l) + { + return OutputToStream(s, l); + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + static istream_type & InputFromStream(istream_type & s, Big & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z, old_z; + bool was_comma = false; + bool was_e = false; + + + // operator>> omits white characters if they're set for ommiting + s >> z; + + if( z=='-' || z=='+' ) + { + ss += z; + s >> z; // we're reading a next character (white characters can be ommited) + } + + old_z = 0; + + // we're reading only digits (base=10) and only one comma operator + for( ; s.good() ; z=static_cast(s.get()) ) + { + if( z=='.' || z==',' ) + { + if( was_comma || was_e ) + // second comma operator or comma operator after 'e' character + break; + + was_comma = true; + } + else + if( z == 'e' || z == 'E' ) + { + if( was_e ) + // second 'e' character + break; + + was_e = true; + } + else + if( z == '+' || z == '-' ) + { + if( old_z != 'e' && old_z != 'E' ) + // '+' or '-' is allowed only after 'e' character + break; + } + else + if( Misc::CharToDigit(z, 10) < 0 ) + break; + + + ss += z; + old_z = z; + } + + // we're leaving the last read character + // (it's not belonging to the value) + s.unget(); + + l.FromString( ss ); + + return s; + } + + + +public: + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, Big & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, Big & l) + { + return InputFromStream(s, l); + } + +}; + + +} // namespace + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathint.h b/src/libghost/ttmath/ttmath/ttmathint.h new file mode 100644 index 0000000..bf2c55a --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathint.h @@ -0,0 +1,1547 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmathint +#define headerfilettmathint + +/*! + \file ttmathint.h + \brief template class Int +*/ + +#include "ttmathuint.h" + +namespace ttmath +{ + + +/*! + \brief Int implements a big integer value with a sign + + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits + value_size = 1,2,3,4,5,6.... +*/ +template +class Int : public UInt +{ +public: + + /*! + this method sets the max value which this class can hold + (all bits will be one besides the last one) + */ + void SetMax() + { + UInt::SetMax(); + UInt::table[value_size-1] = ~ TTMATH_UINT_HIGHEST_BIT; + } + + + /*! + this method sets the min value which this class can hold + (all bits will be zero besides the last one which is one) + */ + void SetMin() + { + UInt::SetZero(); + UInt::table[value_size-1] = TTMATH_UINT_HIGHEST_BIT; + } + + + /*! + this method sets -1 as the value + (-1 is equal the max value in an unsigned type) + */ + void SetSignOne() + { + UInt::SetMax(); + } + + + /*! + we change the sign of the value + + if it isn't possible to change the sign this method returns 1 + else return 0 and changing the sign + */ + uint ChangeSign() + { + Int temp; + + temp.SetMin(); + + /* + if the value is equal that one which has been returned from SetMin + that means we can't change sign because the value is too big (bigger about one) + + e.g. when value_size = 1 and value is -2147483648 we can't change it to the + 2147483648 because the max value which can be held is 2147483647 + + we don't change the value and we're using this fact somewhere in some methods + (if we look on our value without the sign we get the correct value + eg. -2147483648 in Int<1> will be 2147483648 on the UInt<1> type) + */ + if( operator==(temp) ) + return 1; + + temp.SetZero(); + temp.UInt::Sub(*this); + + operator=(temp); + + return 0; + } + + + + /*! + this method sets the sign + + e.g. 1 -> -1 + -2 -> -2 + + from a positive value we make a negative value, + if the value is negative we do nothing + */ + void SetSign() + { + if( IsSign() ) + return; + + ChangeSign(); + } + + + + /*! + this method returns true if there's the sign + + (the highest bit will be converted to the bool) + */ + bool IsSign() const + { + return UInt::IsTheHighestBitSet(); + } + + + + /*! + it sets an absolute value + + it can return carry (1) (look on ChangeSign() for details) + */ + uint Abs() + { + if( !IsSign() ) + return 0; + + return ChangeSign(); + } + + + + + /*! + * + * basic mathematic functions + * + */ + +private: + + uint CorrectCarryAfterAdding(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && !p2_is_sign ) + { + if( UInt::IsTheHighestBitSet() ) + return 1; + } + + if( p1_is_sign && p2_is_sign ) + { + if( ! UInt::IsTheHighestBitSet() ) + return 1; + } + + return 0; + } + + +public: + + /*! + this method adds two value with a sign and returns a carry + + we're using methods from the base class because values are stored with U2 + we must only make the carry correction + + this = p1(=this) + p2 + + when p1>=0 i p2>=0 carry is set when the highest bit of value is set + when p1<0 i p2<0 carry is set when the highest bit of value is clear + when p1>=0 i p2<0 carry will never be set + when p1<0 i p2>=0 carry will never be set + */ + uint Add(const Int & ss2) + { + bool p1_is_sign = IsSign(); + bool p2_is_sign = ss2.IsSign(); + + UInt::Add(ss2); + + return CorrectCarryAfterAdding(p1_is_sign, p2_is_sign); + } + + + /*! + this method adds one *unsigned* word (at a specific position) + and returns a carry (if it was) + + look at a description in UInt<>::AddInt(...) + */ + uint AddInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::AddInt(value, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + + + /*! + this method adds two *unsigned* words to the existing value + and these words begin on the 'index' position + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + look at a description in UInt<>::AddTwoInts(...) + */ + uint AddTwoInts(uint x2, uint x1, uint index) + { + bool p1_is_sign = IsSign(); + + UInt::AddTwoInts(x2, x1, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + +private: + + uint CorrectCarryAfterSubtracting(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && p2_is_sign ) + { + if( UInt::IsTheHighestBitSet() ) + return 1; + } + + if( p1_is_sign && !p2_is_sign ) + { + if( ! UInt::IsTheHighestBitSet() ) + return 1; + } + + return 0; + } + +public: + + /*! + this method subtracts two values with a sign + + we don't use the previous Add because the method ChangeSign can + sometimes return carry + + this = p1(=this) - p2 + + when p1>=0 i p2>=0 carry will never be set + when p1<0 i p2<0 carry will never be set + when p1>=0 i p2<0 carry is set when the highest bit of value is set + when p1<0 i p2>=0 carry is set when the highest bit of value is clear + */ + uint Sub(const Int & ss2) + { + bool p1_is_sign = IsSign(); + bool p2_is_sign = ss2.IsSign(); + + UInt::Sub(ss2); + + return CorrectCarryAfterSubtracting(p1_is_sign, p2_is_sign); + } + + + /*! + this method subtracts one *unsigned* word (at a specific position) + and returns a carry (if it was) + */ + uint SubInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::SubInt(value, index); + + return CorrectCarryAfterSubtracting(p1_is_sign, false); + } + + + /*! + this method adds one to the value and returns carry + */ + uint AddOne() + { + bool p1_is_sign = IsSign(); + + UInt::AddOne(); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + + + /*! + this method subtracts one from the value and returns carry + */ + uint SubOne() + { + bool p1_is_sign = IsSign(); + + UInt::SubOne(); + + return CorrectCarryAfterSubtracting(p1_is_sign, false); + } + + + + /*! + multiplication this = this * ss2 + + it returns carry if the result is too big + (we're using the method from the base class but we have to make + one correction in account of signs) + */ + uint Mul(Int ss2) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + ss2_is_sign = ss2.IsSign(); + + /* + we don't have to check the carry from Abs (values will be correct + because next we're using the method Mul from the base class UInt + which is without a sign) + */ + Abs(); + ss2.Abs(); + + if( UInt::Mul(ss2) ) + return 1; + + + /* + we have to examine the sign of the result now + but if the result is with the sign then: + 1. if the signs were the same that means the result is too big + (the result must be without a sign) + 2. if the signs were different that means if the result + is different from that one which has been returned from SetMin() + that is carry (result too big) but if the result is equal SetMin() + there'll be ok (and the next SetSign will has no effect because + the value is actually negative -- look at description of that case + in ChangeSign()) + */ + if( IsSign() ) + { + /* + there can be one case where signs are different and + the result will be equal the value from SetMin() + (this situation is ok) + */ + if( ss1_is_sign != ss2_is_sign ) + { + Int temp; + temp.SetMin(); + + if( operator!=(temp) ) + /* + the result is too big + */ + return 1; + } + else + { + /* + the result is too big + */ + return 1; + } + } + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + + return 0; + } + + + /*! + division this = this / ss2 + returned values: + 0 - ok + 1 - division by zero + + for example: (result means 'this') + 20 / 3 --> result: 6 remainder: 2 + -20 / 3 --> result: -6 remainder: -2 + 20 / -3 --> result: -6 remainder: 2 + -20 / -3 --> result: 6 remainder: -2 + + in other words: this(old) = ss2 * this(new)(result) + remainder + */ + uint Div(Int ss2, Int * remainder = 0) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + ss2_is_sign = ss2.IsSign(); + + /* + we don't have to test the carry from Abs as well as in Mul + */ + Abs(); + ss2.Abs(); + + uint c = UInt::Div(ss2, remainder); + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + if( ss1_is_sign && remainder ) + remainder->SetSign(); + + return c; + } + + uint Div(const Int & ss2, Int & remainder) + { + return Div(ss2, &remainder); + } + + + /*! + division this = this / ss2 (ss2 is int) + returned values: + 0 - ok + 1 - division by zero + + for example: (result means 'this') + 20 / 3 --> result: 6 remainder: 2 + -20 / 3 --> result: -6 remainder: -2 + 20 / -3 --> result: -6 remainder: 2 + -20 / -3 --> result: 6 remainder: -2 + + in other words: this(old) = ss2 * this(new)(result) + remainder + */ + uint DivInt(sint ss2, sint * remainder = 0) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + + /* + we don't have to test the carry from Abs as well as in Mul + */ + Abs(); + + if( ss2 < 0 ) + { + ss2 = -ss2; + ss2_is_sign = true; + } + else + { + ss2_is_sign = false; + } + + uint rem; + uint c = UInt::DivInt((uint)ss2, &rem); + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + if( remainder ) + { + if( ss1_is_sign ) + *remainder = -sint(rem); + else + *remainder = sint(rem); + } + + return c; + } + + + uint DivInt(sint ss2, sint & remainder) + { + return DivInt(ss2, &remainder); + } + + +private: + + + /*! + power this = this ^ pow + this can be negative + pow is >= 0 + */ + uint Pow2(const Int & pow) + { + bool was_sign = IsSign(); + uint c = 0; + + if( was_sign ) + c += Abs(); + + uint c_temp = UInt::Pow(pow); + if( c_temp > 0 ) + return c_temp; // c_temp can be: 0, 1 or 2 + + if( was_sign && (pow.table[0] & 1) == 1 ) + // negative value to the power of odd number is negative + c += ChangeSign(); + + return (c==0)? 0 : 1; + } + + +public: + + + /*! + power this = this ^ pow + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + uint Pow(Int pow) + { + if( !pow.IsSign() ) + return Pow2(pow); + + if( UInt::IsZero() ) + // if 'pow' is negative then + // 'this' must be different from zero + return 2; + + if( pow.ChangeSign() ) + return 1; + + Int t(*this); + uint c_temp = t.Pow2(pow); + if( c_temp > 0 ) + return c_temp; + + UInt::SetOne(); + if( Div(t) ) + return 1; + + return 0; + } + + + + /*! + * + * convertion methods + * + */ +private: + + + /*! + an auxiliary method for converting both from UInt and Int + */ + template + uint FromUIntOrInt(const UInt & p, bool UInt_type) + { + uint min_size = (value_size < argument_size)? value_size : argument_size; + uint i; + + for(i=0 ; i::table[i] = p.table[i]; + + + if( value_size > argument_size ) + { + uint fill; + + if( UInt_type ) + fill = 0; + else + fill = (p.table[argument_size-1] & TTMATH_UINT_HIGHEST_BIT)? + TTMATH_UINT_MAX_VALUE : 0; + + // 'this' is longer than 'p' + for( ; i::table[i] = fill; + } + else + { + uint test = (UInt::table[value_size-1] & TTMATH_UINT_HIGHEST_BIT)? + TTMATH_UINT_MAX_VALUE : 0; + + if( UInt_type && test!=0 ) + return 1; + + for( ; i type into this class + + this operation has mainly sense if the value from p + can be held in this type + + it returns a carry if the value 'p' is too big + */ + template + uint FromInt(const Int & p) + { + return FromUIntOrInt(p, false); + } + + + /*! + this method converts the sint type into this class + */ + uint FromInt(sint value) + { + uint fill = ( value<0 ) ? TTMATH_UINT_MAX_VALUE : 0; + + for(uint i=1 ; i::table[i] = fill; + + UInt::table[0] = uint(value); + + // there'll never be a carry here + return 0; + } + + + /*! + this method converts UInt into this class + */ + template + uint FromUInt(const UInt & p) + { + return FromUIntOrInt(p, true); + } + + + /*! + this method converts the uint type into this class + */ + uint FromUInt(uint value) + { + for(uint i=1 ; i::table[i] = 0; + + UInt::table[0] = value; + + // there can be a carry here when the size of this value is equal one word + // and the 'value' has the highest bit set + if( value_size==1 && (value & TTMATH_UINT_HIGHEST_BIT)!=0 ) + return 1; + + return 0; + } + + + + /*! + the default assignment operator + */ + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + this operator converts an Int type to this class + + it doesn't return a carry + */ + template + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + this method converts the sint type to this class + */ + Int & operator=(sint i) + { + FromInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + Int(sint i) + { + FromInt(i); + } + + + /*! + a copy constructor + */ + Int(const Int & u) + { + FromInt(u); + } + + + /*! + a constructor for copying from another types + */ + template + Int(const Int & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromInt(u); + } + + + + /*! + this operator converts an UInt type to this class + + it doesn't return a carry + */ + template + Int & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + + /*! + this method converts the Uint type to this class + */ + Int & operator=(uint i) + { + FromUInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + Int(uint i) + { + FromUInt(i); + } + + + /*! + a constructor for copying from another types + */ + template + Int(const UInt & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromUInt(u); + } + + + + +#ifdef TTMATH_PLATFORM64 + + /*! + this method converts the signed int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int & operator=(signed int i) + { + FromInt(sint(i)); + + return *this; + } + + + /*! + a constructor for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int(signed int i) + { + FromInt(sint(i)); + } + + + /*! + this method converts the unsigned int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int & operator=(unsigned int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the unsigned int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int(unsigned int i) + { + FromUInt(uint(i)); + } + +#endif + + + /*! + a constructor for converting string to this class (with the base=10) + */ + Int(const char * s) + { + FromString(s); + } + + + /*! + a constructor for converting string to this class (with the base=10) + */ + Int(const wchar_t * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + Int(const std::string & s) + { + FromString( s.c_str() ); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + Int(const std::wstring & s) + { + FromString( s.c_str() ); + } + + + /*! + a default constructor + + we don't clear table etc. + */ + Int() + { + } + + + /*! + the destructor + */ + ~Int() + { + } + + + /*! + this method returns the lowest value from table with a sign + + we must be sure when we using this method whether the value + will hold in an sint type or not (the rest value from table must be zero or -1) + */ + sint ToInt() const + { + return sint( UInt::table[0] ); + } + + +private: + + /*! + an auxiliary method for converting to a string + */ + template + void ToStringBase(string_type & result, uint b = 10) const + { + if( IsSign() ) + { + Int temp(*this); + temp.Abs(); + + temp.UInt::ToString(result, b); + result.insert(result.begin(), '-'); + } + else + { + UInt::ToString(result, b); + } + } + +public: + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::wstring & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + std::string ToString(uint b = 10) const + { + std::string result; + ToStringBase(result, b); + + return result; + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + std::wstring ToWString(uint b = 10) const + { + std::wstring result; + ToStringBase(result, b); + + return result; + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) + { + bool is_sign = false; + + Misc::SkipWhiteCharacters(s); + + if( *s == '-' ) + { + is_sign = true; + Misc::SkipWhiteCharacters(++s); + } + else + if( *s == '+' ) + { + Misc::SkipWhiteCharacters(++s); + } + + if( UInt::FromString(s,b,after_source,value_read) ) + return 1; + + if( is_sign ) + { + Int mmin; + + mmin.SetMin(); + + /* + the reference to mmin will be automatically converted to the reference + to UInt type + (this value can be equal mmin -- look at a description in ChangeSign()) + */ + if( UInt::operator>( mmin ) ) + return 1; + + /* + if the value is equal mmin the method ChangeSign() does nothing (only returns 1 but we ignore it) + */ + ChangeSign(); + } + else + { + Int mmax; + + mmax.SetMax(); + + if( UInt::operator>( mmax ) ) + return 1; + } + + return 0; + } + + +public: + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + + string is ended with a non-digit value, for example: + "-12" will be translated to -12 + as well as: + "- 12foo" will be translated to -12 too + + existing first white characters will be ommited + (between '-' and a first digit can be white characters too) + + after_source (if exists) is pointing at the end of the parsed string + + value_read (if exists) tells whether something has actually been read (at least one digit) + */ + uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + */ + uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + */ + uint FromString(const std::string & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + */ + uint FromString(const std::wstring & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const char * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const wchar_t * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const std::wstring & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + * + * methods for comparing + * + * + */ + + bool operator==(const Int & l) const + { + return UInt::operator==(l); + } + + bool operator!=(const Int & l) const + { + return UInt::operator!=(l); + } + + bool operator<(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] < l.table[i]; + } + + // they're equal + return false; + } + + + bool operator>(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] > l.table[i]; + } + + // they're equal + return false; + } + + + bool operator<=(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] < l.table[i]; + } + + // they're equal + return true; + } + + + bool operator>=(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] > l.table[i]; + } + + // they're equal + return true; + } + + + + /*! + * + * standard mathematical operators + * + */ + + + /*! + an operator for changing the sign + + it's not changing 'this' but the changed value will be returned + */ + Int operator-() const + { + Int temp(*this); + + temp.ChangeSign(); + + return temp; + } + + + Int operator-(const Int & p2) const + { + Int temp(*this); + + temp.Sub(p2); + + return temp; + } + + + Int & operator-=(const Int & p2) + { + Sub(p2); + + return *this; + } + + + Int operator+(const Int & p2) const + { + Int temp(*this); + + temp.Add(p2); + + return temp; + } + + + Int & operator+=(const Int & p2) + { + Add(p2); + + return *this; + } + + + Int operator*(const Int & p2) const + { + Int temp(*this); + + temp.Mul(p2); + + return temp; + } + + + Int & operator*=(const Int & p2) + { + Mul(p2); + + return *this; + } + + + Int operator/(const Int & p2) const + { + Int temp(*this); + + temp.Div(p2); + + return temp; + } + + + Int & operator/=(const Int & p2) + { + Div(p2); + + return *this; + } + + + Int operator%(const Int & p2) const + { + Int temp(*this); + Int remainder; + + temp.Div(p2, remainder); + + return remainder; + } + + + Int & operator%=(const Int & p2) + { + Int temp(*this); + Int remainder; + + temp.Div(p2, remainder); + + operator=(remainder); + + return *this; + } + + + /*! + Prefix operator e.g. ++variable + */ + UInt & operator++() + { + AddOne(); + + return *this; + } + + + /*! + Postfix operator e.g. variable++ + */ + UInt operator++(int) + { + UInt temp( *this ); + + AddOne(); + + return temp; + } + + + UInt & operator--() + { + SubOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + + /*! + * + * input/output operators for standard streams + * + */ + +private: + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const Int & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const Int & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const Int & l) + { + return OutputToStream(s, l); + } + + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + static istream_type & InputFromStream(istream_type & s, Int & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z; + + // operator>> omits white characters if they're set for ommiting + s >> z; + + if( z=='-' || z=='+' ) + { + ss += z; + s >> z; // we're reading a next character (white characters can be ommited) + } + + // we're reading only digits (base=10) + while( s.good() && Misc::CharToDigit(z, 10)>=0 ) + { + ss += z; + z = static_cast(s.get()); + } + + // we're leaving the last readed character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + + +public: + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, Int & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, Int & l) + { + return InputFromStream(s, l); + } + +}; + +} // namespace + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathmisc.h b/src/libghost/ttmath/ttmath/ttmathmisc.h new file mode 100644 index 0000000..38ab596 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathmisc.h @@ -0,0 +1,243 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + +#ifndef headerfilettmathmisc +#define headerfilettmathmisc + + +/*! + \file ttmathmisc.h + \brief some helpful functions +*/ + + +#include + + +namespace ttmath +{ + +/*! + some helpful functions +*/ +class Misc +{ +public: + + +/* + * + * AssignString(result, str) + * result = str + * + */ + +/*! + result = str +*/ +static void AssignString(std::string & result, const char * str) +{ + result = str; +} + + +/*! + result = str +*/ +static void AssignString(std::wstring & result, const char * str) +{ + result.clear(); + + for( ; *str ; ++str ) + result += *str; +} + + +/*! + result = str +*/ +static void AssignString(std::wstring & result, const std::string & str) +{ + return AssignString(result, str.c_str()); +} + + +/*! + result = str +*/ +static void AssignString(std::string & result, const wchar_t * str) +{ + result.clear(); + + for( ; *str ; ++str ) + result += static_cast(*str); +} + + +/*! + result = str +*/ +static void AssignString(std::string & result, const std::wstring & str) +{ + return AssignString(result, str.c_str()); +} + + +/* + * + * AddString(result, str) + * result += str + * + */ + + +/*! + result += str +*/ +static void AddString(std::string & result, const char * str) +{ + result += str; +} + + +/*! + result += str +*/ +static void AddString(std::wstring & result, const char * str) +{ + for( ; *str ; ++str ) + result += *str; +} + + + +/* + this method omits any white characters from the string + char_type is char or wchar_t +*/ +template +static void SkipWhiteCharacters(const char_type * & c) +{ + // 13 is at the end in a DOS text file (\r\n) + while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') ) + ++c; +} + + + + +/*! + this static method converts one character into its value + + for example: + 1 -> 1 + 8 -> 8 + A -> 10 + f -> 15 + + this method don't check whether c is correct or not +*/ +static uint CharToDigit(uint c) +{ + if(c>='0' && c<='9') + return c-'0'; + + if(c>='a' && c<='z') + return c-'a'+10; + +return c-'A'+10; +} + + +/*! + this method changes a character 'c' into its value + (if there can't be a correct value it returns -1) + + for example: + c=2, base=10 -> function returns 2 + c=A, base=10 -> function returns -1 + c=A, base=16 -> function returns 10 +*/ +static sint CharToDigit(uint c, uint base) +{ + if( c>='0' && c<='9' ) + c=c-'0'; + else + if( c>='a' && c<='z' ) + c=c-'a'+10; + else + if( c>='A' && c<='Z' ) + c=c-'A'+10; + else + return -1; + + + if( c >= base ) + return -1; + + +return sint(c); +} + + + +/*! + this method converts a digit into a char + digit should be from <0,F> + (we don't have to get a base) + + for example: + 1 -> 1 + 8 -> 8 + 10 -> A + 15 -> F +*/ +static uint DigitToChar(uint digit) +{ + if( digit < 10 ) + return digit + '0'; + +return digit - 10 + 'A'; +} + + +}; // struct Misc + +} + + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathobjects.h b/src/libghost/ttmath/ttmath/ttmathobjects.h new file mode 100644 index 0000000..5fe343d --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathobjects.h @@ -0,0 +1,766 @@ +/* + * This file is a part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + +#ifndef headerfilettmathobject +#define headerfilettmathobject + +/*! + \file ttmathobjects.h + \brief Mathematic functions. +*/ + +#include +#include +#include +#include + +#include "ttmathtypes.h" +#include "ttmathmisc.h" + + +namespace ttmath +{ + +/*! + objects of this class are used with the mathematical parser + they hold variables or functions defined by a user + + each object has its own table in which we're keeping variables or functions +*/ +class Objects +{ +public: + + + /*! + one item (variable or function) + 'items' will be on the table + */ + struct Item + { + // name of a variable of a function + // internally we store variables and funcions as std::string (not std::wstring even when wide characters are used) + std::string value; + + // number of parameters required by the function + // (if there's a variable this 'param' is ignored) + int param; + + Item() {} + Item(const std::string & v, int p) : value(v), param(p) {} + }; + + // 'Table' is the type of our table + typedef std::map Table; + typedef Table::iterator Iterator; + typedef Table::const_iterator CIterator; + + + + /*! + this method returns true if a character 'c' is a character + which can be in a name + + if 'can_be_digit' is true that means when the 'c' is a digit this + method returns true otherwise it returns false + */ + static bool CorrectCharacter(wchar_t c, bool can_be_digit) + { + if( (c>='a' && c<='z') || (c>='A' && c<='Z') ) + return true; + + if( can_be_digit && ((c>='0' && c<='9') || c=='_') ) + return true; + + return false; + } + + + /*! + this method returns true if the name can be as a name of an object + */ + template + static bool IsNameCorrect(const string_type & name) + { + if( name.empty() ) + return false; + + if( !CorrectCharacter(name[0], false) ) + return false; + + typename string_type::const_iterator i = name.begin(); + + for(++i ; i!=name.end() ; ++i) + if( !CorrectCharacter(*i, true) ) + return false; + + return true; + } + + + /*! + this method returns true if such an object is defined (name exists) + */ + bool IsDefined(const std::string & name) + { + Iterator i = table.find(name); + + if( i != table.end() ) + // we have this object in our table + return true; + + return false; + } + + + /*! + this method returns true if such an object is defined (name exists) + */ + bool IsDefined(const std::wstring & name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return false; + + Misc::AssignString(str_tmp1, name); + + return IsDefined(str_tmp1); + } + + + /*! + this method adds one object (variable of function) into the table + */ + ErrorCode Add(const std::string & name, const std::string & value, int param = 0) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i != table.end() ) + // we have this object in our table + return err_object_exists; + + table.insert( std::make_pair(name, Item(value, param)) ); + + return err_ok; + } + + + /*! + this method adds one object (variable of function) into the table + */ + ErrorCode Add(const std::wstring & name, const std::wstring & value, int param = 0) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + Misc::AssignString(str_tmp2, value); + + return Add(str_tmp1, str_tmp2, param); + } + + + /*! + this method returns 'true' if the table is empty + */ + bool Empty() const + { + return table.empty(); + } + + + /*! + this method clears the table + */ + void Clear() + { + return table.clear(); + } + + + /*! + this method returns 'const_iterator' on the first item on the table + */ + CIterator Begin() const + { + return table.begin(); + } + + + /*! + this method returns 'const_iterator' pointing at the space after last item + (returns table.end()) + */ + CIterator End() const + { + return table.end(); + } + + + /*! + this method changes the value and the number of parameters for a specific object + */ + ErrorCode EditValue(const std::string & name, const std::string & value, int param = 0) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i == table.end() ) + return err_unknown_object; + + i->second.value = value; + i->second.param = param; + + return err_ok; + } + + + /*! + this method changes the value and the number of parameters for a specific object + */ + ErrorCode EditValue(const std::wstring & name, const std::wstring & value, int param = 0) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + Misc::AssignString(str_tmp2, value); + + return EditValue(str_tmp1, str_tmp2, param); + } + + + /*! + this method changes the name of a specific object + */ + ErrorCode EditName(const std::string & old_name, const std::string & new_name) + { + if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) + return err_incorrect_name; + + Iterator old_i = table.find(old_name); + if( old_i == table.end() ) + return err_unknown_object; + + if( old_name == new_name ) + // the new name is the same as the old one + // we treat it as a normal situation + return err_ok; + + ErrorCode err = Add(new_name, old_i->second.value, old_i->second.param); + + if( err == err_ok ) + { + old_i = table.find(old_name); + TTMATH_ASSERT( old_i != table.end() ) + + table.erase(old_i); + } + + return err; + } + + + /*! + this method changes the name of a specific object + */ + ErrorCode EditName(const std::wstring & old_name, const std::wstring & new_name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, old_name); + Misc::AssignString(str_tmp2, new_name); + + return EditName(str_tmp1, str_tmp2); + } + + + /*! + this method deletes an object + */ + ErrorCode Delete(const std::string & name) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i == table.end() ) + return err_unknown_object; + + table.erase( i ); + + return err_ok; + } + + + /*! + this method deletes an object + */ + ErrorCode Delete(const std::wstring & name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return Delete(str_tmp1); + } + + + /*! + this method gets the value of a specific object + */ + ErrorCode GetValue(const std::string & name, std::string & value) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + value.clear(); + return err_unknown_object; + } + + value = i->second.value; + + return err_ok; + } + + + /*! + this method gets the value of a specific object + */ + ErrorCode GetValue(const std::wstring & name, std::wstring & value) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + ErrorCode err = GetValue(str_tmp1, str_tmp2); + Misc::AssignString(value, str_tmp2); + + return err; + } + + + /*! + this method gets the value of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValue(const std::string & name, const char ** value) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + *value = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + + return err_ok; + } + + + /*! + this method gets the value of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValue(const std::wstring & name, const char ** value) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return GetValue(str_tmp1, value); + } + + + /*! + this method gets the value and the number of parameters + of a specific object + */ + ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + value.empty(); + *param = 0; + return err_unknown_object; + } + + value = i->second.value; + *param = i->second.param; + + return err_ok; + } + + + /*! + this method gets the value and the number of parameters + of a specific object + */ + ErrorCode GetValueAndParam(const std::wstring & name, std::wstring & value, int * param) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + ErrorCode err = GetValueAndParam(str_tmp1, str_tmp2, param); + Misc::AssignString(value, str_tmp2); + + return err; + } + + + /*! + this method sets the value and the number of parameters + of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValueAndParam(const std::string & name, const char ** value, int * param) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + *value = 0; + *param = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + *param = i->second.param; + + return err_ok; + } + + + /*! + this method sets the value and the number of parameters + of a specific object + (this version is used for not copying the whole string + but in fact we make one copying during AssignString()) + */ + ErrorCode GetValueAndParam(const std::wstring & name, const char ** value, int * param) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return GetValueAndParam(str_tmp1, value, param); + } + + + /*! + this method returns a pointer into the table + */ + Table * GetTable() + { + return &table; + } + + +private: + + Table table; + std::string str_tmp1, str_tmp2; + +}; // end of class Objects + + + + + + + +/*! + objects of the class History are used to keep values in functions + which take a lot of time during calculating, for instance in the + function Factorial(x) + + it means that when we're calculating e.g. Factorial(1000) and the + Factorial finds that we have calculated it before, the value (result) + is taken from the history +*/ +template +class History +{ + /*! + one item in the History's object holds a key, a value for the key + and a corresponding error code + */ + struct Item + { + ValueType key, value; + ErrorCode err; + }; + + + /*! + we use std::list for simply deleting the first item + but because we're searching through the whole container + (in the method Get) the container should not be too big + (linear time of searching) + */ + typedef std::list buffer_type; + buffer_type buffer; + typename buffer_type::size_type buffer_max_size; + +public: + + /*! + default constructor + default max size of the History's container is 15 items + */ + History() + { + buffer_max_size = 15; + } + + + /*! + a constructor which takes another value of the max size + of the History's container + */ + History(typename buffer_type::size_type new_size) + { + buffer_max_size = new_size; + } + + + /*! + this method adds one item into the History + if the size of the container is greater than buffer_max_size + the first item will be removed + */ + void Add(const ValueType & key, const ValueType & value, ErrorCode err) + { + Item item; + item.key = key; + item.value = value; + item.err = err; + + buffer.insert( buffer.end(), item ); + + if( buffer.size() > buffer_max_size ) + buffer.erase(buffer.begin()); + } + + + /*! + this method checks whether we have an item which has the key equal 'key' + + if there's such item the method sets the 'value' and the 'err' + and returns true otherwise it returns false and 'value' and 'err' + remain unchanged + */ + bool Get(const ValueType & key, ValueType & value, ErrorCode & err) + { + typename buffer_type::iterator i = buffer.begin(); + + for( ; i != buffer.end() ; ++i ) + { + if( i->key == key ) + { + value = i->value; + err = i->err; + return true; + } + } + + return false; + } + + + /*! + this methods deletes an item + + we assume that there is only one item with the 'key' + (this methods removes the first one) + */ + bool Remove(const ValueType & key) + { + typename buffer_type::iterator i = buffer.begin(); + + for( ; i != buffer.end() ; ++i ) + { + if( i->key == key ) + { + buffer.erase(i); + return true; + } + } + + return false; + } + + +}; // end of class History + + + +/*! + this is an auxiliary class used when calculating Gamma() or Factorial() + + in multithreaded environment you can provide an object of this class to + the Gamma() or Factorial() function, e.g; + typedef Big<1, 3> MyBig; + MyBig x = 123456; + CGamma cgamma; + std::cout << Gamma(x, cgamma); + each thread should have its own CGamma<> object + + in a single-thread environment a CGamma<> object is a static variable + in a second version of Gamma() and you don't have to explicitly use it, e.g. + typedef Big<1, 3> MyBig; + MyBig x = 123456; + std::cout << Gamma(x); +*/ +template +struct CGamma +{ + /*! + this table holds factorials + 1 + 1 + 2 + 6 + 24 + 120 + 720 + ....... + */ + std::vector fact; + + + /*! + this table holds Bernoulli numbers + 1 + -0.5 + 0.166666666666666666666666667 + 0 + -0.0333333333333333333333333333 + 0 + 0.0238095238095238095238095238 + 0 + -0.0333333333333333333333333333 + 0 + 0.075757575757575757575757576 + ..... + */ + std::vector bern; + + + /*! + here we store some calculated values + (this is for speeding up, if the next argument of Gamma() or Factorial() + is in the 'history' then the result we are not calculating but simply + return from the 'history' object) + */ + History history; + + + /*! + this method prepares some coefficients: factorials and Bernoulli numbers + stored in 'fact' and 'bern' objects + + how many values should be depends on the size of the mantissa - if + the mantissa is larger then we must calculate more values + for a mantissa which consists of 256 bits (8 words on a 32bit platform) + we have to calculate about 30 values (the size of fact and bern will be 30), + and for a 2048 bits mantissa we have to calculate 306 coefficients + + you don't have to call this method, these coefficients will be automatically calculated + when they are needed + + you must note that calculating these coefficients is a little time-consuming operation, + (especially when the mantissa is large) and first call to Gamma() or Factorial() + can take more time than next calls, and in the end this is the point when InitAll() + comes in handy: you can call this method somewhere at the beginning of your program + */ + void InitAll(); + // definition is in ttmath.h +}; + + + + +} // namespace + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathparser.h b/src/libghost/ttmath/ttmath/ttmathparser.h new file mode 100644 index 0000000..3f9c796 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathparser.h @@ -0,0 +1,2754 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmathparser +#define headerfilettmathparser + +/*! + \file ttmathparser.h + \brief A mathematical parser +*/ + +#include +#include +#include +#include + +#include "ttmath.h" +#include "ttmathobjects.h" +#include "ttmathmisc.h" + + + +namespace ttmath +{ + +/*! + \brief Mathematical parser + + let x will be an input string meaning an expression for converting: + + x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... + where: + an operator can be: + ^ (pow) (the heighest priority) + + * (mul) (or multiplication without an operator -- short mul) + / (div) (* and / have the same priority) + + + (add) + - (sub) (+ and - have the same priority) + + < (lower than) + > (greater than) + <= (lower or equal than) + >= (greater or equal than) + == (equal) + != (not equal) (all above logical operators have the same priority) + + && (logical and) + + || (logical or) (the lowest priority) + + short mul: + if the second Value (Var below) is either a variable or function there might not be + an operator between them, e.g. + "[+|-]Value Var" is treated as "[+|-]Value * Var" and the multiplication + has the same priority as a normal multiplication: + 4x = 4 * x + 2^3m = (2^3)* m + 6h^3 = 6 * (h^3) + 2sin(pi) = 2 * sin(pi) + etc. + + Value can be: + constant e.g. 100, can be preceded by operators for changing the base (radix): [#|&] + # - hex + & - bin + sample: #10 = 16 + &10 = 2 + variable e.g. pi + another expression between brackets e.g (x) + function e.g. sin(x) + + for example a correct input string can be: + "1" + "2.1234" + "2,1234" (they are the same, by default we can either use a comma or a dot) + "1 + 2" + "(1 + 2) * 3" + "pi" + "sin(pi)" + "(1+2)*(2+3)" + "log(2;1234)" there's a semicolon here (not a comma), we use it in functions + for separating parameters + "1 < 2" (the result will be: 1) + "4 < 3" (the result will be: 0) + "2+x" (of course if the variable 'x' is defined) + "4x+10" + "#20+10" = 32 + 10 = 42 + "10 ^ -&101" = 10 ^ -5 = 0.00001 + "8 * -&10" = 8 * -2 = -16 + etc. + + we can also use a semicolon for separating any 'x' input strings + for example: + "1+2;4+5" + the result will be on the stack as follows: + "3" + "9" +*/ +template +class Parser +{ +private: + +/*! + there are 5 mathematical operators as follows (with their standard priorities): + add (+) + sub (-) + mul (*) + div (/) + pow (^) + and 'shortmul' used when there is no any operators between + a first parameter and a variable or function + (the 'shortmul' has the same priority as the normal multiplication ) +*/ + class MatOperator + { + public: + + enum Type + { + none,add,sub,mul,div,pow,lt,gt,let,get,eq,neq,lor,land,shortmul + }; + + enum Assoc + { + right, // right-associative + non_right // associative or left-associative + }; + + Type GetType() const { return type; } + int GetPriority() const { return priority; } + Assoc GetAssoc() const { return assoc; } + + void SetType(Type t) + { + type = t; + assoc = non_right; + + switch( type ) + { + case lor: + priority = 4; + break; + + case land: + priority = 5; + break; + + case eq: + case neq: + case lt: + case gt: + case let: + case get: + priority = 7; + break; + + case add: + case sub: + priority = 10; + break; + + case mul: + case shortmul: + case div: + priority = 12; + break; + + case pow: + priority = 14; + assoc = right; + break; + + default: + Error( err_internal_error ); + break; + } + } + + MatOperator(): type(none), priority(0), assoc(non_right) + { + } + + private: + + Type type; + int priority; + Assoc assoc; + }; // end of MatOperator class + + + +public: + + + + /*! + Objects of type 'Item' we are keeping on our stack + */ + struct Item + { + enum Type + { + none, numerical_value, mat_operator, first_bracket, + last_bracket, variable, semicolon + }; + + // The kind of type which we're keeping + Type type; + + // if type == numerical_value + ValueType value; + + // if type == mat_operator + MatOperator moperator; + + /* + if type == first_bracket + + if 'function' is set to true it means that the first recognized bracket + was the bracket from function in other words we must call a function when + we'll find the 'last' bracket + */ + bool function; + + // if function is true + std::string function_name; + + /* + the sign of value + + it can be for type==numerical_value or type==first_bracket + when it's true it means e.g. that value is equal -value + */ + bool sign; + + Item(): type(none), function(false), sign(false) + { + } + + }; // end of Item struct + + +/*! + stack on which we're keeping the Items + + at the end of parsing we'll have the result on its + the result don't have to be one value, it can be a list + of values separated by the 'semicolon item' +*/ +std::vector stack; + + +private: + + +/*! + size of the stack when we're starting parsing of the string + + if it's to small while parsing the stack will be automatically resized +*/ +const int default_stack_size; + + + +/*! + index of an object in our stack + it's pointing on the place behind the last element + for example at the beginning of parsing its value is zero +*/ +unsigned int stack_index; + + +/*! + code of the last error +*/ +ErrorCode error; + + +/*! + pointer to the currently reading char + it's either char* or wchar_t* + + when an error has occured it may be used to count the index of the wrong character +*/ +const char * pstring; + + +/*! + the base (radix) of the mathematic system (for example it may be '10') +*/ +int base; + + +/*! + the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot + 0 - deg + 1 - rad (default) + 2 - grad +*/ +int deg_rad_grad; + + + +/*! + a pointer to an object which tell us whether we should stop calculating or not +*/ +const volatile StopCalculating * pstop_calculating; + + + +/*! + a pointer to the user-defined variables' table +*/ +const Objects * puser_variables; + +/*! + a pointer to the user-defined functions' table +*/ +const Objects * puser_functions; + + +typedef std::map FunctionLocalVariables; + +/*! + a pointer to the local variables of a function +*/ +const FunctionLocalVariables * pfunction_local_variables; + + +/*! + a temporary set using during parsing user defined variables +*/ +std::set visited_variables; + + +/*! + a temporary set using during parsing user defined functions +*/ +std::set visited_functions; + + + + +/*! + pfunction is the type of pointer to a mathematic function + + these mathematic functions are private members of this class, + they are the wrappers for standard mathematics function + + 'pstack' is the pointer to the first argument on our stack + 'amount_of_arg' tell us how many argument there are in our stack + 'result' is the reference for result of function +*/ +typedef void (Parser::*pfunction)(int pstack, int amount_of_arg, ValueType & result); + + +/*! + pfunction is the type of pointer to a method which returns value of variable +*/ +typedef void (ValueType::*pfunction_var)(); + + +/*! + table of mathematic functions + + this map consists of: + std::string - function's name + pfunction - pointer to specific function +*/ +typedef std::map FunctionsTable; +FunctionsTable functions_table; + + +/*! + table of mathematic operators + + this map consists of: + std::string - operators's name + MatOperator::Type - type of the operator +*/ +typedef std::map OperatorsTable; +OperatorsTable operators_table; + + +/*! + table of mathematic variables + + this map consists of: + std::string - variable's name + pfunction_var - pointer to specific function which returns value of variable +*/ +typedef std::map VariablesTable; +VariablesTable variables_table; + + +/*! + some coefficients used when calculating the gamma (or factorial) function +*/ +CGamma cgamma; + + +/*! + temporary object for a whole string when Parse(std::wstring) is used +*/ +std::string wide_to_ansi; + + +/*! + group character (used when parsing) + default zero (not used) +*/ +int group; + + +/*! + characters used as a comma + default: '.' and ',' + comma2 can be zero (it means it is not used) +*/ +int comma, comma2; + + +/*! + an additional character used as a separator between function parameters + (semicolon is used always) +*/ +int param_sep; + + +/*! + true if something was calculated (at least one mathematical operator was used or a function or a variable) +*/ +bool calculated; + + + +/*! + we're using this method for reporting an error +*/ +static void Error(ErrorCode code) +{ + throw code; +} + + +/*! + this method skips the white character from the string + + it's moving the 'pstring' to the first no-white character +*/ +void SkipWhiteCharacters() +{ + while( (*pstring==' ' ) || (*pstring=='\t') ) + ++pstring; +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_CheckStopCondition(bool variable, const std::string & name) +{ + if( variable ) + { + if( visited_variables.find(name) != visited_variables.end() ) + Error( err_variable_loop ); + } + else + { + if( visited_functions.find(name) != visited_functions.end() ) + Error( err_functions_loop ); + } +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_AddName(bool variable, const std::string & name) +{ + if( variable ) + visited_variables.insert( name ); + else + visited_functions.insert( name ); +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_DeleteName(bool variable, const std::string & name) +{ + if( variable ) + visited_variables.erase( name ); + else + visited_functions.erase( name ); +} + + +/*! + this method returns the value of a variable or function + by creating a new instance of the mathematical parser + and making the standard parsing algorithm on the given string + + this method is used only during parsing user defined variables or functions + + (there can be a recurrence here therefore we're using 'visited_variables' + and 'visited_functions' sets to make a stop condition) +*/ +ValueType RecurrenceParsingVariablesOrFunction(bool variable, const std::string & name, const char * new_string, + FunctionLocalVariables * local_variables = 0) +{ + RecurrenceParsingVariablesOrFunction_CheckStopCondition(variable, name); + RecurrenceParsingVariablesOrFunction_AddName(variable, name); + + Parser NewParser(*this); + ErrorCode err; + + NewParser.pfunction_local_variables = local_variables; + + try + { + err = NewParser.Parse(new_string); + } + catch(...) + { + RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); + + throw; + } + + RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); + + if( err != err_ok ) + Error( err ); + + if( NewParser.stack.size() != 1 ) + Error( err_must_be_only_one_value ); + + if( NewParser.stack[0].type != Item::numerical_value ) + // I think there shouldn't be this error here + Error( err_incorrect_value ); + +return NewParser.stack[0].value; +} + + +public: + + +/*! + this method returns the user-defined value of a variable +*/ +bool GetValueOfUserDefinedVariable(const std::string & variable_name,ValueType & result) +{ + if( !puser_variables ) + return false; + + const char * string_value; + + if( puser_variables->GetValue(variable_name, &string_value) != err_ok ) + return false; + + result = RecurrenceParsingVariablesOrFunction(true, variable_name, string_value); + calculated = true; + +return true; +} + + +/*! + this method returns the value of a local variable of a function +*/ +bool GetValueOfFunctionLocalVariable(const std::string & variable_name, ValueType & result) +{ + if( !pfunction_local_variables ) + return false; + + typename FunctionLocalVariables::const_iterator i = pfunction_local_variables->find(variable_name); + + if( i == pfunction_local_variables->end() ) + return false; + + result = i->second; + +return true; +} + + +/*! + this method returns the value of a variable from variables' table + + we make an object of type ValueType then call a method which + sets the correct value in it and finally we'll return the object +*/ +ValueType GetValueOfVariable(const std::string & variable_name) +{ +ValueType result; + + if( GetValueOfFunctionLocalVariable(variable_name, result) ) + return result; + + if( GetValueOfUserDefinedVariable(variable_name, result) ) + return result; + + + typename std::map::iterator i = + variables_table.find(variable_name); + + if( i == variables_table.end() ) + Error( err_unknown_variable ); + + (result.*(i->second))(); + calculated = true; + +return result; +} + + +private: + +/*! + wrappers for mathematic functions + + 'sindex' is pointing on the first argument on our stack + (the second argument has 'sindex+2' + because 'sindex+1' is guaranted for the 'semicolon' operator) + the third artument has of course 'sindex+4' etc. + + 'result' will be the result of the function + + (we're using exceptions here for example when function gets an improper argument) +*/ + + +/*! + used by: sin,cos,tan,cot +*/ +ValueType ConvertAngleToRad(const ValueType & input) +{ + if( deg_rad_grad == 1 ) // rad + return input; + + ValueType result; + ErrorCode err; + + if( deg_rad_grad == 0 ) // deg + result = ttmath::DegToRad(input, &err); + else // grad + result = ttmath::GradToRad(input, &err); + + if( err != err_ok ) + Error( err ); + +return result; +} + + +/*! + used by: asin,acos,atan,acot +*/ +ValueType ConvertRadToAngle(const ValueType & input) +{ + if( deg_rad_grad == 1 ) // rad + return input; + + ValueType result; + ErrorCode err; + + if( deg_rad_grad == 0 ) // deg + result = ttmath::RadToDeg(input, &err); + else // grad + result = ttmath::RadToGrad(input, &err); + + if( err != err_ok ) + Error( err ); + +return result; +} + + +void Gamma(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + + result = ttmath::Gamma(stack[sindex].value, cgamma, &err, pstop_calculating); + + if(err != err_ok) + Error( err ); +} + + +/*! + factorial + result = 1 * 2 * 3 * 4 * .... * x +*/ +void Factorial(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + + result = ttmath::Factorial(stack[sindex].value, cgamma, &err, pstop_calculating); + + if(err != err_ok) + Error( err ); +} + + +void Abs(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::Abs(stack[sindex].value); +} + +void Sin(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Sin( ConvertAngleToRad(stack[sindex].value), &err ); + + if(err != err_ok) + Error( err ); +} + +void Cos(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Cos( ConvertAngleToRad(stack[sindex].value), &err ); + + if(err != err_ok) + Error( err ); +} + +void Tan(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Tan(ConvertAngleToRad(stack[sindex].value), &err); + + if(err != err_ok) + Error( err ); +} + +void Cot(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Cot(ConvertAngleToRad(stack[sindex].value), &err); + + if(err != err_ok) + Error( err ); +} + +void Int(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::SkipFraction(stack[sindex].value); +} + + +void Round(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = stack[sindex].value; + + if( result.Round() ) + Error( err_overflow ); +} + + +void Ln(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Ln(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); +} + +void Log(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 2 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Log(stack[sindex].value, stack[sindex+2].value, &err); + + if(err != err_ok) + Error( err ); +} + +void Exp(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Exp(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); +} + + +void Max(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args == 0 ) + { + result.SetMax(); + + return; + } + + result = stack[sindex].value; + + for(int i=1 ; i stack[sindex + i*2].value ) + result = stack[sindex + i*2].value; + } +} + + +void ASin(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + ValueType temp = ttmath::ASin(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); + + result = ConvertRadToAngle(temp); +} + + +void ACos(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + ValueType temp = ttmath::ACos(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); + + result = ConvertRadToAngle(temp); +} + + +void ATan(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ConvertRadToAngle(ttmath::ATan(stack[sindex].value)); +} + + +void ACot(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ConvertRadToAngle(ttmath::ACot(stack[sindex].value)); +} + + +void Sgn(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::Sgn(stack[sindex].value); +} + + +void Mod(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 2 ) + Error( err_improper_amount_of_arguments ); + + if( stack[sindex+2].value.IsZero() ) + Error( err_improper_argument ); + + result = stack[sindex].value; + uint c = result.Mod(stack[sindex+2].value); + + if( c ) + Error( err_overflow ); +} + + +void If(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 3 ) + Error( err_improper_amount_of_arguments ); + + + if( !stack[sindex].value.IsZero() ) + result = stack[sindex+2].value; + else + result = stack[sindex+4].value; +} + + +void Or(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args < 2 ) + Error( err_improper_amount_of_arguments ); + + for(int i=0 ; iGetValueAndParam(function_name, &string_value, ¶m) != err_ok ) + return false; + + if( param != amount_of_args ) + Error( err_improper_amount_of_arguments ); + + + FunctionLocalVariables local_variables; + + if( amount_of_args > 0 ) + { + char buffer[30]; + + // x = x1 + buffer[0] = 'x'; + buffer[1] = 0; + local_variables.insert( std::make_pair(buffer, stack[sindex].value) ); + + for(int i=0 ; i*(i->second))(sindex, amount_of_args, stack[sindex-1].value); + calculated = true; +} + + + + + +/*! + inserting a function to the functions' table + + function_name - name of the function + pf - pointer to the function (to the wrapper) +*/ +void InsertFunctionToTable(const char * function_name, pfunction pf) +{ + std::string str; + Misc::AssignString(str, function_name); + + functions_table.insert( std::make_pair(str, pf) ); +} + + + +/*! + inserting a function to the variables' table + (this function returns value of variable) + + variable_name - name of the function + pf - pointer to the function +*/ +void InsertVariableToTable(const char * variable_name, pfunction_var pf) +{ + std::string str; + Misc::AssignString(str, variable_name); + + variables_table.insert( std::make_pair(str, pf) ); +} + + +/*! + this method creates the table of functions +*/ +void CreateFunctionsTable() +{ + InsertFunctionToTable("gamma", &Parser::Gamma); + InsertFunctionToTable("factorial", &Parser::Factorial); + InsertFunctionToTable("abs", &Parser::Abs); + InsertFunctionToTable("sin", &Parser::Sin); + InsertFunctionToTable("cos", &Parser::Cos); + InsertFunctionToTable("tan", &Parser::Tan); + InsertFunctionToTable("tg", &Parser::Tan); + InsertFunctionToTable("cot", &Parser::Cot); + InsertFunctionToTable("ctg", &Parser::Cot); + InsertFunctionToTable("int", &Parser::Int); + InsertFunctionToTable("round", &Parser::Round); + InsertFunctionToTable("ln", &Parser::Ln); + InsertFunctionToTable("log", &Parser::Log); + InsertFunctionToTable("exp", &Parser::Exp); + InsertFunctionToTable("max", &Parser::Max); + InsertFunctionToTable("min", &Parser::Min); + InsertFunctionToTable("asin", &Parser::ASin); + InsertFunctionToTable("acos", &Parser::ACos); + InsertFunctionToTable("atan", &Parser::ATan); + InsertFunctionToTable("atg", &Parser::ATan); + InsertFunctionToTable("acot", &Parser::ACot); + InsertFunctionToTable("actg", &Parser::ACot); + InsertFunctionToTable("sgn", &Parser::Sgn); + InsertFunctionToTable("mod", &Parser::Mod); + InsertFunctionToTable("if", &Parser::If); + InsertFunctionToTable("or", &Parser::Or); + InsertFunctionToTable("and", &Parser::And); + InsertFunctionToTable("not", &Parser::Not); + InsertFunctionToTable("degtorad", &Parser::DegToRad); + InsertFunctionToTable("radtodeg", &Parser::RadToDeg); + InsertFunctionToTable("degtodeg", &Parser::DegToDeg); + InsertFunctionToTable("gradtorad", &Parser::GradToRad); + InsertFunctionToTable("radtograd", &Parser::RadToGrad); + InsertFunctionToTable("degtograd", &Parser::DegToGrad); + InsertFunctionToTable("gradtodeg", &Parser::GradToDeg); + InsertFunctionToTable("ceil", &Parser::Ceil); + InsertFunctionToTable("floor", &Parser::Floor); + InsertFunctionToTable("sqrt", &Parser::Sqrt); + InsertFunctionToTable("sinh", &Parser::Sinh); + InsertFunctionToTable("cosh", &Parser::Cosh); + InsertFunctionToTable("tanh", &Parser::Tanh); + InsertFunctionToTable("tgh", &Parser::Tanh); + InsertFunctionToTable("coth", &Parser::Coth); + InsertFunctionToTable("ctgh", &Parser::Coth); + InsertFunctionToTable("root", &Parser::Root); + InsertFunctionToTable("asinh", &Parser::ASinh); + InsertFunctionToTable("acosh", &Parser::ACosh); + InsertFunctionToTable("atanh", &Parser::ATanh); + InsertFunctionToTable("atgh", &Parser::ATanh); + InsertFunctionToTable("acoth", &Parser::ACoth); + InsertFunctionToTable("actgh", &Parser::ACoth); + InsertFunctionToTable("bitand", &Parser::BitAnd); + InsertFunctionToTable("bitor", &Parser::BitOr); + InsertFunctionToTable("bitxor", &Parser::BitXor); + InsertFunctionToTable("band", &Parser::BitAnd); + InsertFunctionToTable("bor", &Parser::BitOr); + InsertFunctionToTable("bxor", &Parser::BitXor); + InsertFunctionToTable("sum", &Parser::Sum); + InsertFunctionToTable("avg", &Parser::Avg); + InsertFunctionToTable("frac", &Parser::Frac); +} + + +/*! + this method creates the table of variables +*/ +void CreateVariablesTable() +{ + InsertVariableToTable("pi", &ValueType::SetPi); + InsertVariableToTable("e", &ValueType::SetE); +} + + +/*! + converting from a big letter to a small one +*/ +int ToLowerCase(int c) +{ + if( c>='A' && c<='Z' ) + return c - 'A' + 'a'; + +return c; +} + + +/*! + this method read the name of a variable or a function + + 'result' will be the name of a variable or a function + function return 'false' if this name is the name of a variable + or function return 'true' if this name is the name of a function + + what should be returned is tested just by a '(' character that means if there's + a '(' character after a name that function returns 'true' +*/ +bool ReadName(std::string & result) +{ +int character; + + + result.erase(); + character = *pstring; + + /* + the first letter must be from range 'a' - 'z' or 'A' - 'Z' + */ + if( ! (( character>='a' && character<='z' ) || ( character>='A' && character<='Z' )) ) + Error( err_unknown_character ); + + + do + { + result += static_cast( character ); + character = * ++pstring; + } + while( (character>='a' && character<='z') || + (character>='A' && character<='Z') || + (character>='0' && character<='9') || + character=='_' ); + + + SkipWhiteCharacters(); + + + /* + if there's a character '(' that means this name is a name of a function + */ + if( *pstring == '(' ) + { + ++pstring; + return true; + } + + +return false; +} + + +/*! + we're checking whether the first character is '-' or '+' + if it is we'll return 'true' and if it is equally '-' we'll set the 'sign' member of 'result' +*/ +bool TestSign(Item & result) +{ + SkipWhiteCharacters(); + result.sign = false; + + if( *pstring == '-' || *pstring == '+' ) + { + if( *pstring == '-' ) + result.sign = true; + + ++pstring; + + return true; + } + +return false; +} + + +/*! + we're reading the name of a variable or a function + if is there a function we'll return 'true' +*/ +bool ReadVariableOrFunction(Item & result) +{ +std::string name; +bool is_it_name_of_function = ReadName(name); + + if( is_it_name_of_function ) + { + /* + we've read the name of a function + */ + result.function_name = name; + result.type = Item::first_bracket; + result.function = true; + } + else + { + /* + we've read the name of a variable and we're getting its value now + */ + result.value = GetValueOfVariable( name ); + } + +return is_it_name_of_function; +} + + + + +/*! + we're reading a numerical value directly from the string +*/ +void ReadValue(Item & result, int reading_base) +{ +const char * new_stack_pointer; +bool value_read; +Conv conv; + + conv.base = reading_base; + conv.comma = comma; + conv.comma2 = comma2; + conv.group = group; + + uint carry = result.value.FromString(pstring, conv, &new_stack_pointer, &value_read); + pstring = new_stack_pointer; + + if( carry ) + Error( err_overflow ); + + if( !value_read ) + Error( err_unknown_character ); +} + + +/*! + this method returns true if 'character' is a proper first digit for the value (or a comma -- can be first too) +*/ +bool ValueStarts(int character, int base) +{ + if( character == comma ) + return true; + + if( comma2!=0 && character==comma2 ) + return true; + + if( Misc::CharToDigit(character, base) != -1 ) + return true; + +return false; +} + + +/*! + we're reading the item + + return values: + 0 - all ok, the item is successfully read + 1 - the end of the string (the item is not read) + 2 - the final bracket ')' +*/ +int ReadValueVariableOrFunction(Item & result) +{ +bool it_was_sign = false; +int character; + + + if( TestSign(result) ) + // 'result.sign' was set as well + it_was_sign = true; + + SkipWhiteCharacters(); + character = ToLowerCase( *pstring ); + + + if( character == 0 ) + { + if( it_was_sign ) + // at the end of the string a character like '-' or '+' has left + Error( err_unexpected_end ); + + // there's the end of the string here + return 1; + } + else + if( character == '(' ) + { + // we've got a normal bracket (not a function) + result.type = Item::first_bracket; + result.function = false; + ++pstring; + + return 0; + } + else + if( character == ')' ) + { + // we've got a final bracket + // (in this place we can find a final bracket only when there are empty brackets + // without any values inside or with a sign '-' or '+' inside) + + if( it_was_sign ) + Error( err_unexpected_final_bracket ); + + result.type = Item::last_bracket; + + // we don't increment 'pstring', this final bracket will be read next by the + // 'ReadOperatorAndCheckFinalBracket(...)' method + + return 2; + } + else + if( character == '#' ) + { + ++pstring; + SkipWhiteCharacters(); + + // after '#' character we do not allow '-' or '+' (can be white characters) + if( ValueStarts(*pstring, 16) ) + ReadValue( result, 16 ); + else + Error( err_unknown_character ); + } + else + if( character == '&' ) + { + ++pstring; + SkipWhiteCharacters(); + + // after '&' character we do not allow '-' or '+' (can be white characters) + if( ValueStarts(*pstring, 2) ) + ReadValue( result, 2 ); + else + Error( err_unknown_character ); + } + else + if( ValueStarts(character, base) ) + { + ReadValue( result, base ); + } + else + if( character>='a' && character<='z' ) + { + if( ReadVariableOrFunction(result) ) + // we've read the name of a function + return 0; + } + else + Error( err_unknown_character ); + + + + /* + we've got a value in the 'result' + this value is from a variable or directly from the string + */ + result.type = Item::numerical_value; + + if( result.sign ) + { + result.value.ChangeSign(); + result.sign = false; + } + + +return 0; +} + + +void InsertOperatorToTable(const char * name, typename MatOperator::Type type) +{ + operators_table.insert( std::make_pair(std::string(name), type) ); +} + + +/*! + this method creates the table of operators +*/ +void CreateMathematicalOperatorsTable() +{ + InsertOperatorToTable("||", MatOperator::lor); + InsertOperatorToTable("&&", MatOperator::land); + InsertOperatorToTable("!=", MatOperator::neq); + InsertOperatorToTable("==", MatOperator::eq); + InsertOperatorToTable(">=", MatOperator::get); + InsertOperatorToTable("<=", MatOperator::let); + InsertOperatorToTable(">", MatOperator::gt); + InsertOperatorToTable("<", MatOperator::lt); + InsertOperatorToTable("-", MatOperator::sub); + InsertOperatorToTable("+", MatOperator::add); + InsertOperatorToTable("/", MatOperator::div); + InsertOperatorToTable("*", MatOperator::mul); + InsertOperatorToTable("^", MatOperator::pow); +} + + +/*! + returns true if 'str2' is the substring of str1 + + e.g. + true when str1="test" and str2="te" +*/ +bool IsSubstring(const std::string & str1, const std::string & str2) +{ + if( str2.length() > str1.length() ) + return false; + + for(typename std::string::size_type i=0 ; ifirst, oper) ) + { + oper.erase( --oper.end() ); // we've got mininum one element + + if( iter_old != operators_table.end() && iter_old->first == oper ) + { + result.type = Item::mat_operator; + result.moperator.SetType( iter_old->second ); + break; + } + + Error( err_unknown_operator ); + } + + iter_old = iter_new; + } +} + + +/*! + this method makes a calculation for the percentage operator + e.g. + 1000-50% = 1000-(1000*0,5) = 500 +*/ +void OperatorPercentage() +{ + if( stack_index < 3 || + stack[stack_index-1].type != Item::numerical_value || + stack[stack_index-2].type != Item::mat_operator || + stack[stack_index-3].type != Item::numerical_value ) + Error(err_percent_from); + + ++pstring; + SkipWhiteCharacters(); + + uint c = 0; + c += stack[stack_index-1].value.Div(100); + c += stack[stack_index-1].value.Mul(stack[stack_index-3].value); + + if( c ) + Error(err_overflow); +} + + +/*! + this method reads a mathematic operators + or the final bracket or the semicolon operator + + return values: + 0 - ok + 1 - the string is finished +*/ +int ReadOperator(Item & result) +{ + SkipWhiteCharacters(); + + if( *pstring == '%' ) + OperatorPercentage(); + + + if( *pstring == 0 ) + return 1; + else + if( *pstring == ')' ) + { + result.type = Item::last_bracket; + ++pstring; + } + else + if( *pstring == ';' || (param_sep!=0 && *pstring==param_sep) ) + { + result.type = Item::semicolon; + ++pstring; + } + else + if( (*pstring>='a' && *pstring<='z') || (*pstring>='A' && *pstring<='Z') ) + { + // short mul (without any operators) + + result.type = Item::mat_operator; + result.moperator.SetType( MatOperator::shortmul ); + } + else + ReadMathematicalOperator(result); + +return 0; +} + + + +/*! + this method is making the standard mathematic operation like '-' '+' '*' '/' and '^' + + the operation is made between 'value1' and 'value2' + the result of this operation is stored in the 'value1' +*/ +void MakeStandardMathematicOperation(ValueType & value1, typename MatOperator::Type mat_operator, + const ValueType & value2) +{ +uint res; + + calculated = true; + + switch( mat_operator ) + { + case MatOperator::land: + (!value1.IsZero() && !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::lor: + (!value1.IsZero() || !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::eq: + (value1 == value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::neq: + (value1 != value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::lt: + (value1 < value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::gt: + (value1 > value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::let: + (value1 <= value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::get: + (value1 >= value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::sub: + if( value1.Sub(value2) ) Error( err_overflow ); + break; + + case MatOperator::add: + if( value1.Add(value2) ) Error( err_overflow ); + break; + + case MatOperator::mul: + case MatOperator::shortmul: + if( value1.Mul(value2) ) Error( err_overflow ); + break; + + case MatOperator::div: + if( value2.IsZero() ) Error( err_division_by_zero ); + if( value1.Div(value2) ) Error( err_overflow ); + break; + + case MatOperator::pow: + res = value1.Pow( value2 ); + + if( res == 1 ) Error( err_overflow ); + else + if( res == 2 ) Error( err_improper_argument ); + + break; + + default: + /* + on the stack left an unknown operator but we had to recognize its before + that means there's an error in our algorithm + */ + Error( err_internal_error ); + } +} + + + + +/*! + this method is trying to roll the stack up with the operator's priority + + for example if there are: + "1 - 2 +" + we can subtract "1-2" and the result store on the place where is '1' and copy the last + operator '+', that means there'll be '-1+' on our stack + + but if there are: + "1 - 2 *" + we can't roll the stack up because the operator '*' has greater priority than '-' +*/ +void TryRollingUpStackWithOperatorPriority() +{ + while( stack_index>=4 && + stack[stack_index-4].type == Item::numerical_value && + stack[stack_index-3].type == Item::mat_operator && + stack[stack_index-2].type == Item::numerical_value && + stack[stack_index-1].type == Item::mat_operator && + ( + ( + // the first operator has greater priority + stack[stack_index-3].moperator.GetPriority() > stack[stack_index-1].moperator.GetPriority() + ) || + ( + // or both operators have the same priority and the first operator is not right associative + stack[stack_index-3].moperator.GetPriority() == stack[stack_index-1].moperator.GetPriority() && + stack[stack_index-3].moperator.GetAssoc() == MatOperator::non_right + ) + ) + ) + { + MakeStandardMathematicOperation(stack[stack_index-4].value, + stack[stack_index-3].moperator.GetType(), + stack[stack_index-2].value); + + + /* + copying the last operator and setting the stack pointer to the correct value + */ + stack[stack_index-3] = stack[stack_index-1]; + stack_index -= 2; + } +} + + +/*! + this method is trying to roll the stack up without testing any operators + + for example if there are: + "1 - 2" + there'll be "-1" on our stack +*/ +void TryRollingUpStack() +{ + while( stack_index >= 3 && + stack[stack_index-3].type == Item::numerical_value && + stack[stack_index-2].type == Item::mat_operator && + stack[stack_index-1].type == Item::numerical_value ) + { + MakeStandardMathematicOperation( stack[stack_index-3].value, + stack[stack_index-2].moperator.GetType(), + stack[stack_index-1].value ); + + stack_index -= 2; + } +} + + +/*! + this method is reading a value or a variable or a function + (the normal first bracket as well) and push it into the stack +*/ +int ReadValueVariableOrFunctionAndPushItIntoStack(Item & temp) +{ +int code = ReadValueVariableOrFunction( temp ); + + if( code == 0 ) + { + if( stack_index < stack.size() ) + stack[stack_index] = temp; + else + stack.push_back( temp ); + + ++stack_index; + } + + if( code == 2 ) + // there was a final bracket, we didn't push it into the stack + // (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next) + code = 0; + + +return code; +} + + + +/*! + this method calculate how many parameters there are on the stack + and the index of the first parameter + + if there aren't any parameters on the stack this method returns + 'size' equals zero and 'index' pointing after the first bracket + (on non-existend element) +*/ +void HowManyParameters(int & size, int & index) +{ + size = 0; + index = stack_index; + + if( index == 0 ) + // we haven't put a first bracket on the stack + Error( err_unexpected_final_bracket ); + + + if( stack[index-1].type == Item::first_bracket ) + // empty brackets + return; + + for( --index ; index>=1 ; index-=2 ) + { + if( stack[index].type != Item::numerical_value ) + { + /* + this element must be 'numerical_value', if not that means + there's an error in our algorithm + */ + Error( err_internal_error ); + } + + ++size; + + if( stack[index-1].type != Item::semicolon ) + break; + } + + if( index<1 || stack[index-1].type != Item::first_bracket ) + { + /* + we haven't put a first bracket on the stack + */ + Error( err_unexpected_final_bracket ); + } +} + + +/*! + this method is being called when the final bracket ')' is being found + + this method's rolling the stack up, counting how many parameters there are + on the stack and if there was a function it's calling the function +*/ +void RollingUpFinalBracket() +{ +int amount_of_parameters; +int index; + + + if( stack_index<1 || + (stack[stack_index-1].type != Item::numerical_value && + stack[stack_index-1].type != Item::first_bracket) + ) + Error( err_unexpected_final_bracket ); + + + TryRollingUpStack(); + HowManyParameters(amount_of_parameters, index); + + // 'index' will be greater than zero + // 'amount_of_parameters' can be zero + + + if( amount_of_parameters==0 && !stack[index-1].function ) + Error( err_unexpected_final_bracket ); + + + bool was_sign = stack[index-1].sign; + + + if( stack[index-1].function ) + { + // the result of a function will be on 'stack[index-1]' + // and then at the end we'll set the correct type (numerical value) of this element + CallFunction(stack[index-1].function_name, amount_of_parameters, index); + } + else + { + /* + there was a normal bracket (not a funcion) + */ + if( amount_of_parameters != 1 ) + Error( err_unexpected_semicolon_operator ); + + + /* + in the place where is the bracket we put the result + */ + stack[index-1] = stack[index]; + } + + + /* + if there was a '-' character before the first bracket + we change the sign of the expression + */ + stack[index-1].sign = false; + + if( was_sign ) + stack[index-1].value.ChangeSign(); + + stack[index-1].type = Item::numerical_value; + + + /* + the pointer of the stack will be pointing on the next (non-existing now) element + */ + stack_index = index; +} + + +/*! + this method is putting the operator on the stack +*/ + +void PushOperatorIntoStack(Item & temp) +{ + if( stack_index < stack.size() ) + stack[stack_index] = temp; + else + stack.push_back( temp ); + + ++stack_index; +} + + + +/*! + this method is reading a operator and if it's a final bracket + it's calling RollingUpFinalBracket() and reading a operator again +*/ +int ReadOperatorAndCheckFinalBracket(Item & temp) +{ + do + { + if( ReadOperator(temp) == 1 ) + { + /* + the string is finished + */ + return 1; + } + + if( temp.type == Item::last_bracket ) + RollingUpFinalBracket(); + + } + while( temp.type == Item::last_bracket ); + +return 0; +} + + +/*! + we check wheter there are only numerical value's or 'semicolon' operators on the stack +*/ +void CheckIntegrityOfStack() +{ + for(unsigned int i=0 ; iWasStopSignal() ) + Error( err_interrupt ); + + result_code = ReadValueVariableOrFunctionAndPushItIntoStack( item ); + + if( result_code == 0 ) + { + if( item.type == Item::first_bracket ) + continue; + + result_code = ReadOperatorAndCheckFinalBracket( item ); + } + + + if( result_code==1 || item.type==Item::semicolon ) + { + /* + the string is finished or the 'semicolon' operator has appeared + */ + + if( stack_index == 0 ) + Error( err_nothing_has_read ); + + TryRollingUpStack(); + + if( result_code == 1 ) + { + CheckIntegrityOfStack(); + + return; + } + } + + + PushOperatorIntoStack( item ); + TryRollingUpStackWithOperatorPriority(); + } +} + +/*! + this method is called at the end of the parsing process + + on our stack we can have another value than 'numerical_values' for example + when someone use the operator ';' in the global scope or there was an error during + parsing and the parser hasn't finished its job + + if there was an error the stack is cleaned up now + otherwise we resize stack and leave on it only 'numerical_value' items +*/ +void NormalizeStack() +{ + if( error!=err_ok || stack_index==0 ) + { + stack.clear(); + return; + } + + + /* + 'stack_index' tell us how many elements there are on the stack, + we must resize the stack now because 'stack_index' is using only for parsing + and stack has more (or equal) elements than value of 'stack_index' + */ + stack.resize( stack_index ); + + for(uint i=stack_index-1 ; i!=uint(-1) ; --i) + { + if( stack[i].type != Item::numerical_value ) + stack.erase( stack.begin() + i ); + } +} + + +public: + + +/*! + the default constructor +*/ +Parser(): default_stack_size(100) +{ + pstop_calculating = 0; + puser_variables = 0; + puser_functions = 0; + pfunction_local_variables = 0; + base = 10; + deg_rad_grad = 1; + error = err_ok; + group = 0; + comma = '.'; + comma2 = ','; + param_sep = 0; + + CreateFunctionsTable(); + CreateVariablesTable(); + CreateMathematicalOperatorsTable(); +} + + +/*! + the assignment operator +*/ +Parser & operator=(const Parser & p) +{ + pstop_calculating = p.pstop_calculating; + puser_variables = p.puser_variables; + puser_functions = p.puser_functions; + pfunction_local_variables = 0; + base = p.base; + deg_rad_grad = p.deg_rad_grad; + error = p.error; + group = p.group; + comma = p.comma; + comma2 = p.comma2; + param_sep = p.param_sep; + + /* + we don't have to call 'CreateFunctionsTable()' etc. + we can only copy these tables + */ + functions_table = p.functions_table; + variables_table = p.variables_table; + operators_table = p.operators_table; + + visited_variables = p.visited_variables; + visited_functions = p.visited_functions; + +return *this; +} + + +/*! + the copying constructor +*/ +Parser(const Parser & p): default_stack_size(p.default_stack_size) +{ + operator=(p); +} + + +/*! + the new base of mathematic system + default is 10 +*/ +void SetBase(int b) +{ + if( b>=2 && b<=16 ) + base = b; +} + + +/*! + the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot + 0 - deg + 1 - rad (default) + 2 - grad +*/ +void SetDegRadGrad(int angle) +{ + if( angle >= 0 || angle <= 2 ) + deg_rad_grad = angle; +} + +/*! + this method sets a pointer to the object which tell us whether we should stop + calculations +*/ +void SetStopObject(const volatile StopCalculating * ps) +{ + pstop_calculating = ps; +} + + +/*! + this method sets the new table of user-defined variables + if you don't want any other variables just put zero value into the 'puser_variables' variable + + (you can have only one table at the same time) +*/ +void SetVariables(const Objects * pv) +{ + puser_variables = pv; +} + + +/*! + this method sets the new table of user-defined functions + if you don't want any other functions just put zero value into the 'puser_functions' variable + + (you can have only one table at the same time) +*/ +void SetFunctions(const Objects * pf) +{ + puser_functions = pf; +} + + +/*! + setting the group character + default zero (not used) +*/ +void SetGroup(int g) +{ + group = g; +} + + +/*! + setting the main comma operator and the additional comma operator + the additional operator can be zero (which means it is not used) + default are: '.' and ',' +*/ +void SetComma(int c, int c2 = 0) +{ + comma = c; + comma2 = c2; +} + + +/*! + setting an additional character which is used as a parameters separator + the main parameters separator is a semicolon (is used always) + + this character is used also as a global separator +*/ +void SetParamSep(int s) +{ + param_sep = s; +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const char * str) +{ + stack_index = 0; + pstring = str; + error = err_ok; + calculated = false; + + stack.resize( default_stack_size ); + + try + { + Parse(); + } + catch(ErrorCode c) + { + error = c; + calculated = false; + } + + NormalizeStack(); + +return error; +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const std::string & str) +{ + return Parse(str.c_str()); +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const wchar_t * str) +{ + Misc::AssignString(wide_to_ansi, str); + +return Parse(wide_to_ansi.c_str()); +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const std::wstring & str) +{ + return Parse(str.c_str()); +} + + +/*! + this method returns true is something was calculated + (at least one mathematical operator was used or a function or variable) + e.g. true if the string to Parse() looked like this: + "1+1" + "2*3" + "sin(5)" + + if the string was e.g. "678" the result is false +*/ +bool Calculated() +{ + return calculated; +} + + +}; + + + +} // namespace + + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmaththreads.h b/src/libghost/ttmath/ttmath/ttmaththreads.h new file mode 100644 index 0000000..586227f --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmaththreads.h @@ -0,0 +1,250 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmaththreads +#define headerfilettmaththreads + +#include "ttmathtypes.h" + +#ifdef TTMATH_WIN32_THREADS +#include +#include +#endif + +#ifdef TTMATH_POSIX_THREADS +#include +#endif + + + +/*! + \file ttmaththreads.h + \brief Some objects used in multithreads environment +*/ + + +/* + this is a simple skeleton of a program in multithreads environment: + + #define TTMATH_MULTITHREADS + #include + + TTMATH_MULTITHREADS_HELPER + + int main() + { + [...] + } + + make sure that macro TTMATH_MULTITHREADS is defined and (somewhere in *.cpp file) + use TTMATH_MULTITHREADS_HELPER macro (outside of any classes/functions/namespaces scope) +*/ + + +namespace ttmath +{ + + +#ifdef TTMATH_WIN32_THREADS + + /* + we use win32 threads + */ + + + /*! + in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro + somewhere in *.cpp file + + (at the moment in win32 this macro does nothing) + */ + #define TTMATH_MULTITHREADS_HELPER + + + /*! + objects of this class are used to synchronize + */ + class ThreadLock + { + HANDLE mutex_handle; + + + void CreateName(char * buffer) const + { + #ifdef _MSC_VER + #pragma warning (disable : 4996) + // warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. + #endif + + sprintf(buffer, "TTMATH_LOCK_%ul", (unsigned long)GetCurrentProcessId()); + + #ifdef _MSC_VER + #pragma warning (default : 4996) + #endif + } + + + public: + + bool Lock() + { + char buffer[50]; + + CreateName(buffer); + mutex_handle = CreateMutexA(0, false, buffer); + + if( mutex_handle == 0 ) + return false; + + WaitForSingleObject(mutex_handle, INFINITE); + + return true; + } + + + ThreadLock() + { + mutex_handle = 0; + } + + + ~ThreadLock() + { + if( mutex_handle != 0 ) + { + ReleaseMutex(mutex_handle); + CloseHandle(mutex_handle); + } + } + }; + +#endif // #ifdef TTMATH_WIN32_THREADS + + + + + +#ifdef TTMATH_POSIX_THREADS + + /* + we use posix threads + */ + + + /*! + in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro + somewhere in *.cpp file + (this macro defines a pthread_mutex_t object used by TTMath library) + */ + #define TTMATH_MULTITHREADS_HELPER \ + namespace ttmath \ + { \ + pthread_mutex_t ttmath_mutex = PTHREAD_MUTEX_INITIALIZER; \ + } + + + /*! + ttmath_mutex will be defined by TTMATH_MULTITHREADS_HELPER macro + */ + extern pthread_mutex_t ttmath_mutex; + + + /*! + objects of this class are used to synchronize + */ + class ThreadLock + { + public: + + bool Lock() + { + if( pthread_mutex_lock(&ttmath_mutex) != 0 ) + return false; + + return true; + } + + + ~ThreadLock() + { + pthread_mutex_unlock(&ttmath_mutex); + } + }; + +#endif // #ifdef TTMATH_POSIX_THREADS + + + + +#if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + /*! + we don't use win32 and pthreads + */ + + /*! + */ + #define TTMATH_MULTITHREADS_HELPER + + + /*! + objects of this class are used to synchronize + actually we don't synchronize, the method Lock() returns always 'false' + */ + class ThreadLock + { + public: + + bool Lock() + { + return false; + } + }; + + +#endif // #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + + + + +} // namespace + +#endif + diff --git a/src/libghost/ttmath/ttmath/ttmathtypes.h b/src/libghost/ttmath/ttmath/ttmathtypes.h new file mode 100644 index 0000000..f3236ea --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathtypes.h @@ -0,0 +1,646 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + +#ifndef headerfilettmathtypes +#define headerfilettmathtypes + +/*! + \file ttmathtypes.h + \brief constants used in the library + + As our library is written in header files (templates) we cannot use + constants like 'const int' etc. because we should have some source files + *.cpp to define this variables. Only what we can have are constants + defined by #define preprocessor macros. + + All macros are preceded by TTMATH_ prefix +*/ + + +#include +#include +#include + +/*! + the version of the library + + TTMATH_PRERELEASE_VER is either zero or one + if zero that means this is the release version of the library +*/ +#define TTMATH_MAJOR_VER 0 +#define TTMATH_MINOR_VER 9 +#define TTMATH_REVISION_VER 1 +#define TTMATH_PRERELEASE_VER 0 + + +/*! + TTMATH_DEBUG + this macro enables further testing during writing your code + you don't have to define it in a release mode + + if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT + are set as well and these macros can throw an exception if a condition in it + is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT) + + TTMATH_RELEASE + if you are confident that your code is perfect you can define TTMATH_RELEASE + macro for example by using -D option in gcc + gcc -DTTMATH_RELEASE -o myprogram myprogram.cpp + or by defining this macro in your code before using any header files of this library + + if TTMATH_RELEASE is not set then TTMATH_DEBUG is set automatically +*/ +#ifndef TTMATH_RELEASE + #define TTMATH_DEBUG +#endif + + + +namespace ttmath +{ + +#if !defined _M_X64 && !defined __x86_64__ + + /*! + we're using a 32bit platform + */ + #define TTMATH_PLATFORM32 + +#else + + /*! + we're using a 64bit platform + */ + #define TTMATH_PLATFORM64 + +#endif + + + +/*! + another compilers than MS VC or GCC by default use no asm version (TTMATH_NOASM) +*/ +#if !defined _MSC_VER && !defined __GNUC__ + #define TTMATH_NOASM +#endif + + + +#ifdef TTMATH_PLATFORM32 + + /*! + on 32bit platforms one word (uint, sint) will be equal 32bits + */ + typedef unsigned int uint; + typedef signed int sint; + + /*! + this type is twice bigger than uint + (64bit on a 32bit platforms) + + although C++ Standard - ANSI ISO IEC 14882:2003 doesn't define such a type (long long) + but it is defined in C99 and in upcoming C++0x /3.9.1 (2)/ and many compilers support it + + this type is used in UInt::MulTwoWords and UInt::DivTwoWords when macro TTMATH_NOASM is defined + but only on a 32bit platform + */ + #ifdef TTMATH_NOASM + typedef unsigned long long int ulint; + #endif + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 32u + + /*! + the mask for the highest bit in the unsigned 32bit word (2^31) + */ + #define TTMATH_UINT_HIGHEST_BIT 2147483648u + + /*! + the max value of the unsigned 32bit word (2^32 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 4294967295u + + /*! + the number of words (32bit words on 32bit platform) + which are kept in built-in variables for a Big<> type + (these variables are defined in ttmathbig.h) + */ + #define TTMATH_BUILTIN_VARIABLES_SIZE 256u + + /*! + this macro returns the number of machine words + capable to hold min_bits bits + e.g. TTMATH_BITS(128) returns 4 + */ + #define TTMATH_BITS(min_bits) ((min_bits-1)/32 + 1) + +#else + + /*! + on 64bit platforms one word (uint, sint) will be equal 64bits + */ + #ifdef _MSC_VER + /* in VC 'long' type has 32 bits, __int64 is VC extension */ + typedef unsigned __int64 uint; + typedef signed __int64 sint; + #else + typedef unsigned long uint; + typedef signed long sint; + #endif + + /*! + on 64bit platform we do not define ulint + sizeof(long long) is 8 (64bit) but we need 128bit + + on 64 bit platform (when there is defined TTMATH_NOASM macro) + methods UInt::MulTwoWords and UInt::DivTwoWords are using other algorithms than those on 32 bit + */ + //typedef unsigned long long int ulint; + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 64ul + + /*! + the mask for the highest bit in the unsigned 64bit word (2^63) + */ + #define TTMATH_UINT_HIGHEST_BIT 9223372036854775808ul + + /*! + the max value of the unsigned 64bit word (2^64 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 18446744073709551615ul + + /*! + the number of words (64bit words on 64bit platforms) + which are kept in built-in variables for a Big<> type + (these variables are defined in ttmathbig.h) + */ + #define TTMATH_BUILTIN_VARIABLES_SIZE 128ul + + /*! + this macro returns the number of machine words + capable to hold min_bits bits + e.g. TTMATH_BITS(128) returns 2 + */ + #define TTMATH_BITS(min_bits) ((min_bits-1)/64 + 1) + +#endif +} + + +#if defined(TTMATH_MULTITHREADS) && !defined(TTMATH_MULTITHREADS_NOSYNC) + #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + #if defined(_WIN32) + #define TTMATH_WIN32_THREADS + #elif defined(unix) || defined(__unix__) || defined(__unix) + #define TTMATH_POSIX_THREADS + #endif + + #endif +#endif + + + +/*! + this variable defines how many iterations are performed + during some kind of calculating when we're making any long formulas + (for example Taylor series) + + it's used in ExpSurrounding0(...), LnSurrounding1(...), Sin0pi05(...), etc. + + note! there'll not be so many iterations, iterations are stopped when + there is no sense to continue calculating (for example when the result + still remains unchanged after adding next series and we know that the next + series are smaller than previous ones) +*/ +#define TTMATH_ARITHMETIC_MAX_LOOP 10000 + + + +/*! + this is a limit when calculating Karatsuba multiplication + if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE + the Karatsuba algorithm will use standard schoolbook multiplication +*/ +#ifdef TTMATH_DEBUG_LOG + // if TTMATH_DEBUG_LOG is defined then we should use the same size regardless of the compiler + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 +#else + #ifdef __GNUC__ + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 + #else + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5 + #endif +#endif + + +/*! + this is a special value used when calculating the Gamma(x) function + if x is greater than this value then the Gamma(x) will be calculated using + some kind of series + + don't use smaller values than about 100 +*/ +#define TTMATH_GAMMA_BOUNDARY 2000 + + + + + +namespace ttmath +{ + + /*! + lib type codes: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + enum LibTypeCode + { + asm_vc_32 = 0, + asm_gcc_32, + asm_vc_64, + asm_gcc_64, + no_asm_32, + no_asm_64 + }; + + + /*! + error codes + */ + enum ErrorCode + { + err_ok = 0, + err_nothing_has_read, + err_unknown_character, + err_unexpected_final_bracket, + err_stack_not_clear, + err_unknown_variable, + err_division_by_zero, + err_interrupt, + err_overflow, + err_unknown_function, + err_unknown_operator, + err_unexpected_semicolon_operator, + err_improper_amount_of_arguments, + err_improper_argument, + err_unexpected_end, + err_internal_error, + err_incorrect_name, + err_incorrect_value, + err_variable_exists, + err_variable_loop, + err_functions_loop, + err_must_be_only_one_value, + err_object_exists, + err_unknown_object, + err_still_calculating, + err_in_short_form_used_function, + err_percent_from + }; + + + /*! + this struct is used when converting to/from a string + /temporarily only in Big::ToString() and Big::FromString()/ + */ + struct Conv + { + /*! + base (radix) on which the value will be shown (or read) + default: 10 + */ + uint base; + + + /*! + used only in Big::ToString() + if true the value will be always shown in the scientific mode, e.g: 123e+30 + default: false + */ + bool scient; + + + /*! + used only in Big::ToString() + if scient is false then the value will be print in the scientific mode + only if the exponent is greater than scien_from + default: 15 + */ + sint scient_from; + + + /*! + if 'base_round' is true and 'base' is different from 2, 4, 8, or 16 + and the result value is not an integer then we make an additional rounding + (after converting the last digit from the result is skipped) + default: true + + e.g. + Conv c; + c.base_round = false; + Big<1, 1> a = "0.1"; // decimal input + std::cout << a.ToString(c) << std::endl; // the result is: 0.099999999 + */ + bool base_round; + + + /*! + used only in Big::ToString() + tells how many digits after comma are possible + default: -1 which means all digits are printed + + set it to zero if you want integer value only + + for example when the value is: + 12.345678 and 'round' is 4 + then the result will be + 12.3457 (the last digit was rounded) + */ + sint round; + + + /*! + if true that not mattered digits in the mantissa will be cut off + (zero characters at the end -- after the comma operator) + e.g. 1234,78000 will be: 1234,78 + default: true + */ + bool trim_zeroes; + + + /*! + the main comma operator (used when reading and writing) + default is a dot '.' + */ + uint comma; + + + /*! + additional comma operator (used only when reading) + if you don't want it just set it to zero + default is a comma ',' + + this allowes you to convert from a value: + 123.45 as well as from 123,45 + */ + uint comma2; + + + /*! + it sets the character which is used for grouping + if group=' ' then: 1234,56789 will be printed as: 1 234,567 89 + + if you don't want grouping just set it to zero (which is default) + */ + uint group; + + + /*! + */ + uint group_exp; // not implemented yet + + + + + Conv() + { + // default values + base = 10; + scient = false; + scient_from = 15; + base_round = true; + round = -1; + trim_zeroes = true; + comma = '.'; + comma2 = ','; + group = 0; + group_exp = 0; + } + }; + + + + /*! + this simple class can be used in multithreading model + (you can write your own class derived from this one) + + for example: in some functions like Factorial() + /at the moment only Factorial/ you can give a pointer to + the 'stop object', if the method WasStopSignal() of this + object returns true that means we should break the calculating + and return + */ + class StopCalculating + { + public: + virtual bool WasStopSignal() const volatile { return false; } + virtual ~StopCalculating(){} + }; + + + /*! + a small class which is useful when compiling with gcc + + object of this type holds the name and the line of a file + in which the macro TTMATH_ASSERT or TTMATH_REFERENCE_ASSERT was used + */ + class ExceptionInfo + { + const char * file; + int line; + + public: + ExceptionInfo() : file(0), line(0) {} + ExceptionInfo(const char * f, int l) : file(f), line(l) {} + + std::string Where() const + { + if( !file ) + return "unknown"; + + std::ostringstream result; + result << file << ":" << line; + + return result.str(); + } + }; + + + /*! + A small class used for reporting 'reference' errors + + In the library is used macro TTMATH_REFERENCE_ASSERT which + can throw an exception of this type + + If you compile with gcc you can get a small benefit + from using method Where() (it returns std::string) with + the name and the line of a file where the macro TTMATH_REFERENCE_ASSERT + was used) + + What is the 'reference' error? + Some kind of methods use a reference as their argument to another object, + and the another object not always can be the same which is calling, e.g. + Big<1,2> foo(10); + foo.Mul(foo); // this is incorrect + above method Mul is making something more with 'this' object and + 'this' cannot be passed as the argument because the result will be undefined + + macro TTMATH_REFERENCE_ASSERT helps us to solve the above problem + + note! some methods can use 'this' object as the argument + for example this code is correct: + UInt<2> foo(10); + foo.Add(foo); + but there are only few methods which can do that + */ + class ReferenceError : public std::logic_error, public ExceptionInfo + { + public: + + ReferenceError() : std::logic_error("reference error") + { + } + + ReferenceError(const char * f, int l) : + std::logic_error("reference error"), ExceptionInfo(f,l) + { + } + + std::string Where() const + { + return ExceptionInfo::Where(); + } + }; + + + /*! + a small class used for reporting errors + + in the library is used macro TTMATH_ASSERT which + (if the condition in it is false) throw an exception + of this type + + if you compile with gcc you can get a small benefit + from using method Where() (it returns std::string) with + the name and the line of a file where the macro TTMATH_ASSERT + was used) + */ + class RuntimeError : public std::runtime_error, public ExceptionInfo + { + public: + + RuntimeError() : std::runtime_error("internal error") + { + } + + RuntimeError(const char * f, int l) : + std::runtime_error("internal error"), ExceptionInfo(f,l) + { + } + + std::string Where() const + { + return ExceptionInfo::Where(); + } + }; + + + + /*! + look at the description of macros TTMATH_RELEASE and TTMATH_DEBUG + */ + #ifdef TTMATH_DEBUG + + #if defined(__FILE__) && defined(__LINE__) + + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ttmath::ReferenceError(__FILE__, __LINE__); + + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw ttmath::RuntimeError(__FILE__, __LINE__); + + #else + + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ReferenceError(); + + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw RuntimeError(); + #endif + + #else + #define TTMATH_REFERENCE_ASSERT(expression) + #define TTMATH_ASSERT(expression) + #endif + + + + #ifdef TTMATH_DEBUG_LOG + #define TTMATH_LOG(msg) PrintLog(msg, std::cout); + #define TTMATH_LOGC(msg, carry) PrintLog(msg, carry, std::cout); + #define TTMATH_VECTOR_LOG(msg, vector, len) PrintVectorLog(msg, std::cout, vector, len); + #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) PrintVectorLog(msg, carry, std::cout, vector, len); + #else + #define TTMATH_LOG(msg) + #define TTMATH_LOGC(msg, carry) + #define TTMATH_VECTOR_LOG(msg, vector, len) + #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) + #endif + + + + +} // namespace + + +#endif + diff --git a/src/libghost/ttmath/ttmath/ttmathuint.h b/src/libghost/ttmath/ttmath/ttmathuint.h new file mode 100644 index 0000000..5f3e3e2 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathuint.h @@ -0,0 +1,3520 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmathuint +#define headerfilettmathuint + + +/*! + \file ttmathuint.h + \brief template class UInt +*/ + +#include +#include + + +#include "ttmathtypes.h" +#include "ttmathmisc.h" + + + +/*! + \brief a namespace for the TTMath library +*/ +namespace ttmath +{ + +/*! + \brief UInt implements a big integer value without a sign + + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits + value_size = 1,2,3,4,5,6.... +*/ +template +class UInt +{ +public: + + /*! + buffer for the integer value + table[0] - the lowest word of the value + */ + uint table[value_size]; + + + + /*! + some methods used for debugging purposes + */ + + + /*! + this method is only for debugging purposes or when we want to make + a table of a variable (constant) in ttmathbig.h + + it prints the table in a nice form of several columns + */ + template + void PrintTable(ostream_type & output) const + { + // how many columns there'll be + const int columns = 8; + + int c = 1; + for(int i=value_size-1 ; i>=0 ; --i) + { + output << "0x" << std::setfill('0'); + + #ifdef TTMATH_PLATFORM32 + output << std::setw(8); + #else + output << std::setw(16); + #endif + + output << std::hex << table[i]; + + if( i>0 ) + { + output << ", "; + + if( ++c > columns ) + { + output << std::endl; + c = 1; + } + } + } + + output << std::dec << std::endl; + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + static void PrintVectorLog(const char_type * msg, ostream_type & output, const uint * vector, uint vector_len) + { + output << msg << std::endl; + + for(uint i=0 ; i + static void PrintVectorLog(const char_type * msg, uint carry, ostream_type & output, const uint * vector, uint vector_len) + { + PrintVectorLog(msg, output, vector, vector_len); + output << " carry: " << carry << std::endl; + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + void PrintLog(const char_type * msg, ostream_type & output) const + { + PrintVectorLog(msg, output, table, value_size); + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + void PrintLog(const char_type * msg, uint carry, ostream_type & output) const + { + PrintVectorLog(msg, output, table, value_size); + output << " carry: " << carry << std::endl; + } + + + /*! + this method returns the size of the table + */ + uint Size() const + { + return value_size; + } + + + /*! + this method sets zero + */ + void SetZero() + { + // in the future here can be 'memset' + + for(uint i=0 ; i=0 && temp_table_index=0 ; --i) + table[i] = 0; + + + TTMATH_LOG("UInt::SetFromTable") + } + +#endif + + +#ifdef TTMATH_PLATFORM64 + /*! + this method copies the value stored in an another table + (warning: first values in temp_table are the highest words -- it's different + from our table) + + ***this method is created only on a 64bit platform*** + + we copy as many words as it is possible + + if temp_table_len is bigger than value_size we'll try to round + the lowest word from table depending on the last not used bit in temp_table + (this rounding isn't a perfect rounding -- look at the description below) + + and if temp_table_len is smaller than value_size we'll clear the rest words + in the table + + warning: we're using 'temp_table' as a pointer at 32bit words + */ + void SetFromTable(const unsigned int * temp_table, uint temp_table_len) + { + uint temp_table_index = 0; + sint i; // 'i' with a sign + + for(i=value_size-1 ; i>=0 && temp_table_index= 0 ; --i) + table[i] = 0; + + TTMATH_LOG("UInt::SetFromTable") + } + +#endif + + + + + + /*! + * + * basic mathematic functions + * + */ + + + + + /*! + this method adds one to the existing value + */ + uint AddOne() + { + return AddInt(1); + } + + + /*! + this method subtracts one from the existing value + */ + uint SubOne() + { + return SubInt(1); + } + + +private: + + + /*! + an auxiliary method for moving bits into the left hand side + + this method moves only words + */ + void RclMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) + { + rest_bits = bits % TTMATH_BITS_PER_UINT; + uint all_words = bits / TTMATH_BITS_PER_UINT; + uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; + + + if( all_words >= value_size ) + { + if( all_words == value_size && rest_bits == 0 ) + last_c = table[0] & 1; + // else: last_c is default set to 0 + + // clearing + for(uint i = 0 ; i 0 ) + { + // 0 < all_words < value_size + + sint first, second; + last_c = table[value_size - all_words] & 1; // all_words is greater than 0 + + // copying the first part of the value + for(first = value_size-1, second=first-all_words ; second>=0 ; --first, --second) + table[first] = table[second]; + + // setting the rest to 'c' + for( ; first>=0 ; --first ) + table[first] = mask; + } + + TTMATH_LOG("UInt::RclMoveAllWords") + } + +public: + + /*! + moving all bits into the left side 'bits' times + return value <- this <- C + + bits is from a range of <0, man * TTMATH_BITS_PER_UINT> + or it can be even bigger then all bits will be set to 'c' + + the value c will be set into the lowest bits + and the method returns state of the last moved bit + */ + uint Rcl(uint bits, uint c=0) + { + uint last_c = 0; + uint rest_bits = bits; + + if( bits == 0 ) + return 0; + + if( bits >= TTMATH_BITS_PER_UINT ) + RclMoveAllWords(rest_bits, last_c, bits, c); + + if( rest_bits == 0 ) + { + TTMATH_LOG("UInt::Rcl") + return last_c; + } + + // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now + if( rest_bits == 1 ) + { + last_c = Rcl2_one(c); + } + else if( rest_bits == 2 ) + { + // performance tests showed that for rest_bits==2 it's better to use Rcl2_one twice instead of Rcl2(2,c) + Rcl2_one(c); + last_c = Rcl2_one(c); + } + else + { + last_c = Rcl2(rest_bits, c); + } + + TTMATH_LOGC("UInt::Rcl", last_c) + + return last_c; + } + +private: + + /*! + an auxiliary method for moving bits into the right hand side + + this method moves only words + */ + void RcrMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) + { + rest_bits = bits % TTMATH_BITS_PER_UINT; + uint all_words = bits / TTMATH_BITS_PER_UINT; + uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; + + + if( all_words >= value_size ) + { + if( all_words == value_size && rest_bits == 0 ) + last_c = (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; + // else: last_c is default set to 0 + + // clearing + for(uint i = 0 ; i 0 ) + { + // 0 < all_words < value_size + + uint first, second; + last_c = (table[all_words - 1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; // all_words is > 0 + + // copying the first part of the value + for(first=0, second=all_words ; second this -> return value + + bits is from a range of <0, man * TTMATH_BITS_PER_UINT> + or it can be even bigger then all bits will be set to 'c' + + the value c will be set into the highest bits + and the method returns state of the last moved bit + */ + uint Rcr(uint bits, uint c=0) + { + uint last_c = 0; + uint rest_bits = bits; + + if( bits == 0 ) + return 0; + + if( bits >= TTMATH_BITS_PER_UINT ) + RcrMoveAllWords(rest_bits, last_c, bits, c); + + if( rest_bits == 0 ) + { + TTMATH_LOG("UInt::Rcr") + return last_c; + } + + // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now + if( rest_bits == 1 ) + { + last_c = Rcr2_one(c); + } + else if( rest_bits == 2 ) + { + // performance tests showed that for rest_bits==2 it's better to use Rcr2_one twice instead of Rcr2(2,c) + Rcr2_one(c); + last_c = Rcr2_one(c); + } + else + { + last_c = Rcr2(rest_bits, c); + } + + TTMATH_LOGC("UInt::Rcr", last_c) + + return last_c; + } + + + /*! + this method moves all bits into the left side + (it returns value how many bits have been moved) + */ + uint CompensationToLeft() + { + uint moving = 0; + + // a - index a last word which is different from zero + sint a; + for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); + + if( a < 0 ) + return moving; // all words in table have zero + + if( a != value_size-1 ) + { + moving += ( value_size-1 - a ) * TTMATH_BITS_PER_UINT; + + // moving all words + sint i; + for(i=value_size-1 ; a>=0 ; --i, --a) + table[i] = table[a]; + + // setting the rest word to zero + for(; i>=0 ; --i) + table[i] = 0; + } + + uint moving2 = FindLeadingBitInWord( table[value_size-1] ); + // moving2 is different from -1 because the value table[value_size-1] + // is not zero + + moving2 = TTMATH_BITS_PER_UINT - moving2 - 1; + Rcl(moving2); + + TTMATH_LOG("UInt::CompensationToLeft") + + return moving + moving2; + } + + + /*! + this method looks for the highest set bit + + result: + if 'this' is not zero: + return value - true + 'table_id' - the index of a word <0..value_size-1> + 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) + + if 'this' is zero: + return value - false + both 'table_id' and 'index' are zero + */ + bool FindLeadingBit(uint & table_id, uint & index) const + { + for(table_id=value_size-1 ; table_id!=0 && table[table_id]==0 ; --table_id); + + if( table_id==0 && table[table_id]==0 ) + { + // is zero + index = 0; + + return false; + } + + // table[table_id] is different from 0 + index = FindLeadingBitInWord( table[table_id] ); + + return true; + } + + + /*! + this method looks for the smallest set bit + + result: + if 'this' is not zero: + return value - true + 'table_id' - the index of a word <0..value_size-1> + 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) + + if 'this' is zero: + return value - false + both 'table_id' and 'index' are zero + */ + bool FindLowestBit(uint & table_id, uint & index) const + { + for(table_id=0 ; table_id= value_size ) + { + // is zero + index = 0; + table_id = 0; + + return false; + } + + // table[table_id] is different from 0 + index = FindLowestBitInWord( table[table_id] ); + + return true; + } + + + /*! + getting the 'bit_index' bit + + bit_index bigger or equal zero + */ + uint GetBit(uint bit_index) const + { + TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) + + uint index = bit_index / TTMATH_BITS_PER_UINT; + uint bit = bit_index % TTMATH_BITS_PER_UINT; + + uint temp = table[index]; + uint res = SetBitInWord(temp, bit); + + return res; + } + + + /*! + setting the 'bit_index' bit + and returning the last state of the bit + + bit_index bigger or equal zero + */ + uint SetBit(uint bit_index) + { + TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) + + uint index = bit_index / TTMATH_BITS_PER_UINT; + uint bit = bit_index % TTMATH_BITS_PER_UINT; + uint res = SetBitInWord(table[index], bit); + + TTMATH_LOG("UInt::SetBit") + + return res; + } + + + /*! + this method performs a bitwise operation AND + */ + void BitAnd(const UInt & ss2) + { + for(uint x=0 ; x & ss2) + { + for(uint x=0 ; x & ss2) + { + for(uint x=0 ; x + + for example: + BitNot2(8) = BitNot2( 1000(bin) ) = 111(bin) = 7 + */ + void BitNot2() + { + uint table_id, index; + + if( FindLeadingBit(table_id, index) ) + { + for(uint x=0 ; x>= shift; + + table[table_id] ^= mask; + } + else + table[0] = 1; + + + TTMATH_LOG("UInt::BitNot2") + } + + + + /*! + * + * Multiplication + * + * + */ + +public: + + /*! + multiplication: this = this * ss2 + + it can return a carry + */ + uint MulInt(uint ss2) + { + uint r1, r2, x1; + uint c = 0; + + UInt u(*this); + SetZero(); + + if( ss2 == 0 ) + { + TTMATH_LOGC("UInt::MulInt(uint)", 0) + return 0; + } + + for(x1=0 ; x1 + void MulInt(uint ss2, UInt & result) const + { + TTMATH_ASSERT( result_size > value_size ) + + uint r2,r1; + uint x1size=value_size; + uint x1start=0; + + result.SetZero(); + + if( ss2 == 0 ) + { + TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) + return; + } + + if( value_size > 2 ) + { + // if the value_size is smaller than or equal to 2 + // there is no sense to set x1size and x1start to another values + + for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); + + if( x1size == 0 ) + { + TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) + return; + } + + for(x1start=0 ; x1start)", result.table, result_size) + + return; + } + + + + /*! + the multiplication 'this' = 'this' * ss2 + + algorithm: 100 - means automatically choose the fastest algorithm + */ + uint Mul(const UInt & ss2, uint algorithm = 100) + { + switch( algorithm ) + { + case 1: + return Mul1(ss2); + + case 2: + return Mul2(ss2); + + case 3: + return Mul3(ss2); + + case 100: + default: + return MulFastest(ss2); + } + } + + + /*! + the multiplication 'result' = 'this' * ss2 + + since the 'result' is twice bigger than 'this' and 'ss2' + this method never returns a carry + + algorithm: 100 - means automatically choose the fastest algorithm + */ + void MulBig(const UInt & ss2, + UInt & result, + uint algorithm = 100) + { + switch( algorithm ) + { + case 1: + return Mul1Big(ss2, result); + + case 2: + return Mul2Big(ss2, result); + + case 3: + return Mul3Big(ss2, result); + + case 100: + default: + return MulFastestBig(ss2, result); + } + } + + + + /*! + the first version of the multiplication algorithm + */ + + /*! + multiplication: this = this * ss2 + + it returns carry if it has been + */ + uint Mul1(const UInt & ss2) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt ss1( *this ); + SetZero(); + + for(uint i=0; i < value_size*TTMATH_BITS_PER_UINT ; ++i) + { + if( Add(*this) ) + { + TTMATH_LOGC("UInt::Mul1", 1) + return 1; + } + + if( ss1.Rcl(1) ) + if( Add(ss2) ) + { + TTMATH_LOGC("UInt::Mul1", 1) + return 1; + } + } + + TTMATH_LOGC("UInt::Mul1", 0) + + return 0; + } + + + /*! + multiplication: result = this * ss2 + + result is twice bigger than 'this' and 'ss2' + this method never returns carry + */ + void Mul1Big(const UInt & ss2_, UInt & result) + { + UInt ss2; + uint i; + + // copying *this into result and ss2_ into ss2 + for(i=0 ; i & ss2) + { + UInt result; + uint i, c = 0; + + Mul2Big(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + Mul2Big2(table, ss2.table, result); + + TTMATH_LOG("UInt::Mul2Big") + } + + +private: + + /*! + an auxiliary method for calculating the multiplication + + arguments we're taking as pointers (this is to improve the Mul3Big2()- avoiding + unnecessary copying objects), the result should be taken as a pointer too, + but at the moment there is no method AddTwoInts() which can operate on pointers + */ + template + void Mul2Big2(const uint * ss1, const uint * ss2, UInt & result) + { + uint x1size = ss_size, x2size = ss_size; + uint x1start = 0, x2start = 0; + + if( ss_size > 2 ) + { + // if the ss_size is smaller than or equal to 2 + // there is no sense to set x1size (and others) to another values + + for(x1size=ss_size ; x1size>0 && ss1[x1size-1]==0 ; --x1size); + for(x2size=ss_size ; x2size>0 && ss2[x2size-1]==0 ; --x2size); + + for(x1start=0 ; x1start(ss1, ss2, result, x1start, x1size, x2start, x2size); + } + + + + /*! + an auxiliary method for calculating the multiplication + */ + template + void Mul2Big3(const uint * ss1, const uint * ss2, UInt & result, uint x1start, uint x1size, uint x2start, uint x2size) + { + uint r2, r1; + + result.SetZero(); + + if( x1size==0 || x2size==0 ) + return; + + for(uint x1=x1start ; x1 & ss2) + { + UInt result; + uint i, c = 0; + + Mul3Big(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + Mul3Big2(table, ss2.table, result.table); + + TTMATH_LOG("UInt::Mul3Big") + } + + + +private: + + /*! + an auxiliary method for calculating the Karatsuba multiplication + + result_size is equal ss_size*2 + */ + template + void Mul3Big2(const uint * ss1, const uint * ss2, uint * result) + { + const uint * x1, * x0, * y1, * y0; + + + if( ss_size>1 && ss_size res; + Mul2Big2(ss1, ss2, res); + + for(uint i=0 ; i(x1, x0, y1, y0, result); + } + else + { + // ss_size is even + x0 = ss1; + y0 = ss2; + x1 = ss1 + ss_size / 2; + y1 = ss2 + ss_size / 2; + + // all four vectors (x0 x1 y0 y1) are equal in size + Mul3Big3(x1, x0, y1, y0, result); + } + } + + + +#ifdef _MSC_VER +#pragma warning (disable : 4717) +//warning C4717: recursive on all control paths, function will cause runtime stack overflow +//we have the stop point in Mul3Big2() method +#endif + + + /*! + an auxiliary method for calculating the Karatsuba multiplication + + x = x1*B^m + x0 + y = y1*B^m + y0 + + first_size - is the size of vectors: x0 and y0 + second_size - is the size of vectors: x1 and y1 (can be either equal first_size or smaller about one from first_size) + + x*y = (x1*B^m + x0)(y1*B^m + y0) = z2*B^(2m) + z1*B^m + z0 + where + z0 = x0*y0 + z2 = x1*y1 + z1 = (x1 + x0)*(y1 + y0) - z2 - z0 + */ + template + void Mul3Big3(const uint * x1, const uint * x0, const uint * y1, const uint * y0, uint * result) + { + uint i, c, xc, yc; + + UInt temp, temp2; + UInt z1; + + // z0 and z2 we store directly in the result (we don't use any temporary variables) + Mul3Big2(x0, y0, result); // z0 + Mul3Big2(x1, y1, result+first_size*2); // z2 + + // now we calculate z1 + // temp = (x0 + x1) + // temp2 = (y0 + y1) + // we're using temp and temp2 with UInt, although there can be a carry but + // we simple remember it in xc and yc (xc and yc can be either 0 or 1), + // and (x0 + x1)*(y0 + y1) we calculate in this way (schoolbook algorithm): + // + // xc | temp + // yc | temp2 + // -------------------- + // (temp * temp2) + // xc*temp2 | + // yc*temp | + // xc*yc | + // ---------- z1 -------- + // + // and the result is never larger in size than 3*first_size + + xc = AddVector(x0, x1, first_size, second_size, temp.table); + yc = AddVector(y0, y1, first_size, second_size, temp2.table); + + Mul3Big2(temp.table, temp2.table, z1.table); + + // clearing the rest of z1 + for(i=first_size*2 ; i second_size ) + { + uint z1_size = result_size - first_size; + TTMATH_ASSERT( z1_size <= first_size*3 ) + + for(i=z1_size ; i & ss2) + { + UInt result; + uint i, c = 0; + + MulFastestBig(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + if( value_size < TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE ) + return Mul2Big(ss2, result); + + uint x1size = value_size, x2size = value_size; + uint x1start = 0, x2start = 0; + + for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); + for(x2size=value_size ; x2size>0 && ss2.table[x2size-1]==0 ; --x2size); + + if( x1size==0 || x2size==0 ) + { + // either 'this' or 'ss2' is equal zero - the result is zero too + result.SetZero(); + return; + } + + for(x1start=0 ; x1start(table, ss2.table, result, x1start, x1size, x2start, x2size); + + + // Karatsuba multiplication + Mul3Big(ss2, result); + + TTMATH_LOG("UInt::MulFastestBig") + } + + + /*! + * + * Division + * + * + */ + +public: + + + /*! + division by one unsigned word + + returns 1 when divisor is zero + */ + uint DivInt(uint divisor, uint * remainder = 0) + { + if( divisor == 0 ) + { + if( remainder ) + *remainder = 0; // this is for convenience, without it the compiler can report that 'remainder' is uninitialized + + TTMATH_LOG("UInt::DivInt") + + return 1; + } + + if( divisor == 1 ) + { + if( remainder ) + *remainder = 0; + + TTMATH_LOG("UInt::DivInt") + + return 0; + } + + UInt dividend(*this); + SetZero(); + + sint i; // i must be with a sign + uint r = 0; + + // we're looking for the last word in ss1 + for(i=value_size-1 ; i>0 && dividend.table[i]==0 ; --i); + + for( ; i>=0 ; --i) + DivTwoWords(r, dividend.table[i], divisor, &table[i], &r); + + if( remainder ) + *remainder = r; + + TTMATH_LOG("UInt::DivInt") + + return 0; + } + + uint DivInt(uint divisor, uint & remainder) + { + return DivInt(divisor, &remainder); + } + + + + /*! + division this = this / ss2 + + return values: + 0 - ok + 1 - division by zero + 'this' will be the quotient + 'remainder' - remainder + */ + uint Div( const UInt & divisor, + UInt * remainder = 0, + uint algorithm = 3) + { + switch( algorithm ) + { + case 1: + return Div1(divisor, remainder); + + case 2: + return Div2(divisor, remainder); + + case 3: + default: + return Div3(divisor, remainder); + } + } + + uint Div(const UInt & divisor, UInt & remainder, uint algorithm = 3) + { + return Div(divisor, &remainder, algorithm); + } + + + +private: + + /*! + return values: + 0 - none has to be done + 1 - division by zero + 2 - division should be made + */ + uint Div_StandardTest( const UInt & v, + uint & m, uint & n, + UInt * remainder = 0) + { + switch( Div_CalculatingSize(v, m, n) ) + { + case 4: // 'this' is equal v + if( remainder ) + remainder->SetZero(); + + SetOne(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 3: // 'this' is smaller than v + if( remainder ) + *remainder = *this; + + SetZero(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 2: // 'this' is zero + if( remainder ) + remainder->SetZero(); + + SetZero(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 1: // v is zero + TTMATH_LOG("UInt::Div_StandardTest") + return 1; + } + + TTMATH_LOG("UInt::Div_StandardTest") + + return 2; + } + + + + /*! + return values: + 0 - ok + 'm' - is the index (from 0) of last non-zero word in table ('this') + 'n' - is the index (from 0) of last non-zero word in v.table + 1 - v is zero + 2 - 'this' is zero + 3 - 'this' is smaller than v + 4 - 'this' is equal v + + if the return value is different than zero the 'm' and 'n' are undefined + */ + uint Div_CalculatingSize(const UInt & v, uint & m, uint & n) + { + m = n = value_size-1; + + for( ; n!=0 && v.table[n]==0 ; --n); + + if( n==0 && v.table[n]==0 ) + return 1; + + for( ; m!=0 && table[m]==0 ; --m); + + if( m==0 && table[m]==0 ) + return 2; + + if( m < n ) + return 3; + else + if( m == n ) + { + uint i; + for(i = n ; i!=0 && table[i]==v.table[i] ; --i); + + if( table[i] < v.table[i] ) + return 3; + else + if (table[i] == v.table[i] ) + return 4; + } + + return 0; + } + + +public: + + /*! + the first division algorithm + radix 2 + */ + uint Div1(const UInt & divisor, UInt * remainder = 0) + { + uint m,n, test; + + test = Div_StandardTest(divisor, m, n, remainder); + if( test < 2 ) + return test; + + if( !remainder ) + { + UInt rem; + + return Div1_Calculate(divisor, rem); + } + + return Div1_Calculate(divisor, *remainder); + } + + +private: + + + uint Div1_Calculate(const UInt & divisor, UInt & rest) + { + TTMATH_REFERENCE_ASSERT( divisor ) + + sint loop; + sint c; + + rest.SetZero(); + loop = value_size * TTMATH_BITS_PER_UINT; + c = 0; + + + div_a: + c = Rcl(1, c); + c = rest.Add(rest,c); + c = rest.Sub(divisor,c); + + c = !c; + + if(!c) + goto div_d; + + + div_b: + --loop; + if(loop) + goto div_a; + + c = Rcl(1, c); + TTMATH_LOG("UInt::Div1_Calculate") + return 0; + + + div_c: + c = Rcl(1, c); + c = rest.Add(rest,c); + c = rest.Add(divisor); + + if(c) + goto div_b; + + + div_d: + --loop; + if(loop) + goto div_c; + + c = Rcl(1, c); + c = rest.Add(divisor); + + TTMATH_LOG("UInt::Div1_Calculate") + + return 0; + } + + +public: + + + /*! + the second division algorithm + + return values: + 0 - ok + 1 - division by zero + */ + uint Div2(const UInt & divisor, UInt * remainder = 0) + { + TTMATH_REFERENCE_ASSERT( divisor ) + + uint bits_diff; + uint status = Div2_Calculate(divisor, remainder, bits_diff); + if( status < 2 ) + return status; + + if( CmpBiggerEqual(divisor) ) + { + Div2(divisor, remainder); + SetBit(bits_diff); + } + else + { + if( remainder ) + *remainder = *this; + + SetZero(); + SetBit(bits_diff); + } + + TTMATH_LOG("UInt::Div2") + + return 0; + } + + + uint Div2(const UInt & divisor, UInt & remainder) + { + return Div2(divisor, &remainder); + } + + +private: + + /*! + return values: + 0 - we've calculated the division + 1 - division by zero + 2 - we have to still calculate + + */ + uint Div2_Calculate(const UInt & divisor, UInt * remainder, + uint & bits_diff) + { + uint table_id, index; + uint divisor_table_id, divisor_index; + + uint status = Div2_FindLeadingBitsAndCheck( divisor, remainder, + table_id, index, + divisor_table_id, divisor_index); + + if( status < 2 ) + { + TTMATH_LOG("UInt::Div2_Calculate") + return status; + } + + // here we know that 'this' is greater than divisor + // then 'index' is greater or equal 'divisor_index' + bits_diff = index - divisor_index; + + UInt divisor_copy(divisor); + divisor_copy.Rcl(bits_diff, 0); + + if( CmpSmaller(divisor_copy, table_id) ) + { + divisor_copy.Rcr(1); + --bits_diff; + } + + Sub(divisor_copy, 0); + + TTMATH_LOG("UInt::Div2_Calculate") + + return 2; + } + + + /*! + return values: + 0 - we've calculated the division + 1 - division by zero + 2 - we have to still calculate + */ + uint Div2_FindLeadingBitsAndCheck( const UInt & divisor, + UInt * remainder, + uint & table_id, uint & index, + uint & divisor_table_id, uint & divisor_index) + { + if( !divisor.FindLeadingBit(divisor_table_id, divisor_index) ) + { + // division by zero + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + return 1; + } + + if( !FindLeadingBit(table_id, index) ) + { + // zero is divided by something + + SetZero(); + + if( remainder ) + remainder->SetZero(); + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 0; + } + + divisor_index += divisor_table_id * TTMATH_BITS_PER_UINT; + index += table_id * TTMATH_BITS_PER_UINT; + + if( divisor_table_id == 0 ) + { + // dividor has only one 32-bit word + + uint r; + DivInt(divisor.table[0], &r); + + if( remainder ) + { + remainder->SetZero(); + remainder->table[0] = r; + } + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 0; + } + + + if( Div2_DivisorGreaterOrEqual( divisor, remainder, + table_id, index, + divisor_index) ) + { + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + return 0; + } + + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 2; + } + + + /*! + return values: + true if divisor is equal or greater than 'this' + */ + bool Div2_DivisorGreaterOrEqual( const UInt & divisor, + UInt * remainder, + uint table_id, uint index, + uint divisor_index ) + { + if( divisor_index > index ) + { + // divisor is greater than this + + if( remainder ) + *remainder = *this; + + SetZero(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + + if( divisor_index == index ) + { + // table_id == divisor_table_id as well + + uint i; + for(i = table_id ; i!=0 && table[i]==divisor.table[i] ; --i); + + if( table[i] < divisor.table[i] ) + { + // divisor is greater than 'this' + + if( remainder ) + *remainder = *this; + + SetZero(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + else + if( table[i] == divisor.table[i] ) + { + // divisor is equal 'this' + + if( remainder ) + remainder->SetZero(); + + SetOne(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + } + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return false; + } + + +public: + + /*! + the third division algorithm + + this algorithm is described in the following book: + "The art of computer programming 2" (4.3.1 page 272) + Donald E. Knuth + */ + uint Div3(const UInt & v, UInt * remainder = 0) + { + TTMATH_REFERENCE_ASSERT( v ) + + uint m,n, test; + + test = Div_StandardTest(v, m, n, remainder); + if( test < 2 ) + return test; + + if( n == 0 ) + { + uint r; + DivInt( v.table[0], &r ); + + if( remainder ) + { + remainder->SetZero(); + remainder->table[0] = r; + } + + TTMATH_LOG("UInt::Div3") + + return 0; + } + + + // we can only use the third division algorithm when + // the divisor is greater or equal 2^32 (has more than one 32-bit word) + ++m; + ++n; + m = m - n; + Div3_Division(v, remainder, m, n); + + TTMATH_LOG("UInt::Div3") + + return 0; + } + + + +private: + + + void Div3_Division(UInt v, UInt * remainder, uint m, uint n) + { + TTMATH_ASSERT( n>=2 ) + + UInt uu, vv; + UInt q; + uint d, u_value_size, u0, u1, u2, v1, v0, j=m; + + u_value_size = Div3_Normalize(v, n, d); + + if( j+n == value_size ) + u2 = u_value_size; + else + u2 = table[j+n]; + + Div3_MakeBiggerV(v, vv); + + for(uint i = j+1 ; i & uu, uint j, uint n, uint u_max) + { + uint i; + + for(i=0 ; i so and 'i' is from <0..value_size> + // then table[i] is always correct (look at the declaration of 'uu') + uu.table[i] = u_max; + + for( ++i ; i & uu, uint j, uint n) + { + uint i; + + for(i=0 ; i & v, UInt & vv) + { + for(uint i=0 ; i & v, uint n, uint & d) + { + // v.table[n-1] is != 0 + + uint bit = (uint)FindLeadingBitInWord(v.table[n-1]); + uint move = (TTMATH_BITS_PER_UINT - bit - 1); + uint res = table[value_size-1]; + d = move; + + if( move > 0 ) + { + v.Rcl(move, 0); + Rcl(move, 0); + res = res >> (bit + 1); + } + else + { + res = 0; + } + + TTMATH_LOG("UInt::Div3_Normalize") + + return res; + } + + + void Div3_Unnormalize(UInt * remainder, uint n, uint d) + { + for(uint i=n ; i u_temp; + uint rp; + bool next_test; + + TTMATH_ASSERT( v1 != 0 ) + + u_temp.table[1] = u2; + u_temp.table[0] = u1; + u_temp.DivInt(v1, &rp); + + TTMATH_ASSERT( u_temp.table[1]==0 || u_temp.table[1]==1 ) + + do + { + bool decrease = false; + + if( u_temp.table[1] == 1 ) + decrease = true; + else + { + UInt<2> temp1, temp2; + + UInt<2>::MulTwoWords(u_temp.table[0], v0, temp1.table+1, temp1.table); + temp2.table[1] = rp; + temp2.table[0] = u0; + + if( temp1 > temp2 ) + decrease = true; + } + + next_test = false; + + if( decrease ) + { + u_temp.SubOne(); + + rp += v1; + + if( rp >= v1 ) // it means that there wasn't a carry (r & uu, + const UInt & vv, uint & qp) + { + // D4 (in the book) + + UInt vv_temp(vv); + vv_temp.MulInt(qp); + + if( uu.Sub(vv_temp) ) + { + // there was a carry + + // + // !!! this part of code was not tested + // + + --qp; + uu.Add(vv); + + // can be a carry from this additions but it should be ignored + // because it cancels with the borrow from uu.Sub(vv_temp) + } + + TTMATH_LOG("UInt::Div3_MultiplySubtract") + } + + + + + + +public: + + + /*! + power this = this ^ pow + binary algorithm (r-to-l) + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument (0^0) + */ + uint Pow(UInt pow) + { + if(pow.IsZero() && IsZero()) + // we don't define zero^zero + return 2; + + UInt start(*this), start_temp; + UInt result; + result.SetOne(); + uint c = 0; + + while( !c ) + { + if( pow.table[0] & 1 ) + c += result.Mul(start); + + pow.Rcr2_one(0); + if( pow.IsZero() ) + break; + + start_temp = start; + // in the second Mul algorithm we can use start.Mul(start) directly (there is no TTMATH_ASSERT_REFERENCE there) + c += start.Mul(start_temp); + } + + *this = result; + + TTMATH_LOGC("UInt::Pow(UInt<>)", c) + + return (c==0)? 0 : 1; + } + + + /*! + square root + e.g. Sqrt(9) = 3 + ('digit-by-digit' algorithm) + */ + void Sqrt() + { + UInt bit, temp; + + if( IsZero() ) + return; + + UInt value(*this); + + SetZero(); + bit.SetZero(); + bit.table[value_size-1] = (TTMATH_UINT_HIGHEST_BIT >> 1); + + while( bit > value ) + bit.Rcr(2); + + while( !bit.IsZero() ) + { + temp = *this; + temp.Add(bit); + + if( value >= temp ) + { + value.Sub(temp); + Rcr(1); + Add(bit); + } + else + { + Rcr(1); + } + + bit.Rcr(2); + } + + TTMATH_LOG("UInt::Sqrt") + } + + + + /*! + this method sets n first bits to value zero + + For example: + let n=2 then if there's a value 111 (bin) there'll be '100' (bin) + */ + void ClearFirstBits(uint n) + { + if( n >= value_size*TTMATH_BITS_PER_UINT ) + { + SetZero(); + TTMATH_LOG("UInt::ClearFirstBits") + return; + } + + uint * p = table; + + // first we're clearing the whole words + while( n >= TTMATH_BITS_PER_UINT ) + { + *p++ = 0; + n -= TTMATH_BITS_PER_UINT; + } + + if( n == 0 ) + { + TTMATH_LOG("UInt::ClearFirstBits") + return; + } + + // and then we're clearing one word which has left + // mask -- all bits are set to one + uint mask = TTMATH_UINT_MAX_VALUE; + + mask = mask << n; + + (*p) &= mask; + + TTMATH_LOG("UInt::ClearFirstBits") + } + + + /*! + this method returns true if the highest bit of the value is set + */ + bool IsTheHighestBitSet() const + { + return (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0; + } + + + /*! + this method returns true if the lowest bit of the value is set + */ + bool IsTheLowestBitSet() const + { + return (*table & 1) != 0; + } + + + /*! + this method returns true if the value is equal zero + */ + bool IsZero() const + { + for(uint i=0 ; i> (TTMATH_BITS_PER_UINT - rest); + + return (table[i] & mask) == 0; + } + + + + /*! + * + * conversion methods + * + */ + + + + /*! + this method converts an UInt type to this class + + this operation has mainly sense if the value from p is + equal or smaller than that one which is returned from UInt::SetMax() + + it returns a carry if the value 'p' is too big + */ + template + uint FromUInt(const UInt & p) + { + uint min_size = (value_size < argument_size)? value_size : argument_size; + uint i; + + for(i=0 ; i argument_size ) + { + // 'this' is longer than 'p' + + for( ; i)", 1) + return 1; + } + } + + TTMATH_LOGC("UInt::FromUInt(UInt<>)", 0) + + return 0; + } + + + /*! + this method converts the uint type to this class + */ + void FromUInt(uint value) + { + for(uint i=1 ; i type to this class + + it doesn't return a carry + */ + template + UInt & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + + /*! + the assignment operator + */ + UInt & operator=(const UInt & p) + { + for(uint i=0 ; i)") + + return *this; + } + + + /*! + this method converts the uint type to this class + */ + UInt & operator=(uint i) + { + FromUInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + UInt(uint i) + { + FromUInt(i); + } + + + /*! + this method converts the sint type to this class + + we provide operator(sint) and the constructor(sint) in order to allow + the programmer do that: + UInt<..> type = 10; + + above "10" constant has the int type (signed int), if we don't give such + operators and constructors the compiler will not compile the program, + because it has to make a conversion and doesn't know into which type + (the UInt class has operator=(const char*), operator=(uint) etc.) + */ + UInt & operator=(sint i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the sint to this class + + look at the description of UInt::operator=(sint) + */ + UInt(sint i) + { + FromUInt(uint(i)); + } + + + +#ifdef TTMATH_PLATFORM64 + + /*! + in 64bit platforms we must define additional operators and contructors + in order to allow a user initializing the objects in this way: + UInt<...> type = 20; + or + UInt<...> type; + type = 30; + + decimal constants such as 20, 30 etc. are integer literal of type int, + if the value is greater it can even be long int, + 0 is an octal integer of type int + (ISO 14882 p2.13.1 Integer literals) + */ + + /*! + this operator converts the unsigned int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + UInt & operator=(unsigned int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the unsigned int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + UInt(unsigned int i) + { + FromUInt(uint(i)); + } + + + /*! + an operator for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + + look at the description of UInt::operator=(sint) + */ + UInt & operator=(signed int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + + look at the description of UInt::operator=(sint) + */ + UInt(signed int i) + { + FromUInt(uint(i)); + } + + +#endif + + + + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const char * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const wchar_t * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const std::string & s) + { + FromString( s.c_str() ); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const std::wstring & s) + { + FromString( s.c_str() ); + } + + + /*! + a default constructor + + we don't clear the table + */ + UInt() + { + // when macro TTMATH_DEBUG_LOG is defined + // we set special values to the table + // in order to be everywhere the same value of the UInt object + // without this it would be difficult to analyse the log file + #ifdef TTMATH_DEBUG_LOG + #ifdef TTMATH_PLATFORM32 + for(uint i=0 ; i & u) + { + for(uint i=0 ; i)") + } + + + + /*! + a template for producting constructors for copying from another types + */ + template + UInt(const UInt & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromUInt(u); + } + + + + + /*! + a destructor + */ + ~UInt() + { + } + + + /*! + this method returns the lowest value from table + + we must be sure when we using this method whether the value + will hold in an uint type or not (the rest value from the table must be zero) + */ + uint ToUInt() const + { + return table[0]; + } + + +private: + + /*! + an auxiliary method for converting to a string + */ + template + void ToStringBase(string_type & result, uint b = 10) const + { + UInt temp( *this ); + char character; + uint rem; + + result.clear(); + + if( b<2 || b>16 ) + return; + + do + { + temp.DivInt(b, &rem); + character = static_cast( Misc::DigitToChar(rem) ); + result.insert(result.begin(), character); + } + while( !temp.IsZero() ); + + return; + } + + +public: + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + void ToString(std::wstring & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + std::string ToString(uint b = 10) const + { + std::string result; + ToStringBase(result, b); + + return result; + } + + std::wstring ToWString(uint b = 10) const + { + std::wstring result; + ToStringBase(result, b); + + return result; + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) + { + UInt base( b ); + UInt temp; + sint z; + uint c = 0; + + SetZero(); + temp.SetZero(); + Misc::SkipWhiteCharacters(s); + + if( after_source ) + *after_source = s; + + if( value_read ) + *value_read = false; + + if( b<2 || b>16 ) + return 1; + + + for( ; (z=Misc::CharToDigit(*s, b)) != -1 ; ++s) + { + if( value_read ) + *value_read = true; + + if( c == 0 ) + { + temp.table[0] = z; + + c += Mul(base); + c += Add(temp); + } + } + + if( after_source ) + *after_source = s; + + TTMATH_LOGC("UInt::FromString", c) + + return (c==0)? 0 : 1; + } + + +public: + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + + string is ended with a non-digit value, for example: + "12" will be translated to 12 + as well as: + "12foo" will be translated to 12 too + + existing first white characters will be ommited + + if the value from s is too large the rest digits will be skipped + + after_source (if exists) is pointing at the end of the parsed string + + value_read (if exists) tells whether something has actually been read (at least one digit) + */ + uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + */ + uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + + (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) + */ + uint FromString(const std::string & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this method converts a string into its value + + (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) + */ + uint FromString(const std::wstring & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const char * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const wchar_t * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const std::wstring & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + * + * methods for comparing + * + */ + + + /*! + this method returns true if 'this' is smaller than 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + I introduced it for some kind of optimization made in the second division algorithm (Div2) + */ + bool CmpSmaller(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return false; + } + + + + /*! + this method returns true if 'this' is bigger than 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + + I introduced it for some kind of optimization made in the second division algorithm (Div2) + */ + bool CmpBigger(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return false; + } + + + /*! + this method returns true if 'this' is equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpEqual(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + if( table[i] != l.table[i] ) + return false; + + return true; + } + + + + /*! + this method returns true if 'this' is smaller than or equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpSmallerEqual(const UInt & l, sint index=-1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return true; + } + + + + /*! + this method returns true if 'this' is bigger than or equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpBiggerEqual(const UInt & l, sint index=-1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return true; + } + + + /* + operators for comparising + */ + + bool operator<(const UInt & l) const + { + return CmpSmaller(l); + } + + + bool operator>(const UInt & l) const + { + return CmpBigger(l); + } + + + bool operator==(const UInt & l) const + { + return CmpEqual(l); + } + + + bool operator!=(const UInt & l) const + { + return !operator==(l); + } + + + bool operator<=(const UInt & l) const + { + return CmpSmallerEqual(l); + } + + bool operator>=(const UInt & l) const + { + return CmpBiggerEqual(l); + } + + + /*! + * + * standard mathematical operators + * + */ + + UInt operator-(const UInt & p2) const + { + UInt temp(*this); + + temp.Sub(p2); + + return temp; + } + + UInt & operator-=(const UInt & p2) + { + Sub(p2); + + return *this; + } + + UInt operator+(const UInt & p2) const + { + UInt temp(*this); + + temp.Add(p2); + + return temp; + } + + UInt & operator+=(const UInt & p2) + { + Add(p2); + + return *this; + } + + + UInt operator*(const UInt & p2) const + { + UInt temp(*this); + + temp.Mul(p2); + + return temp; + } + + + UInt & operator*=(const UInt & p2) + { + Mul(p2); + + return *this; + } + + + UInt operator/(const UInt & p2) const + { + UInt temp(*this); + + temp.Div(p2); + + return temp; + } + + + UInt & operator/=(const UInt & p2) + { + Div(p2); + + return *this; + } + + + UInt operator%(const UInt & p2) const + { + UInt temp(*this); + UInt remainder; + + temp.Div( p2, remainder ); + + return remainder; + } + + + UInt & operator%=(const UInt & p2) + { + UInt temp(*this); + UInt remainder; + + temp.Div( p2, remainder ); + + operator=(remainder); + + return *this; + } + + + /*! + Prefix operator e.g ++variable + */ + UInt & operator++() + { + AddOne(); + + return *this; + } + + + /*! + Postfix operator e.g variable++ + */ + UInt operator++(int) + { + UInt temp( *this ); + + AddOne(); + + return temp; + } + + + UInt & operator--() + { + SubOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + UInt operator>>(int move) + { + UInt temp( *this ); + + temp.Rcr(move); + + return temp; + } + + + UInt & operator>>=(int move) + { + Rcr(move); + + return *this; + } + + + UInt operator<<(int move) + { + UInt temp( *this ); + + temp.Rcl(move); + + return temp; + } + + + UInt & operator<<=(int move) + { + Rcl(move); + + return *this; + } + + + /*! + * + * input/output operators for standard streams + * + * (they are very simple, in the future they should be changed) + * + */ + + +private: + + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const UInt & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const UInt & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const UInt & l) + { + return OutputToStream(s, l); + } + + +private: + + /*! + an auxiliary method for reading from standard streams + */ + template + static istream_type & InputFromStream(istream_type & s, UInt & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z; + + // operator>> omits white characters if they're set for ommiting + s >> z; + + // we're reading only digits (base=10) + while( s.good() && Misc::CharToDigit(z, 10)>=0 ) + { + ss += z; + z = static_cast(s.get()); + } + + // we're leaving the last read character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + +public: + + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, UInt & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, UInt & l) + { + return InputFromStream(s, l); + } + + + /* + following methods are defined in: + ttmathuint_x86.h + ttmathuint_x86_64.h + ttmathuint_noasm.h + */ + +#ifdef TTMATH_NOASM + static uint AddTwoWords(uint a, uint b, uint carry, uint * result); + static uint SubTwoWords(uint a, uint b, uint carry, uint * result); + +#ifdef TTMATH_PLATFORM64 + + union uint_ + { + struct + { + unsigned int low; // 32 bit + unsigned int high; // 32 bit + } u_; + + uint u; // 64 bit + }; + + + static void DivTwoWords2(uint a,uint b, uint c, uint * r, uint * rest); + static uint DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_); + static uint DivTwoWordsUnnormalize(uint u, uint d); + static unsigned int DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_); + static void MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_); + +#endif // TTMATH_PLATFORM64 +#endif // TTMATH_NOASM + + +private: + uint Rcl2_one(uint c); + uint Rcr2_one(uint c); + uint Rcl2(uint bits, uint c); + uint Rcr2(uint bits, uint c); + +public: + static const char * LibTypeStr(); + static LibTypeCode LibType(); + uint Add(const UInt & ss2, uint c=0); + uint AddInt(uint value, uint index = 0); + uint AddTwoInts(uint x2, uint x1, uint index); + static uint AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint Sub(const UInt & ss2, uint c=0); + uint SubInt(uint value, uint index = 0); + static uint SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + static sint FindLeadingBitInWord(uint x); + static sint FindLowestBitInWord(uint x); + static uint SetBitInWord(uint & value, uint bit); + static void MulTwoWords(uint a, uint b, uint * result_high, uint * result_low); + static void DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest); + +}; + + + +/*! + this specialization is needed in order to not confused the compiler "error: ISO C++ forbids zero-size array" + when compiling Mul3Big2() method +*/ +template<> +class UInt<0> +{ +public: + uint table[1]; + + void Mul2Big(const UInt<0> &, UInt<0> &) { TTMATH_ASSERT(false) }; + void SetZero() { TTMATH_ASSERT(false) }; + uint AddTwoInts(uint, uint, uint) { TTMATH_ASSERT(false) return 0; }; +}; + + +} //namespace + + +#include "ttmathuint_x86.h" +#include "ttmathuint_x86_64.h" +#include "ttmathuint_noasm.h" + +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathuint_noasm.h b/src/libghost/ttmath/ttmath/ttmathuint_noasm.h new file mode 100644 index 0000000..ed3c180 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathuint_noasm.h @@ -0,0 +1,1013 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + +#ifndef headerfilettmathuint_noasm +#define headerfilettmathuint_noasm + + +#ifdef TTMATH_NOASM + +/*! + \file ttmathuint_noasm.h + \brief template class UInt with methods without any assembler code + + this file is included at the end of ttmathuint.h +*/ + + +namespace ttmath +{ + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifdef TTMATH_PLATFORM32 + static const char info[] = "no_asm_32"; + #endif + + #ifdef TTMATH_PLATFORM64 + static const char info[] = "no_asm_64"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifdef TTMATH_PLATFORM32 + LibTypeCode info = no_asm_32; + #endif + + #ifdef TTMATH_PLATFORM64 + LibTypeCode info = no_asm_64; + #endif + + return info; + } + + + /*! + this method adds two words together + returns carry + + this method is created only when TTMATH_NOASM macro is defined + */ + template + uint UInt::AddTwoWords(uint a, uint b, uint carry, uint * result) + { + uint temp; + + if( carry == 0 ) + { + temp = a + b; + + if( temp < a ) + carry = 1; + } + else + { + carry = 1; + temp = a + b + carry; + + if( temp > a ) // !(temp<=a) + carry = 0; + } + + *result = temp; + + return carry; + } + + + + /*! + this method adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint i; + + for(i=0 ; i + uint UInt::AddInt(uint value, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size ) + + + c = AddTwoWords(table[index], value, 0, &table[index]); + + for(i=index+1 ; i + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size - 1 ) + + + c = AddTwoWords(table[index], x1, 0, &table[index]); + c = AddTwoWords(table[index+1], x2, c, &table[index+1]); + + for(i=index+2 ; i + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + uint i, c = 0; + + TTMATH_ASSERT( ss1_size >= ss2_size ) + + for(i=0 ; i + uint UInt::SubTwoWords(uint a, uint b, uint carry, uint * result) + { + if( carry == 0 ) + { + *result = a - b; + + if( a < b ) + carry = 1; + } + else + { + carry = 1; + *result = a - b - carry; + + if( a > b ) // !(a <= b ) + carry = 0; + } + + return carry; + } + + + + + /*! + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint i; + + for(i=0 ; i + uint UInt::SubInt(uint value, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size ) + + + c = SubTwoWords(table[index], value, 0, &table[index]); + + for(i=index+1 ; i + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + uint i, c = 0; + + TTMATH_ASSERT( ss1_size >= ss2_size ) + + for(i=0 ; i + uint UInt::Rcl2_one(uint c) + { + uint i, new_c; + + if( c != 0 ) + c = 1; + + for(i=0 ; i this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + */ + template + uint UInt::Rcr2_one(uint c) + { + sint i; // signed i + uint new_c; + + if( c != 0 ) + c = TTMATH_UINT_HIGHEST_BIT; + + for(i=sint(value_size)-1 ; i>=0 ; --i) + { + new_c = (table[i] & 1) ? TTMATH_UINT_HIGHEST_BIT : 0; + table[i] = (table[i] >> 1) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits> move; + + for(i=0 ; i> move; + table[i] = (table[i] << bits) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcl2", c) + + return (c & 1); + } + + + + + /*! + this method moves all bits into the right hand side + C -> this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits=0 ; --i) + { + new_c = table[i] << move; + table[i] = (table[i] >> bits) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcr2", c) + + return (c & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; + } + + + + + /*! + this method returns the number of the highest set bit in x + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLeadingBitInWord(uint x) + { + if( x == 0 ) + return -1; + + uint bit = TTMATH_BITS_PER_UINT - 1; + + while( (x & TTMATH_UINT_HIGHEST_BIT) == 0 ) + { + x = x << 1; + --bit; + } + + return bit; + } + + + + /*! + this method returns the number of the highest set bit in x + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + if( x == 0 ) + return -1; + + uint bit = 0; + + while( (x & 1) == 0 ) + { + x = x >> 1; + ++bit; + } + + return bit; + } + + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + bit is from <0,TTMATH_BITS_PER_UINT-1> + + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint mask = 1; + + if( bit > 0 ) + mask = mask << bit; + + uint last = value & mask; + value = value | mask; + + return (last != 0) ? 1 : 0; + } + + + + + + + /*! + * + * Multiplication + * + * + */ + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + #ifdef TTMATH_PLATFORM32 + + /* + on 32bit platforms we have defined 'unsigned long long int' type known as 'ulint' in ttmath namespace + this type has 64 bits, then we're using only one multiplication: 32bit * 32bit = 64bit + */ + + union uint_ + { + struct + { + uint low; // 32 bits + uint high; // 32 bits + } u_; + + ulint u; // 64 bits + } res; + + res.u = ulint(a) * ulint(b); // multiply two 32bit words, the result has 64 bits + + *result_high = res.u_.high; + *result_low = res.u_.low; + + #else + + /* + 64 bits platforms + + we don't have a native type which has 128 bits + then we're splitting 'a' and 'b' to 4 parts (high and low halves) + and using 4 multiplications (with additions and carry correctness) + */ + + uint_ a_; + uint_ b_; + uint_ res_high1, res_high2; + uint_ res_low1, res_low2; + + a_.u = a; + b_.u = b; + + /* + the multiplication is as follows (schoolbook algorithm with O(n^2) ): + + 32 bits 32 bits + + +--------------------------------+ + | a_.u_.high | a_.u_.low | + +--------------------------------+ + | b_.u_.high | b_.u_.low | + +--------------------------------+--------------------------------+ + | res_high1.u | res_low1.u | + +--------------------------------+--------------------------------+ + | res_high2.u | res_low2.u | + +--------------------------------+--------------------------------+ + + 64 bits 64 bits + */ + + + uint_ temp; + + res_low1.u = uint(b_.u_.low) * uint(a_.u_.low); + + temp.u = uint(res_low1.u_.high) + uint(b_.u_.low) * uint(a_.u_.high); + res_low1.u_.high = temp.u_.low; + res_high1.u_.low = temp.u_.high; + res_high1.u_.high = 0; + + res_low2.u_.low = 0; + temp.u = uint(b_.u_.high) * uint(a_.u_.low); + res_low2.u_.high = temp.u_.low; + + res_high2.u = uint(b_.u_.high) * uint(a_.u_.high) + uint(temp.u_.high); + + uint c = AddTwoWords(res_low1.u, res_low2.u, 0, &res_low2.u); + AddTwoWords(res_high1.u, res_high2.u, c, &res_high2.u); // there is no carry from here + + *result_high = res_high2.u; + *result_low = res_low2.u; + + #endif + } + + + + + /*! + * + * Division + * + * + */ + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + * + * WARNING: + * the c has to be suitably large for the result being keeped in one word, + * if c is equal zero there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) + { + // (a < c ) for the result to be one word + TTMATH_ASSERT( c != 0 && a < c ) + + #ifdef TTMATH_PLATFORM32 + + union + { + struct + { + uint low; // 32 bits + uint high; // 32 bits + } u_; + + ulint u; // 64 bits + } ab; + + ab.u_.high = a; + ab.u_.low = b; + + *r = uint(ab.u / c); + *rest = uint(ab.u % c); + + #else + + uint_ c_; + c_.u = c; + + + if( a == 0 ) + { + *r = b / c; + *rest = b % c; + } + else + if( c_.u_.high == 0 ) + { + // higher half of 'c' is zero + // then higher half of 'a' is zero too (look at the asserts at the beginning - 'a' is smaller than 'c') + uint_ a_, b_, res_, temp1, temp2; + + a_.u = a; + b_.u = b; + + temp1.u_.high = a_.u_.low; + temp1.u_.low = b_.u_.high; + + res_.u_.high = (unsigned int)(temp1.u / c); + temp2.u_.high = (unsigned int)(temp1.u % c); + temp2.u_.low = b_.u_.low; + + res_.u_.low = (unsigned int)(temp2.u / c); + *rest = temp2.u % c; + + *r = res_.u; + } + else + { + return DivTwoWords2(a, b, c, r, rest); + } + + #endif + } + + +#ifdef TTMATH_PLATFORM64 + + + /*! + this method is available only on 64bit platforms + + the same algorithm like the third division algorithm in ttmathuint.h + but now with the radix=2^32 + */ + template + void UInt::DivTwoWords2(uint a, uint b, uint c, uint * r, uint * rest) + { + // a is not zero + // c_.u_.high is not zero + + uint_ a_, b_, c_, u_, q_; + unsigned int u3; // 32 bit + + a_.u = a; + b_.u = b; + c_.u = c; + + // normalizing + uint d = DivTwoWordsNormalize(a_, b_, c_); + + // loop from j=1 to j=0 + // the first step (for j=2) is skipped because our result is only in one word, + // (first 'q' were 0 and nothing would be changed) + u_.u_.high = a_.u_.high; + u_.u_.low = a_.u_.low; + u3 = b_.u_.high; + q_.u_.high = DivTwoWordsCalculate(u_, u3, c_); + MultiplySubtract(u_, u3, q_.u_.high, c_); + + u_.u_.high = u_.u_.low; + u_.u_.low = u3; + u3 = b_.u_.low; + q_.u_.low = DivTwoWordsCalculate(u_, u3, c_); + MultiplySubtract(u_, u3, q_.u_.low, c_); + + *r = q_.u; + + // unnormalizing for the remainder + u_.u_.high = u_.u_.low; + u_.u_.low = u3; + *rest = DivTwoWordsUnnormalize(u_.u, d); + } + + + + + template + uint UInt::DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_) + { + uint d = 0; + + for( ; (c_.u & TTMATH_UINT_HIGHEST_BIT) == 0 ; ++d ) + { + c_.u = c_.u << 1; + + uint bc = b_.u & TTMATH_UINT_HIGHEST_BIT; // carry from 'b' + + b_.u = b_.u << 1; + a_.u = a_.u << 1; // carry bits from 'a' are simply skipped + + if( bc ) + a_.u = a_.u | 1; + } + + return d; + } + + + template + uint UInt::DivTwoWordsUnnormalize(uint u, uint d) + { + if( d == 0 ) + return u; + + u = u >> d; + + return u; + } + + + template + unsigned int UInt::DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_) + { + bool next_test; + uint_ qp_, rp_, temp_; + + qp_.u = u_.u / uint(v_.u_.high); + rp_.u = u_.u % uint(v_.u_.high); + + TTMATH_ASSERT( qp_.u_.high==0 || qp_.u_.high==1 ) + + do + { + bool decrease = false; + + if( qp_.u_.high == 1 ) + decrease = true; + else + { + temp_.u_.high = rp_.u_.low; + temp_.u_.low = u3; + + if( qp_.u * uint(v_.u_.low) > temp_.u ) + decrease = true; + } + + next_test = false; + + if( decrease ) + { + --qp_.u; + rp_.u += v_.u_.high; + + if( rp_.u_.high == 0 ) + next_test = true; + } + } + while( next_test ); + + return qp_.u_.low; + } + + + template + void UInt::MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_) + { + uint_ temp_; + + uint res_high; + uint res_low; + + MulTwoWords(v_.u, q, &res_high, &res_low); + + uint_ sub_res_high_; + uint_ sub_res_low_; + + temp_.u_.high = u_.u_.low; + temp_.u_.low = u3; + + uint c = SubTwoWords(temp_.u, res_low, 0, &sub_res_low_.u); + + temp_.u_.high = 0; + temp_.u_.low = u_.u_.high; + c = SubTwoWords(temp_.u, res_high, c, &sub_res_high_.u); + + if( c ) + { + --q; + + c = AddTwoWords(sub_res_low_.u, v_.u, 0, &sub_res_low_.u); + AddTwoWords(sub_res_high_.u, 0, c, &sub_res_high_.u); + } + + u_.u_.high = sub_res_high_.u_.low; + u_.u_.low = sub_res_low_.u_.high; + u3 = sub_res_low_.u_.low; + } + +#endif // #ifdef TTMATH_PLATFORM64 + + + +} //namespace + + +#endif //ifdef TTMATH_NOASM +#endif + + + + diff --git a/src/libghost/ttmath/ttmath/ttmathuint_x86.h b/src/libghost/ttmath/ttmath/ttmathuint_x86.h new file mode 100644 index 0000000..1dd087f --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathuint_x86.h @@ -0,0 +1,1602 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + + +#ifndef headerfilettmathuint_x86 +#define headerfilettmathuint_x86 + + +#ifndef TTMATH_NOASM +#ifdef TTMATH_PLATFORM32 + + +/*! + \file ttmathuint_x86.h + \brief template class UInt with assembler code for 32bit x86 processors + + this file is included at the end of ttmathuint.h +*/ + + + +/*! + \brief a namespace for the TTMath library +*/ +namespace ttmath +{ + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifndef __GNUC__ + static const char info[] = "asm_vc_32"; + #endif + + #ifdef __GNUC__ + static const char info[] = "asm_gcc_32"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifndef __GNUC__ + LibTypeCode info = asm_vc_32; + #endif + + #ifdef __GNUC__ + LibTypeCode info = asm_gcc_32; + #endif + + return info; + } + + + + /*! + * + * basic mathematic functions + * + */ + + + /*! + adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it has been) + */ + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + uint * p2 = const_cast(ss2.table); + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + + __asm + { + push eax + push ebx + push ecx + push edx + push esi + + mov ecx,[b] + + mov ebx,[p1] + mov esi,[p2] + + xor edx,edx // edx=0 + mov eax,[c] + neg eax // CF=1 if rax!=0 , CF=0 if rax==0 + + ttmath_loop: + mov eax,[esi+edx*4] + adc [ebx+edx*4],eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop esi + pop edx + pop ecx + pop ebx + pop eax + } + + + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + // this part should be compiled with gcc + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" + "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movl (%%esi,%%edx,4), %%eax \n" + "adcl %%eax, (%%ebx,%%edx,4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + #endif + + TTMATH_LOGC("UInt::Add", c) + + return c; + } + + + + /*! + adding one word (at a specific position) + and returning a carry (if it has been) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::AddInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov edx, [index] + mov ebx, [p1] + + mov eax, [value] + + ttmath_loop: + add [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 1 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "1: \n" + "addl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "movl $1, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%edx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddInt", c) + + return c; + } + + + + + /*! + adding only two unsigned words to the existing value + and these words begin on the 'index' position + (it's used in the multiplication algorithm 2) + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + for example if we've got value_size equal 4 and: + table[0] = 3 + table[1] = 4 + table[2] = 5 + table[3] = 6 + then let + x1 = 10 + x2 = 20 + and + index = 1 + + the result of this method will be: + table[0] = 3 + table[1] = 4 + x1 = 14 + table[2] = 5 + x2 = 25 + table[3] = 6 + + and no carry at the end of table[3] + + (of course if there was a carry in table[2](5+20) then + this carry would be passed to the table[3] etc.) + */ + template + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size - 1 ) + + #ifndef __GNUC__ + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov ebx, [p1] + mov edx, [index] + + mov eax, [x1] + add [ebx+edx*4], eax + inc edx + dec ecx + + mov eax, [x2] + + ttmath_loop: + adc [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 0 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + + } + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "addl %%esi, (%%ebx,%%edx,4) \n" + "incl %%edx \n" + "decl %%ecx \n" + + "1: \n" + "adcl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "mov $0, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%eax \n" + + : "=a" (c), "=c" (dummy), "=d" (dummy2) + : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddTwoInts", c) + + return c; + } + + + + /*! + this static method addes one vector to the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5+1 + 4 3 4+3 + 2 7 2+7 + 6 6 + 9 9 + of course the carry is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint rest = ss1_size - ss2_size; + uint c; + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + __asm + { + pushad + + mov ecx, [ss2_size] + xor edx, edx // edx = 0, cf = 0 + + mov esi, [ss1] + mov ebx, [ss2] + mov edi, [result] + + ttmath_loop: + mov eax, [esi+edx*4] + adc eax, [ebx+edx*4] + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx // ecx has the cf state + + mov ebx, [rest] + or ebx, ebx + jz ttmath_end + + xor ebx, ebx // ebx = 0 + neg ecx // setting cf from ecx + mov ecx, [rest] // ecx is != 0 + + ttmath_loop2: + mov eax, [esi+edx*4] + adc eax, ebx + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop2 + + adc ecx, ecx + + ttmath_end: + mov [c], ecx + + popad + } + + #endif + + + #ifdef __GNUC__ + + // this part should be compiled with gcc + uint dummy1, dummy2, dummy3; + + __asm__ __volatile__( + "push %%edx \n" + "xor %%edx, %%edx \n" // edx = 0, cf = 0 + "1: \n" + "mov (%%esi,%%edx,4), %%eax \n" + "adc (%%ebx,%%edx,4), %%eax \n" + "mov %%eax, (%%edi,%%edx,4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" // ecx has the cf state + "pop %%eax \n" // eax = rest + + "or %%eax, %%eax \n" + "jz 3f \n" + + "xor %%ebx, %%ebx \n" // ebx = 0 + "neg %%ecx \n" // setting cf from ecx + "mov %%eax, %%ecx \n" // ecx=rest and is != 0 + "2: \n" + "mov (%%esi, %%edx, 4), %%eax \n" + "adc %%ebx, %%eax \n" + "mov %%eax, (%%edi, %%edx, 4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 2b \n" + + "adc %%ecx, %%ecx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) + + return c; + } + + + /*! + subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it has been) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + uint * p2 = const_cast(ss2.table); + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + push esi + + mov ecx,[b] + + mov ebx,[p1] + mov esi,[p2] + + xor edx,edx // edx=0 + mov eax,[c] + neg eax // CF=1 if rax!=0 , CF=0 if rax==0 + + ttmath_loop: + mov eax,[esi+edx*4] + sbb [ebx+edx*4],eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop esi + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" + "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movl (%%esi,%%edx,4), %%eax \n" + "sbbl %%eax, (%%ebx,%%edx,4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Sub", c) + + return c; + } + + + + + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::SubInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov edx, [index] + mov ebx, [p1] + + mov eax, [value] + + ttmath_loop: + sub [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 1 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "1: \n" + "subl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "movl $1, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%edx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::SubInt", c) + + return c; + } + + + + /*! + this static method subtractes one vector from the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5-1 + 4 3 4-3 + 2 7 2-7 + 6 6-1 (the borrow from previous item) + 9 9 + return (carry): 0 + of course the carry (borrow) is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint rest = ss1_size - ss2_size; + uint c; + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + + /* + the asm code is nearly the same as in AddVector + only two instructions 'adc' are changed to 'sbb' + */ + __asm + { + pushad + + mov ecx, [ss2_size] + xor edx, edx // edx = 0, cf = 0 + + mov esi, [ss1] + mov ebx, [ss2] + mov edi, [result] + + ttmath_loop: + mov eax, [esi+edx*4] + sbb eax, [ebx+edx*4] + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx // ecx has the cf state + + mov ebx, [rest] + or ebx, ebx + jz ttmath_end + + xor ebx, ebx // ebx = 0 + neg ecx // setting cf from ecx + mov ecx, [rest] // ecx is != 0 + + ttmath_loop2: + mov eax, [esi+edx*4] + sbb eax, ebx + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop2 + + adc ecx, ecx + + ttmath_end: + mov [c], ecx + + popad + } + + #endif + + + #ifdef __GNUC__ + + // this part should be compiled with gcc + uint dummy1, dummy2, dummy3; + + __asm__ __volatile__( + "push %%edx \n" + "xor %%edx, %%edx \n" // edx = 0, cf = 0 + "1: \n" + "mov (%%esi,%%edx,4), %%eax \n" + "sbb (%%ebx,%%edx,4), %%eax \n" + "mov %%eax, (%%edi,%%edx,4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" // ecx has the cf state + "pop %%eax \n" // eax = rest + + "or %%eax, %%eax \n" + "jz 3f \n" + + "xor %%ebx, %%ebx \n" // ebx = 0 + "neg %%ecx \n" // setting cf from ecx + "mov %%eax, %%ecx \n" // ecx=rest and is != 0 + "2: \n" + "mov (%%esi, %%edx, 4), %%eax \n" + "sbb %%ebx, %%eax \n" + "mov %%eax, (%%edi, %%edx, 4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 2b \n" + + "adc %%ecx, %%ecx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) + + return c; + } + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bit* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 + */ + template + uint UInt::Rcl2_one(uint c) + { + uint b = value_size; + uint * p1 = table; + + #ifndef __GNUC__ + __asm + { + push ebx + push ecx + push edx + + mov ebx, [p1] + xor edx, edx + mov ecx, [c] + neg ecx + mov ecx, [b] + + ttmath_loop: + rcl dword ptr [ebx+edx*4], 1 + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop edx + pop ecx + pop ebx + } + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" // edx=0 + "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 + + "1: \n" + "rcll $1, (%%ebx, %%edx, 4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adcl %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2_one", c) + + return c; + } + + + + /*! + this method moves all bits into the right hand side + c -> this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + */ + template + uint UInt::Rcr2_one(uint c) + { + uint b = value_size; + uint * p1 = table; + + #ifndef __GNUC__ + __asm + { + push ebx + push ecx + + mov ebx, [p1] + mov ecx, [c] + neg ecx + mov ecx, [b] + + ttmath_loop: + rcr dword ptr [ebx+ecx*4-4], 1 + + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop ecx + pop ebx + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ __volatile__( + + "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 + + "1: \n" + "rcrl $1, -4(%%ebx, %%ecx, 4) \n" + + "decl %%ecx \n" + "jnz 1b \n" + + "adcl %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + +#ifdef _MSC_VER +#pragma warning (disable : 4731) +//warning C4731: frame pointer register 'ebp' modified by inline assembly code +#endif + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits edx -> cf) (cl times) + "movl %%edx, %%ebp \n" // ebp = edx = mask + "movl %%esi, %%ecx \n" + + "xorl %%edx, %%edx \n" + "movl %%edx, %%esi \n" + "orl %%eax, %%eax \n" + "cmovnz %%ebp, %%esi \n" // if(c) esi=mask else esi=0 + + "1: \n" + "roll %%cl, (%%ebx,%%edx,4) \n" + + "movl (%%ebx,%%edx,4), %%eax \n" + "andl %%ebp, %%eax \n" + "xorl %%eax, (%%ebx,%%edx,4) \n" + "orl %%esi, (%%ebx,%%edx,4) \n" + "movl %%eax, %%esi \n" + + "incl %%edx \n" + "decl %%edi \n" + "jnz 1b \n" + + "and $1, %%eax \n" + + "pop %%ebp \n" + + : "=a" (c), "=D" (dummy), "=S" (dummy2), "=d" (dummy3) + : "0" (c), "1" (b), "b" (p1), "c" (bits) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2", c) + + return c; + } + + + + + /*! + this method moves all bits into the right hand side + C -> this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits + sint UInt::FindLeadingBitInWord(uint x) + { + sint result; + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx,-1 + bsr eax,[x] + cmovz eax,edx + mov [result], eax + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movl $-1, %1 \n" + "bsrl %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + return result; + } + + + + /* + this method returns the number of the smallest set bit in one 32-bit word + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + sint result; + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx,-1 + bsf eax,[x] + cmovz eax,edx + mov [result], eax + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movl $-1, %1 \n" + "bsfl %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + return result; + } + + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + bit is from <0,31> + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint old_bit; + uint v = value; + + #ifndef __GNUC__ + __asm + { + push ebx + push eax + + mov eax, [v] + mov ebx, [bit] + bts eax, ebx + mov [v], eax + + setc bl + movzx ebx, bl + mov [old_bit], ebx + + pop eax + pop ebx + } + #endif + + + #ifdef __GNUC__ + __asm__ ( + + "btsl %%ebx, %%eax \n" + "setc %%bl \n" + "movzx %%bl, %%ebx \n" + + : "=a" (v), "=b" (old_bit) + : "0" (v), "1" (bit) + : "cc" ); + + #endif + + value = v; + + return old_bit; + } + + + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + /* + we must use these temporary variables in order to inform the compilator + that value pointed with result1 and result2 has changed + + this has no effect in visual studio but it's useful when + using gcc and options like -Ox + */ + uint result1_; + uint result2_; + + #ifndef __GNUC__ + + __asm + { + push eax + push edx + + mov eax, [a] + mul dword ptr [b] + + mov [result2_], edx + mov [result1_], eax + + pop edx + pop eax + } + + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "mull %%edx \n" + + : "=a" (result1_), "=d" (result2_) + : "0" (a), "1" (b) + : "cc" ); + + #endif + + + *result_low = result1_; + *result_high = result2_; + } + + + + + + /*! + * + * Division + * + * + */ + + + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + * + * WARNING: + * if r (one word) is too small for the result or c is equal zero + * there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) + { + uint r_; + uint rest_; + /* + these variables have similar meaning like those in + the multiplication algorithm MulTwoWords + */ + + TTMATH_ASSERT( c != 0 ) + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx, [a] + mov eax, [b] + div dword ptr [c] + + mov [r_], eax + mov [rest_], edx + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "divl %%ecx \n" + + : "=a" (r_), "=d" (rest_) + : "0" (b), "1" (a), "c" (c) + : "cc" ); + + #endif + + + *r = r_; + *rest = rest_; + + } + + + +} //namespace + + + +#endif //ifdef TTMATH_PLATFORM32 +#endif //ifndef TTMATH_NOASM +#endif diff --git a/src/libghost/ttmath/ttmath/ttmathuint_x86_64.h b/src/libghost/ttmath/ttmath/ttmathuint_x86_64.h new file mode 100644 index 0000000..2fedb70 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathuint_x86_64.h @@ -0,0 +1,1222 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 COPYRIGHT OWNER 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. + */ + + +#ifndef headerfilettmathuint_x86_64 +#define headerfilettmathuint_x86_64 + + +#ifndef TTMATH_NOASM +#ifdef TTMATH_PLATFORM64 + + +/*! + \file ttmathuint_x86_64.h + \brief template class UInt with assembler code for 64bit x86_64 processors + + this file is included at the end of ttmathuint.h +*/ + +#ifdef _MSC_VER +#include +#endif + + +namespace ttmath +{ + + #ifdef _MSC_VER + + extern "C" + { + uint __fastcall ttmath_adc_x64(uint* p1, const uint* p2, uint nSize, uint c); + uint __fastcall ttmath_addindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); + uint __fastcall ttmath_addindexed2_x64(uint* p1, uint nSize, uint nPos, uint nValue1, uint nValue2); + uint __fastcall ttmath_addvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint __fastcall ttmath_sbb_x64(uint* p1, const uint* p2, uint nSize, uint c); + uint __fastcall ttmath_subindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); + uint __fastcall ttmath_subvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint __fastcall ttmath_rcl_x64(uint* p1, uint nSize, uint nLowestBit); + uint __fastcall ttmath_rcr_x64(uint* p1, uint nSize, uint nLowestBit); + uint __fastcall ttmath_div_x64(uint* pnValHi, uint* pnValLo, uint nDiv); + uint __fastcall ttmath_rcl2_x64(uint* p1, uint nSize, uint nBits, uint c); + uint __fastcall ttmath_rcr2_x64(uint* p1, uint nSize, uint nBits, uint c); + }; + #endif + + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifdef _MSC_VER + static const char info[] = "asm_vc_64"; + #endif + + #ifdef __GNUC__ + static const char info[] = "asm_gcc_64"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifdef _MSC_VER + LibTypeCode info = asm_vc_64; + #endif + + #ifdef __GNUC__ + LibTypeCode info = asm_gcc_64; + #endif + + return info; + } + + + /*! + * + * basic mathematic functions + * + */ + + + + /*! + this method adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + ***this method is created only on a 64bit platform*** + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + const uint * p2 = ss2.table; + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + #ifdef _MSC_VER + c = ttmath_adc_x64(p1,p2,b,c); + #endif + + #ifdef __GNUC__ + uint dummy, dummy2; + + /* + this part should be compiled with gcc + */ + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movq (%%rsi,%%rdx,8), %%rax \n" + "adcq %%rax, (%%rbx,%%rdx,8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Add", c) + + return c; + } + + + + /*! + this method adds one word (at a specific position) + and returns a carry (if it was) + + ***this method is created only on a 64bit platform*** + + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::AddInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addindexed_x64(p1,b,index,value); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "1: \n" + "addq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "movq $1, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rdx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddInt", c) + + return c; + } + + + + /*! + this method adds only two unsigned words to the existing value + and these words begin on the 'index' position + (it's used in the multiplication algorithm 2) + + ***this method is created only on a 64bit platform*** + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + for example if we've got value_size equal 4 and: + table[0] = 3 + table[1] = 4 + table[2] = 5 + table[3] = 6 + then let + x1 = 10 + x2 = 20 + and + index = 1 + + the result of this method will be: + table[0] = 3 + table[1] = 4 + x1 = 14 + table[2] = 5 + x2 = 25 + table[3] = 6 + + and no carry at the end of table[3] + + (of course if there was a carry in table[2](5+20) then + this carry would be passed to the table[3] etc.) + */ + template + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size - 1 ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addindexed2_x64(p1,b,index,x1,x2); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "addq %%rsi, (%%rbx,%%rdx,8) \n" + "incq %%rdx \n" + "decq %%rcx \n" + + "1: \n" + "adcq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "mov $0, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rax \n" + + : "=a" (c), "=c" (dummy), "=d" (dummy2) + : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddTwoInts", c) + + return c; + } + + + + /*! + this static method addes one vector to the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5+1 + 4 3 4+3 + 2 7 2+7 + 6 6 + 9 9 + of course the carry is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint c; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addvector_x64(ss1, ss2, ss1_size, ss2_size, result); + #endif + + + #ifdef __GNUC__ + uint dummy1, dummy2, dummy3; + uint rest = ss1_size - ss2_size; + + // this part should be compiled with gcc + + __asm__ __volatile__( + "mov %%rdx, %%r8 \n" + "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 + "1: \n" + "mov (%%rsi,%%rdx,8), %%rax \n" + "adc (%%rbx,%%rdx,8), %%rax \n" + "mov %%rax, (%%rdi,%%rdx,8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 1b \n" + + "adc %%rcx, %%rcx \n" // rcx has the cf state + + "or %%r8, %%r8 \n" + "jz 3f \n" + + "xor %%rbx, %%rbx \n" // ebx = 0 + "neg %%rcx \n" // setting cf from rcx + "mov %%r8, %%rcx \n" // rcx=rest and is != 0 + "2: \n" + "mov (%%rsi, %%rdx, 8), %%rax \n" + "adc %%rbx, %%rax \n" + "mov %%rax, (%%rdi, %%rdx, 8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 2b \n" + + "adc %%rcx, %%rcx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "%r8", "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) + + return c; + } + + + + /*! + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + ***this method is created only on a 64bit platform*** + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + const uint * p2 = ss2.table; + + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_sbb_x64(p1,p2,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movq (%%rsi,%%rdx,8), %%rax \n" + "sbbq %%rax, (%%rbx,%%rdx,8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Sub", c) + + return c; + } + + + + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + ***this method is created only on a 64bit platform*** + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::SubInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_subindexed_x64(p1,b,index,value); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "1: \n" + "subq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "movq $1, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rdx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::SubInt", c) + + return c; + } + + + /*! + this static method subtractes one vector from the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5-1 + 4 3 4-3 + 2 7 2-7 + 6 6-1 (the borrow from previous item) + 9 9 + return (carry): 0 + of course the carry (borrow) is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint c; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_subvector_x64(ss1, ss2, ss1_size, ss2_size, result); + #endif + + + #ifdef __GNUC__ + + // the asm code is nearly the same as in AddVector + // only two instructions 'adc' are changed to 'sbb' + + uint dummy1, dummy2, dummy3; + uint rest = ss1_size - ss2_size; + + __asm__ __volatile__( + "mov %%rdx, %%r8 \n" + "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 + "1: \n" + "mov (%%rsi,%%rdx,8), %%rax \n" + "sbb (%%rbx,%%rdx,8), %%rax \n" + "mov %%rax, (%%rdi,%%rdx,8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 1b \n" + + "adc %%rcx, %%rcx \n" // rcx has the cf state + + "or %%r8, %%r8 \n" + "jz 3f \n" + + "xor %%rbx, %%rbx \n" // ebx = 0 + "neg %%rcx \n" // setting cf from rcx + "mov %%r8, %%rcx \n" // rcx=rest and is != 0 + "2: \n" + "mov (%%rsi, %%rdx, 8), %%rax \n" + "sbb %%rbx, %%rax \n" + "mov %%rax, (%%rdi, %%rdx, 8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 2b \n" + + "adc %%rcx, %%rcx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "%r8", "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) + + return c; + } + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bit* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcl2_one(uint c) + { + sint b = value_size; + uint * p1 = table; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_rcl_x64(p1,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" // rdx=0 + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "rclq $1, (%%rbx, %%rdx, 8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2_one", c) + + return c; + } + + + /*! + this method moves all bits into the right hand side + c -> this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcr2_one(uint c) + { + sint b = value_size; + uint * p1 = table; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_rcr_x64(p1,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ __volatile__( + + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "rcrq $1, -8(%%rbx, %%rcx, 8) \n" + + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits + sint UInt::FindLeadingBitInWord(uint x) + { + sint result; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + unsigned long nIndex = 0; + + if( _BitScanReverse64(&nIndex,x) == 0 ) + result = -1; + else + result = nIndex; + + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movq $-1, %1 \n" + "bsrq %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + + return result; + } + + + /* + this method returns the number of the highest set bit in one 64-bit word + if the 'x' is zero this method returns '-1' + + ***this method is created only on a 64bit platform*** + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + sint result; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + unsigned long nIndex = 0; + + if( _BitScanForward64(&nIndex,x) == 0 ) + result = -1; + else + result = nIndex; + + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movq $-1, %1 \n" + "bsfq %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + + return result; + } + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + ***this method is created only on a 64bit platform*** + + bit is from <0,63> + + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint old_bit; + uint v = value; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + old_bit = _bittestandset64((__int64*)&value,bit) != 0; + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "btsq %%rbx, %%rax \n" + "setc %%bl \n" + "movzx %%bl, %%rbx \n" + + : "=a" (v), "=b" (old_bit) + : "0" (v), "1" (bit) + : "cc" ); + + #endif + + value = v; + + return old_bit; + } + + + /*! + * + * Multiplication + * + * + */ + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + + ***this method is created only on a 64bit platform*** + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + /* + we must use these temporary variables in order to inform the compilator + that value pointed with result1 and result2 has changed + + this has no effect in visual studio but it's usefull when + using gcc and options like -O + */ + uint result1_; + uint result2_; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + result1_ = _umul128(a,b,&result2_); + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "mulq %%rdx \n" + + : "=a" (result1_), "=d" (result2_) + : "0" (a), "1" (b) + : "cc" ); + + #endif + + + *result_low = result1_; + *result_high = result2_; + } + + + + + /*! + * + * Division + * + * + */ + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + ***this method is created only on a 64bit platform*** + + * + * WARNING: + * if r (one word) is too small for the result or c is equal zero + * there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest) + { + uint r_; + uint rest_; + /* + these variables have similar meaning like those in + the multiplication algorithm MulTwoWords + */ + + TTMATH_ASSERT( c != 0 ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + ttmath_div_x64(&a,&b,c); + r_ = a; + rest_ = b; + + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "divq %%rcx \n" + + : "=a" (r_), "=d" (rest_) + : "d" (a), "a" (b), "c" (c) + : "cc" ); + + #endif + + + *r = r_; + *rest = rest_; + } + +} //namespace + + +#endif //ifdef TTMATH_PLATFORM64 +#endif //ifndef TTMATH_NOASM +#endif + + diff --git a/src/libghost/ttmath/ttmath/ttmathuint_x86_64_msvc.asm b/src/libghost/ttmath/ttmath/ttmathuint_x86_64_msvc.asm new file mode 100644 index 0000000..d2ea969 --- /dev/null +++ b/src/libghost/ttmath/ttmath/ttmathuint_x86_64_msvc.asm @@ -0,0 +1,548 @@ +; +; This file is a part of TTMath Bignum Library +; and is distributed under the (new) BSD licence. +; Author: Christian Kaiser +; + +; +; Copyright (c) 2009, Christian Kaiser +; All rights reserved. +; +; 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. +; +; * Neither the name Christian Kaiser nor the names of contributors to this +; project may be used to endorse or promote products derived +; from this software without specific prior written permission. +; +; 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 COPYRIGHT OWNER 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. +; + +; +; compile with debug info: ml64.exe /Zd /Zi ttmathuint_x86_64_msvc.asm +; compile without debug info: ml64.exe ttmathuint_x86_64_msvc.asm +; this create ttmathuint_x86_64_msvc.obj file which can be linked with your program +; + +PUBLIC ttmath_adc_x64 +PUBLIC ttmath_addindexed_x64 +PUBLIC ttmath_addindexed2_x64 +PUBLIC ttmath_addvector_x64 + +PUBLIC ttmath_sbb_x64 +PUBLIC ttmath_subindexed_x64 +PUBLIC ttmath_subvector_x64 + +PUBLIC ttmath_rcl_x64 +PUBLIC ttmath_rcr_x64 + +PUBLIC ttmath_rcl2_x64 +PUBLIC ttmath_rcr2_x64 + +PUBLIC ttmath_div_x64 + +; +; Microsoft x86_64 convention: http://msdn.microsoft.com/en-us/library/9b372w95.aspx +; +; "rax, rcx, rdx, r8-r11 are volatile." +; "rbx, rbp, rdi, rsi, r12-r15 are nonvolatile." +; + + +.CODE + + + ALIGN 8 + +;---------------------------------------- + +ttmath_adc_x64 PROC + ; rcx = p1 + ; rdx = p2 + ; r8 = nSize + ; r9 = nCarry + + xor rax, rax + xor r11, r11 + sub rax, r9 ; sets CARRY if r9 != 0 + + ALIGN 16 + loop1: + mov rax,qword ptr [rdx + r11 * 8] + adc qword ptr [rcx + r11 * 8], rax + lea r11, [r11+1] + dec r8 + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_adc_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_addindexed_x64 PROC + + ; rcx = p1 + ; rdx = nSize + ; r8 = nPos + ; r9 = nValue + + xor rax, rax ; rax = result + sub rdx, r8 ; rdx = remaining count of uints + + add qword ptr [rcx + r8 * 8], r9 + jc next1 + + ret + +next1: + mov r9, 1 + + ALIGN 16 +loop1: + dec rdx + jz done_with_cy + lea r8, [r8+1] + add qword ptr [rcx + r8 * 8], r9 + jc loop1 + + ret + +done_with_cy: + lea rax, [rax+1] ; rax = 1 + + ret + +ttmath_addindexed_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_addindexed2_x64 PROC + + ; rcx = p1 (pointer) + ; rdx = b (value size) + ; r8 = nPos + ; r9 = nValue1 + ; [esp+0x28] = nValue2 + + xor rax, rax ; return value + mov r11, rcx ; table + sub rdx, r8 ; rdx = remaining count of uints + mov r10, [esp+028h] ; r10 = nValue2 + + add qword ptr [r11 + r8 * 8], r9 + lea r8, [r8+1] + lea rdx, [rdx-1] + adc qword ptr [r11 + r8 * 8], r10 + jc next + ret + + ALIGN 16 +loop1: + lea r8, [r8+1] + add qword ptr [r11 + r8 * 8], 1 + jc next + ret + +next: + dec rdx ; does not modify CY too... + jnz loop1 + lea rax, [rax+1] + ret + +ttmath_addindexed2_x64 ENDP + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + + +ttmath_addvector_x64 PROC + ; rcx = ss1 + ; rdx = ss2 + ; r8 = ss1_size + ; r9 = ss2_size + ; [esp+0x28] = result + + mov r10, [esp+028h] + sub r8, r9 + xor r11, r11 ; r11=0, cf=0 + + ALIGN 16 + loop1: + mov rax, qword ptr [rcx + r11 * 8] + adc rax, qword ptr [rdx + r11 * 8] + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r9 + jnz loop1 + + adc r9, r9 ; r9 has the cf state + + or r8, r8 + jz done + + neg r9 ; setting cf from r9 + mov r9, 0 ; don't use xor here (cf is used) + loop2: + mov rax, qword ptr [rcx + r11 * 8] + adc rax, r9 + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r8 + jnz loop2 + + adc r8, r8 + mov rax, r8 + + ret + +done: + mov rax, r9 + ret + +ttmath_addvector_x64 ENDP + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_sbb_x64 PROC + + ; rcx = p1 + ; rdx = p2 + ; r8 = nCount + ; r9 = nCarry + + xor rax, rax + xor r11, r11 + sub rax, r9 ; sets CARRY if r9 != 0 + + ALIGN 16 + loop1: + mov rax,qword ptr [rdx + r11 * 8] + sbb qword ptr [rcx + r11 * 8], rax + lea r11, [r11+1] + dec r8 + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_sbb_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_subindexed_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = nPos + ; r9 = nValue + + sub rdx, r8 ; rdx = remaining count of uints + + ALIGN 16 +loop1: + sub qword ptr [rcx + r8 * 8], r9 + jnc done + + lea r8, [r8+1] + mov r9, 1 + dec rdx + jnz loop1 + + mov rax, 1 + ret + +done: + xor rax, rax + ret + +ttmath_subindexed_x64 ENDP + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +; the same asm code as in addvector_x64 only two instructions 'adc' changed to 'sbb' + +ttmath_subvector_x64 PROC + ; rcx = ss1 + ; rdx = ss2 + ; r8 = ss1_size + ; r9 = ss2_size + ; [esp+0x28] = result + + mov r10, [esp+028h] + sub r8, r9 + xor r11, r11 ; r11=0, cf=0 + + ALIGN 16 + loop1: + mov rax, qword ptr [rcx + r11 * 8] + sbb rax, qword ptr [rdx + r11 * 8] + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r9 + jnz loop1 + + adc r9, r9 ; r9 has the cf state + + or r8, r8 + jz done + + neg r9 ; setting cf from r9 + mov r9, 0 ; don't use xor here (cf is used) + loop2: + mov rax, qword ptr [rcx + r11 * 8] + sbb rax, r9 + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r8 + jnz loop2 + + adc r8, r8 + mov rax, r8 + + ret + +done: + mov rax, r9 + ret + +ttmath_subvector_x64 ENDP + + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcl_x64 PROC + ; rcx = p1 + ; rdx = b + ; r8 = nLowestBit + + mov r11, rcx ; table + xor r10, r10 + neg r8 ; CY set if r8 <> 0 + + ALIGN 16 +loop1: + rcl qword ptr [r11 + r10 * 8], 1 + lea r10, [r10+1] + dec rdx + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_rcl_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcr_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = nLowestBit + + xor r10, r10 + neg r8 ; CY set if r8 <> 0 + + ALIGN 16 +loop1: + rcr qword ptr -8[rcx + rdx * 8], 1 + dec rdx + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_rcr_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_div_x64 PROC + + ; rcx = &Hi + ; rdx = &Lo + ; r8 = nDiv + + mov r11, rcx + mov r10, rdx + + mov rdx, qword ptr [r11] + mov rax, qword ptr [r10] + div r8 + mov qword ptr [r10], rdx ; remainder + mov qword ptr [r11], rax ; value + + ret + +ttmath_div_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcl2_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = bits + ; r9 = c + + push rbx + + mov r10, rcx ; r10 = p1 + xor rax, rax + + mov rcx, 64 + sub rcx, r8 + + mov r11, -1 + shr r11, cl ; r11 = mask + + mov rcx, r8 ; rcx = count of bits + + mov rbx, rax ; rbx = old value = 0 + or r9, r9 + cmovnz rbx, r11 ; if (c) then old value = mask + + mov r9, rax ; r9 = index (0..nSize-1) + + ALIGN 16 +loop1: + rol qword ptr [r10+r9*8], cl + mov rax, qword ptr [r10+r9*8] + and rax, r11 + xor qword ptr [r10+r9*8], rax + or qword ptr [r10+r9*8], rbx + mov rbx, rax + + lea r9, [r9+1] + dec rdx + + jnz loop1 + + and rax, 1 + pop rbx + ret + +ttmath_rcl2_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcr2_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = bits + ; r9 = c + + push rbx + mov r10, rcx ; r10 = p1 + xor rax, rax + + mov rcx, 64 + sub rcx, r8 + + mov r11, -1 + shl r11, cl ; r11 = mask + + mov rcx, r8 ; rcx = count of bits + + mov rbx, rax ; rbx = old value = 0 + or r9, r9 + cmovnz rbx, r11 ; if (c) then old value = mask + + mov r9, rdx ; r9 = index (0..nSize-1) + lea r9, [r9-1] + + ALIGN 16 +loop1: + ror qword ptr [r10+r9*8], cl + mov rax, qword ptr [r10+r9*8] + and rax, r11 + xor qword ptr [r10+r9*8], rax + or qword ptr [r10+r9*8], rbx + mov rbx, rax + + lea r9, [r9-1] + dec rdx + + jnz loop1 + + rol rax, 1 + and rax, 1 + pop rbx + + ret + +ttmath_rcr2_x64 ENDP + +END diff --git a/src/libghost/util.cpp b/src/libghost/util.cpp new file mode 100644 index 0000000..494e83b --- /dev/null +++ b/src/libghost/util.cpp @@ -0,0 +1,274 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#include "ghost.h" +#include "util.h" + +#include +#include +#include +#include +#include + +const QByteArray Util :: emptyByteArray16( 2, 0 ); +const QByteArray Util :: emptyByteArray32( 4, 0 ); + +quint16 Util::extractUInt16(const QByteArray& data, int offset) +{ + return qFromLittleEndian((uchar*)data.mid(offset, 2).data()); +} + +quint32 Util::extractUInt32(const QByteArray& data, int offset) +{ + return qFromLittleEndian((uchar*)data.mid(offset, 4).data()); +} + +QByteArray Util::fromUInt16(const quint16 &value) +{ + uchar dest[2]; + qToLittleEndian(value, dest); + return QByteArray((char*)dest, 2); +} + +QByteArray Util::fromUInt32(const quint32 &value) +{ + uchar dest[4]; + qToLittleEndian(value, dest); + return QByteArray((char*)dest, 4); +} + +QByteArray Util::reverse(const QByteArray &b) +{ + QByteArray res; + QByteArray::const_iterator it; + for (it = b.end() - 1; it == b.begin(); it--) + res.push_back(*it); + + return res; +} + +QString UTIL_QByteArrayToDecString( const QByteArray &b ) +{ + if( b.isEmpty( ) ) + return QString( ); + + QString result = QString::number( (unsigned char)b[0] ); + + for( QByteArray :: const_iterator i = b.begin( ) + 1; i != b.end( ); i++ ) + result += " " + QString::number( (unsigned char)*i ); + + return result; +} + +QByteArray UTIL_ExtractCString( const QByteArray &b, unsigned int start ) +{ + // start searching the byte array at position 'start' for the first null value + // if found, return the subarray from 'start' to the null value but not including the null value + + QString s(b.mid(start).data()); + return s.toUtf8(); +} + +unsigned char UTIL_ExtractHex( const QByteArray &b, unsigned int start, bool reverse ) +{ + // consider the byte array to contain a 2 character ASCII encoded hex value at b[start] and b[start + 1] e.g. "FF" + // extract it as a single decoded byte + + if (reverse) + return (unsigned char)(b.mid(start + 1, 1) + b.mid(start, 1)).toUShort(NULL, 16); + + return (unsigned char)b.mid(start, 2).toUShort(NULL, 16); +} + +QByteArray UTIL_ExtractNumbers( QString s, unsigned int count ) +{ + // consider the QString to contain a QByteArray in dec-text form, e.g. "52 99 128 1" + + QByteArray result; + unsigned int c; + QTextStream SS( &s, QIODevice::ReadOnly ); + + for( unsigned int i = 0; i < count; i++ ) + { + if( SS.atEnd() ) + break; + + SS >> c; + + // todotodo: if c > 255 handle the error instead of truncating + + result.push_back( (unsigned char)c ); + } + + return result; +} + +QByteArray UTIL_FileRead( const QString &file ) +{ + QFile f(file); + f.open(QFile::ReadOnly); + + if (f.error() != QFile::NoError) + { + CONSOLE_Print( "[UTIL] warning - unable to read file [" + file + "]" ); + return QByteArray(); + } + + return f.readAll(); +} + +bool UTIL_FileWrite( const QString &file, const QByteArray &data ) +{ + QFile f(file); + f.open(QFile::Truncate | QFile::WriteOnly); + + if (f.error() != QFile::NoError || !f.isWritable()) + { + CONSOLE_Print( "[UTIL] warning - unable to write file [" + file + "]" ); + return false; + } + + f.write(data); + return true; +} + +QString UTIL_FileSafeName( QString fileName ) +{ + return fileName.replace(QRegExp("\\\\\\/\\:\\*\\?\\<\\>\\|"), "_"); +} + +QString UTIL_AddPathSeparator( const QString &path ) +{ + if( path.isEmpty( ) ) + return path; + + if( path.right(1) == QDir::separator() ) + return path; + else + return path + QDir::separator(); +} + +QByteArray UTIL_EncodeStatString( const QByteArray &data ) +{ + unsigned char Mask = 1; + QByteArray Result; + + for( int i = 0; i < data.size( ); i++ ) + { + if( ( data[i] % 2 ) == 0 ) + Result.push_back( data[i] + 1 ); + else + { + Result.push_back( data[i] ); + Mask |= 1 << ( ( i % 7 ) + 1 ); + } + + if( i % 7 == 6 || i == data.size( ) - 1 ) + { + Result.insert( Result.size() - 1 - ( i % 7 ), Mask); + Mask = 1; + } + } + + return Result; +} + +bool UTIL_IsLanIP( const QByteArray &ip ) +{ + if( ip.size( ) != 4 ) + return false; + + // thanks to LuCasn for this function + + // 127.0.0.1 + if( ip.at(0) == 127 && ip.at(1) == 0 && ip.at(2) == 0 && ip.at(3) == 1 ) + return true; + + // 10.x.x.x + if( ip.at(0) == 10 ) + return true; + + // 172.16.0.0-172.31.255.255 + if( (unsigned char)ip.at(0) == 172 && ip.at(1) >= 16 && ip.at(1) <= 31 ) + return true; + + // 192.168.x.x + if( (unsigned char)ip.at(0) == 192 && (unsigned char)ip.at(1) == 168 ) + return true; + + // RFC 3330 and RFC 3927 automatic address range + if( (unsigned char)ip.at(0) == 169 && (unsigned char)ip.at(1) == 254 ) + return true; + + return false; +} + +bool UTIL_IsLocalIP( const QByteArray &ip, QList &localIPs ) +{ + if( ip.size( ) != 4 ) + return false; + + for( QList :: const_iterator i = localIPs.begin( ); i != localIPs.end( ); i++ ) + { + if( (*i).size( ) != 4 ) + continue; + + if( ip[0] == (*i)[0] && ip[1] == (*i)[1] && ip[2] == (*i)[2] && ip[3] == (*i)[3] ) + return true; + } + + return false; +} + +QList UTIL_Tokenize( const QString &s, char delim ) +{ + QList Tokens; + QString Token; + + for( QString :: const_iterator i = s.begin( ); i != s.end( ); i++ ) + { + if( *i == delim ) + { + if( Token.isEmpty( ) ) + continue; + + Tokens.push_back( Token ); + Token.clear( ); + } + else + Token += *i; + } + + if( !Token.isEmpty( ) ) + Tokens.push_back( Token ); + + return Tokens; +} + +quint32 UTIL_Factorial( quint32 x ) +{ + quint32 Factorial = 1; + + for( quint32 i = 2; i <= x; i++ ) + Factorial *= i; + + return Factorial; +} + diff --git a/src/libghost/util.h b/src/libghost/util.h new file mode 100644 index 0000000..0aa0d40 --- /dev/null +++ b/src/libghost/util.h @@ -0,0 +1,77 @@ +/* + + Copyright [2008] [Trevor Hogan] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/ + +*/ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include +#include + +class Util +{ +public: + static quint16 extractUInt16(const QByteArray& data, int offset = 0); + static quint32 extractUInt32(const QByteArray& data, int offset = 0); + + static QByteArray fromUInt16(const quint16 &value); + static QByteArray fromUInt32(const quint32 &value); + static const QByteArray &EmptyData16( ) { return emptyByteArray16; } + static const QByteArray &EmptyData32( ) { return emptyByteArray32; } + + static QByteArray reverse(const QByteArray &b); +private: + static const QByteArray emptyByteArray16; + static const QByteArray emptyByteArray32; +}; + +// byte arrays + +QString UTIL_QByteArrayToDecString( const QByteArray &b ); +QByteArray UTIL_ExtractCString( const QByteArray &b, unsigned int start ); +unsigned char UTIL_ExtractHex( const QByteArray &b, unsigned int start, bool reverse ); +QByteArray UTIL_ExtractNumbers( QString s, unsigned int count ); + +// files + +QByteArray UTIL_FileRead( const QString &file ); +bool UTIL_FileWrite( const QString &file, const QByteArray &data ); +QString UTIL_FileSafeName( QString fileName ); +QString UTIL_AddPathSeparator( const QString &path ); + +// stat strings + +QByteArray UTIL_EncodeStatString( const QByteArray &data ); + +// other + +bool UTIL_IsLanIP( const QByteArray &ip ); +bool UTIL_IsLocalIP( const QByteArray &ip, QList &localIPs ); +QList UTIL_Tokenize( const QString &s, char delim ); + +// math + +quint32 UTIL_Factorial( quint32 x ); + +#define nCr(n, r) (UTIL_Factorial(n) / UTIL_Factorial((n)-(r)) / UTIL_Factorial(r)) +#define nPr(n, r) (UTIL_Factorial(n) / UTIL_Factorial((n)-(r))) + +#endif diff --git a/ghost/w3g_actions.txt b/src/libghost/w3g_actions.txt similarity index 100% rename from ghost/w3g_actions.txt rename to src/libghost/w3g_actions.txt diff --git a/ghost/w3g_format.txt b/src/libghost/w3g_format.txt similarity index 100% rename from ghost/w3g_format.txt rename to src/libghost/w3g_format.txt diff --git a/src/plugins/cmd_builtin/cmd_builtin.pro b/src/plugins/cmd_builtin/cmd_builtin.pro new file mode 100755 index 0000000..2c0abd9 --- /dev/null +++ b/src/plugins/cmd_builtin/cmd_builtin.pro @@ -0,0 +1,12 @@ +! include( ../plugin.pri ) { + error( Couldn't find plugin.pri! ) +} + +QT += network #sql + +HEADERS = commands.h +SOURCES = commands.cpp +#TARGET = $$qtLibraryTarget(cmd_builtin) +TARGET = cmd_builtin + + diff --git a/src/plugins/cmd_builtin/commands.cpp b/src/plugins/cmd_builtin/commands.cpp new file mode 100644 index 0000000..29a7140 --- /dev/null +++ b/src/plugins/cmd_builtin/commands.cpp @@ -0,0 +1,77 @@ +/* + * commands.cpp + * ghost + * + * Created by Lucas on 08.05.10. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#include "commands.h" +#include "ghost.h" +#include "config.h" +#include "bnet.h" +#include "game.h" +#include "language.h" +#include +#include + +CCommands :: CCommands() +{ + m_SupportedCommands << "close"; +} + +QStringList CCommands :: GetCommands() const +{ + return m_SupportedCommands; +} + +void CCommands :: PluginLoaded( CGHost *ghost, CConfig *cfg ) +{ + m_GHost = ghost; +} + +void CCommands :: OnGameCommand( CBaseGame *game, CGamePlayer *player, const CommandData &data ) +{ + +} + +QString CCommands :: GetName( ) const +{ + return "Built-in commands"; +} + +void CCommands :: OnBNETCommand( CBNET *bnet, const QString &user, bool whisper, const CommandData &data ) +{ + if( data.GetCommand() == "close" && !data.GetCommand().isEmpty( ) && m_GHost->GetCurrentGame() ) + { + if( !m_GHost->GetCurrentGame()->GetLocked( ) ) + { + // close as many slots as specified, e.g. "5 10" closes slots 5 and 10 + + QTextStream SS; + SS << data.GetPayload(); + + while( !SS.atEnd() ) + { + quint32 SID; + SS >> SID; + + if( SS.status() != QTextStream::Ok ) + { + //CONSOLE_Print( "[BNET: " + bnet->GetServerAlias() + "] bad input to close command" ); + break; + } + else + m_GHost->GetCurrentGame()->CloseSlot( (unsigned char)( SID - 1 ), true ); + } + } + else + { + //m_GHost->m_Language->TheGameIsLockedBNET(); + bnet->QueueChatCommand( QString(), user, whisper ); + } + } +} + +Q_EXPORT_PLUGIN2(cmd_builtin, CCommands) diff --git a/src/plugins/cmd_builtin/commands.h b/src/plugins/cmd_builtin/commands.h new file mode 100644 index 0000000..5a864cc --- /dev/null +++ b/src/plugins/cmd_builtin/commands.h @@ -0,0 +1,68 @@ +/* + * commands.h + * ghost + * + * Created by Lucas on 08.05.10. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef COMMANDS_H +#define COMMANDS_H + +#include +#include "interfaces.h" + +class CGHost; +class CGameBase; +class CGame; +class CommandData; +class CGamePlayer; +class CBNET; + +class CCommand { + public: + virtual int operator()(const QString &payload) = 0; + }; + +class CGameCommand { +protected: + CGHost *m_GHost; +public: + CGameCommand(CGHost *ghost) : m_GHost(ghost) {} + virtual int operator()(CGameBase *game, CGamePlayer *player, const QString &payload); +}; + +class CKickCommand : public CGameCommand +{ +public: + int operator()(const QString &payload) + { + + } +}; + +template + void CallGameCommand(FunctObj f, const QString &payload) + { + f( payload ); + } + +class CCommands : public QObject, public ICommandProvider +{ + Q_OBJECT + Q_INTERFACES(ICommandProvider) + Q_INTERFACES(IGHostPlugin) +private: + CGHost *m_GHost; + QStringList m_SupportedCommands; +public: + CCommands(); + virtual QString GetName() const; + QStringList GetCommands() const; + virtual void PluginLoaded( CGHost *ghost, CConfig *cfg ); + virtual void OnGameCommand( CBaseGame *game, CGamePlayer *player, const CommandData &data ); + virtual void OnBNETCommand( CBNET *bnet, const QString &user, bool whisper, const CommandData &data ); +}; + +#endif diff --git a/src/plugins/plugin.pri b/src/plugins/plugin.pri new file mode 100644 index 0000000..19fbc07 --- /dev/null +++ b/src/plugins/plugin.pri @@ -0,0 +1,13 @@ +QT -= gui +TEMPLATE = lib +CONFIG += plugin debug_and_release #link_prl + +LIBS += -lghost -lbncsutil -lgmp -L/usr/lib -L../../../lib +macx { + LIBS += -lz +CONFIG += x86_64 x86 +QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.5.sdk +} + +INCLUDEPATH += ../../libghost +DESTDIR = ../../../bin/plugins diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro new file mode 100644 index 0000000..677d76e --- /dev/null +++ b/src/plugins/plugins.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = cmd_builtin rcon \ No newline at end of file diff --git a/src/plugins/rcon/rcon.cpp b/src/plugins/rcon/rcon.cpp new file mode 100644 index 0000000..1afe2ba --- /dev/null +++ b/src/plugins/rcon/rcon.cpp @@ -0,0 +1,441 @@ +/* + * rcon.cpp + * + * Copyright 2008-2010 Lucas Romero + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "ghost.h" +#include "config.h" +#include "bnet.h" +#include "game.h" +#include "language.h" +#include +#include +#include +#include "rcon.h" +#include "config.h" +#include "gameplayer.h" +#include "bnetprotocol.h" +#include "util.h" +#include "game_base.h" +#include "gameprotocol.h" + +CRemoteConsole :: CRemoteConsole( ) +{ + CONSOLE_Print( "[RCON] Remote Console 1.5 loading" ); + m_UDPSocket = new QUdpSocket(this); + connect(m_UDPSocket, SIGNAL(readyRead()), + this, SLOT(readPendingDatagrams())); + // lookup "localhost" for later use + //bool lookup_success = (inet_aton("localhost", &localhost) == 1); +} + +CRemoteConsole :: ~CRemoteConsole( ) +{ + for( QList :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); i++ ) + { + delete *i; + } +} + +QString CRemoteConsole :: GetName() const +{ + return "Remote Console"; +} + +void CRemoteConsole :: PluginLoaded( CGHost *ghost, CConfig *cfg ) +{ + m_GHost = ghost; + QString bindto = cfg->GetString( "rcon_bindto", "255.255.255.255" ); + qint32 port = cfg->GetInt( "rcon_port", 6969 ); + m_Password = cfg->GetString( "rcon_password", "lol" ); + m_Timeout = cfg->GetInt( "rcon_timeout", 10 ); + m_KeepAliveTime = cfg->GetInt( "rcon_keepalivetime", 120 ); + m_KeepAliveInterval = cfg->GetInt( "rcon_keepaliveinterval", 2 ); + m_AnonymousBroadcast = cfg->GetInt( "rcon_anonymousbroadcast", 0 ) == 0 ? false : true; + m_AnonymousAdminGame = cfg->GetInt( "rcon_anonymousadmingame", 0 ) == 0 ? false : true; + + QHostAddress bindAddr( bindto ); + + if( m_Password.isEmpty( ) ) + { + bindAddr = QHostAddress::LocalHost; + CONSOLE_Print("[RCON] WARNING: No rcon_password set in the .cfg file! Only local commands allowed!"); + } + // we are all set, lets create our socket + + + // TODO: bind correctly + if( !m_UDPSocket->bind( bindAddr, port ) ) + { + CONSOLE_Print( "[RCON] ERROR: Could not bind to [" + bindto + "] on port [" + QString :: number( port ) + "]" ); + } + else + { + CONSOLE_Print( "[RCON] Listening at [" + bindto + "] on port [" + QString :: number( port ) + "]" ); + //disabled for now + /*if( m_AnonymousBroadcast ) + CONSOLE_Print( "[RCON] Anonymous broadcasting [enabled]" ); + else + CONSOLE_Print( "[RCON] Anonymous broadcasting [disabled]" ); + if( m_AnonymousAdminGame ) + CONSOLE_Print( "[RCON] Anonymous Admin game [enabled]" ); + else + CONSOLE_Print( "[RCON] Anonymous Admin game [disabled]" );*/ + } +} + +void CRemoteConsole :: readPendingDatagrams() +{ + while (m_UDPSocket->hasPendingDatagrams()) { + QByteArray datagram; + datagram.resize(m_UDPSocket->pendingDatagramSize()); + QHostAddress sender; + quint16 senderPort; + + m_UDPSocket->readDatagram(datagram.data(), datagram.size(), + &sender, &senderPort); + ProcessPacket( datagram, sender, senderPort ); + // echo + m_UDPSocket->writeDatagram(datagram.data(), sender, senderPort); + } +} + +void CRemoteConsole :: ProcessPacket( const QByteArray &data, const QHostAddress &sender, const quint16 &senderPort ) +{ + QString message( data ); + message = message.trimmed(); + + if (!message.isEmpty()) + { + QString cmd; + QString payload; + QString target; + SplitLine( message, cmd, payload, target ); + + CRemoteConsoleClient *client = NULL; + for( QList :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); i++ ) + { + if( (*i)->GetAddress( ) == sender && (*i)->GetPort() == senderPort ) + { + client = *i; + // update LastReceived time + //client->Pong( ); + break; + } + } + } + + for( QList :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); ) + { + //(*i)->AutoBroadcast( m_GHost->m_CurrentGame, m_GHost->m_AdminGame ); + + /*if( GetTime( ) > (*i)->GetLastReceived( ) + m_KeepAliveTime + m_Timeout && (*i)->IsAuthed( ) ) + { + // user has not responded in time, de-auth him + (*i)->SetAuthed( false ); + (*i)->Send( "[RCON] Your session timed out" ); + CONSOLE_Print("[RCON] User [" + (*i)->GetIPString( ) + "] timed out"); + } + else if( GetTime( ) > (*i)->GetLastReceived( ) + m_KeepAliveTime + && GetTime( ) > (*i)->GetLastPinged( ) + m_KeepAliveInterval ) + { + // user has not sent an command in quite some time, send him a keep-alive packet (containing the word "PING") + (*i)->Ping( ); + } + + if ( !(*i)->IsAuthed( ) && !(*i)->IsBanned( ) ) + { + delete *i; + i = m_KnownClients.erase( i ); + } + else + i++;*/ + } +} + +void CRemoteConsole :: LogInfo( const QString &message ) +{ + Send( message ); +} + +void CRemoteConsole :: LogWarning( const QString &message ) +{ + Send( message ); +} + +void CRemoteConsole :: LogError( const QString &message ) +{ + Send( message ); +} + +/*bool CRemoteConsole :: Update( void *fd ) +{ + if( !m_Socket ) + return true; + sockaddr_in recvAddr; + string recvString; + m_Socket->RecvFrom( (fd_set *)fd, &recvAddr, &recvString); + + if( !recvString.empty( ) ) + { + // erase newline if found + if ( recvString[recvString.size()-1] == '\n' ) + recvString.erase( recvString.size()-1, 1 ); + string cmd, payload, target = ""; + SplitLine( recvString, cmd, payload, target ); + CRemoteConsoleClient *client = NULL; + for( vector :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); i++ ) + { + if( AreEqual( (*i)->GetEndPoint( ), &recvAddr , true) ) + { + client = *i; + // update LastReceived time + client->Pong( ); + break; + } + } + + if( !client ) + { + // client is not known yet + if( recvAddr.sin_addr.s_addr == localhost.s_addr || ( !m_Password.empty( ) && cmd == "rcon_password" && payload == m_Password ) ) + { + // client has authed himself + client = new CRemoteConsoleClient( m_Socket, recvAddr, -1, true ); + client->Send( "[RCON] You are now authed" ); + CONSOLE_Print("[RCON] User [" + client->GetIPString( ) + "] is now authorized"); + m_KnownClients.push_back( client ); + } + else if( cmd == "rcon_broadcast" && payload.empty( ) ) + { + bool authorized = false; + if( !authorized ) + for( vector :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); i++ ) + { + // only respond if IP is already connected and authed as rcon user + if( AreEqual( (*i)->GetEndPoint( ), &recvAddr, false ) && (*i)->IsAuthed( ) ) + { + authorized = true; + break; + } + } + if( authorized || m_AnonymousBroadcast ) + { + if( m_GHost->m_CurrentGame ) + m_GHost->m_CurrentGame->SendGame( m_Socket, recvAddr ); + + if( m_GHost->m_AdminGame && ( authorized || m_AnonymousAdminGame ) ) + m_GHost->m_AdminGame->SendGame( m_Socket, recvAddr ); + } + else + { + // ban client for 5 seconds for not being authorized + client = new CRemoteConsoleClient( m_Socket, recvAddr, 5 , false); + m_KnownClients.push_back( client ); + CONSOLE_Print("[RCON] User [" + client->GetIPString( ) + "] is not allowed to receive broadcasts"); + } + } + else + { + // ban client for 5 seconds for sending an unkown command or the wrong password + client = new CRemoteConsoleClient( m_Socket, recvAddr, 5, false ); + m_KnownClients.push_back( client ); + CONSOLE_Print("[RCON] User [" + client->GetIPString( ) + "] failed to authenticate"); + } + } + else if( client->IsBanned( ) ) + { + // we have seen this user before, but he is banned + CONSOLE_Print("[RCON] Banned user [" + client->GetIPString( ) + "] tried to execute command [" + recvString + "]"); + } + else if( !client->IsAuthed( ) ) + { + // we have seen this user before, but he hasn't provided the right login credentials yet + if( !m_Password.empty( ) && cmd == "rcon_password" && payload == m_Password ) + { + client->Send( "[RCON] You are now authed" ); + CONSOLE_Print("[RCON] User [" + client->GetIPString( ) + "] is now authorized"); + client->SetAuthed( true ); + } + else + { + // ban client for 5 seconds for sending an unkown command or the wrong password + client->Ban( 5 ); + CONSOLE_Print("[RCON] User [" + client->GetIPString( ) + "] failed to authenticate"); + } + } + else if( cmd == "rcon_password" ) + { + // client is already authed and tries to auth again, just tell him he is now authed + client->Send( "[RCON] You are now authed" ); + } + else if( cmd == "rcon_sendlobbychat" ) + { + if ( m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetGameLoading( ) && !m_GHost->m_CurrentGame->GetGameLoaded( ) ) + m_GHost->m_CurrentGame->SendAllChat( payload ); + } + else if( cmd == "rcon_kick" ) + { + if ( m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetGameLoading( ) && !m_GHost->m_CurrentGame->GetGameLoaded( ) ) + { + CGamePlayer *player = m_GHost->m_CurrentGame->GetPlayerFromName( payload, true ); + if( player ) + { + player->SetDeleteMe( true ); + player->SetLeftReason( m_GHost->m_Language->WasKickedByPlayer( "Remote Console" ) ); + player->SetLeftCode( PLAYERLEAVE_LOBBY ); + m_GHost->m_CurrentGame->OpenSlot( m_GHost->m_CurrentGame->GetSIDFromPID( player->GetPID( ) ), false ); + } + } + } + // disabled for now + //else if( cmd == "rcon_gamedetails" ) + //{ + // if( m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetGameLoading( ) && !m_GHost->m_CurrentGame->GetGameLoaded( ) ) + // client->Send( "[RCON] Game details: " + m_GHost->m_CurrentGame->GetGameDetails( ) ); + // else + // client->Send( "[RCON] Game details: no game in lobby" ); + //} + //else + if( !cmd.empty( ) ) + { + // this is a legitimate user, do what he says + ProcessInput( cmd, payload, target, client ); + } + } + + for( vector :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); ) + { + //(*i)->AutoBroadcast( m_GHost->m_CurrentGame, m_GHost->m_AdminGame ); + + if( GetTime( ) > (*i)->GetLastReceived( ) + m_KeepAliveTime + m_Timeout && (*i)->IsAuthed( ) ) + { + // user has not responded in time, de-auth him + (*i)->SetAuthed( false ); + (*i)->Send( "[RCON] Your session timed out" ); + CONSOLE_Print("[RCON] User [" + (*i)->GetIPString( ) + "] timed out"); + } + else if( GetTime( ) > (*i)->GetLastReceived( ) + m_KeepAliveTime + && GetTime( ) > (*i)->GetLastPinged( ) + m_KeepAliveInterval ) + { + // user has not sent an command in quite some time, send him a keep-alive packet (containing the word "PING") + (*i)->Ping( ); + } + + if ( !(*i)->IsAuthed( ) && !(*i)->IsBanned( ) ) + { + delete *i; + i = m_KnownClients.erase( i ); + } + else + i++; + } + + return false; +}*/ + +void CRemoteConsole :: SplitLine( const QString &input, QString &command, QString &payload, QString &target ) +{ + int pos; + QString Message = input; + // has the user specified a specific target the command should be sent to? + // looks for "" at the beginning of the received command, + // sets the target accordingly and strips it from the command + if ( input.indexOf("<") == 0 && (pos=input.indexOf(">")) != -1 ) + { + target = input.mid(1, pos - 1); + Message = input.mid( pos+1 ); + //input.erase(0, pos + 1); + } + // we expect commands not to start with the command trigger because this is a commandsocket, + // we only except commands and therefore know we received one and not some chatting + // this way the user sending the command does not have to have knowledge of the commandtrigger + // set in GHost's config file + + + int PayloadStart = Message.indexOf( " " ); + + if( PayloadStart != -1 ) + { + command = Message.mid( 0, PayloadStart ); + payload = Message.mid( PayloadStart + 1 ); + } + else + command = Message; +} + +/*void CRemoteConsole :: ProcessInput( string cmd, string payload, string target, CRemoteConsoleClient *sender ) +{ + // default server to relay the message to + bool relayed = false; + + // loop through all connections to find the server the command should be issued on + for( vector :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ ) + { + // is this the right one or should we just send it to the first in list? + if ( target == (*i)->GetServer( ) || target.empty() ) + { + // don't be so verbose! + //CONSOLE_Print("[RCON] Relaying command [" + cmd + "] with payload [" + payload + "] to server [" + (*i)->GetServer( ) + "]"); + // spoof a whisper from the rootadmin belonging to this connection + string msg = (*i)->GetCommandTrigger( ) + cmd; + if( !payload.empty( ) ) + msg += " " + payload; + CIncomingChatEvent chatCommand( CBNETProtocol::EID_WHISPER, 0, (*i)->GetRootAdmin( ), msg); + (*i)->ProcessChatEvent( &chatCommand ); + relayed = true; + break; + } + } + if (!relayed) + CONSOLE_Print("[RCON] Could not relay cmd [" + cmd + "] with payload [" + payload + "] to server [" + target + "]: server unknown"); +}*/ + +void CRemoteConsole :: Send( const QString &message ) +{ + QByteArray datagram; + QDataStream out( &datagram, QIODevice::WriteOnly ); + out << message; + for( QList :: iterator i = m_KnownClients.begin( ); i != m_KnownClients.end( ); i++ ) + { + // relay message to all unbanned clients + if( !(*i)->IsBanned( ) && (*i)->IsAuthed( ) ) + m_UDPSocket->writeDatagram( datagram, (*i)->GetAddress( ), (*i)->GetPort( ) ); + } +} + +/*bool CRemoteConsole :: AreEqual( const struct sockaddr_in *a, const struct sockaddr_in *b, bool checkports ) +{ + return a->sin_family == b->sin_family && + a->sin_addr.s_addr == b->sin_addr.s_addr && + ( !checkports || a->sin_port == b->sin_port ); +}*/ + +CRemoteConsoleClient :: CRemoteConsoleClient( const CRemoteConsole &rcon, const QHostAddress &address, quint16 port, int banTime, bool authed ) : +m_RCon( rcon ), +m_Address( address ), +m_Port( port ), +m_LastReceived( 0 ), +m_LastPinged( 0 ), +m_Authed( authed ) +{ + Ban( banTime ); +} + +Q_EXPORT_PLUGIN2(cmd_builtin, CRemoteConsole) diff --git a/src/plugins/rcon/rcon.h b/src/plugins/rcon/rcon.h new file mode 100644 index 0000000..e6814f2 --- /dev/null +++ b/src/plugins/rcon/rcon.h @@ -0,0 +1,88 @@ +/* + * commands.h + * ghost + * + * Created by Lucas on 08.05.10. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ +#ifndef RCON_H +#define RCON_H + +#include +#include "interfaces.h" +#include +//#include "ghost.h" + +QT_FORWARD_DECLARE_CLASS(QUdpSocket) +class CConfig; +class CGHost; +class CRemoteConsole; + +class CRemoteConsoleClient +{ +public: + CRemoteConsoleClient( const CRemoteConsole &rcon, const QHostAddress &address, quint16 port, qint32 banTime, bool authed ); + + //virtual void Ping( ) { m_LastPinged = 000; } + //virtual void Pong( ) { m_LastReceived = 000; } + + virtual void Ban( int seconds ) { m_BannedUntil = 000 + seconds; } + virtual bool IsBanned( ) const { return false; } + virtual void UnBan( ) { m_BannedUntil = 0; } + + virtual bool IsAuthed( ) const { return m_Authed; } + virtual void SetAuthed( bool authed ) { m_Authed = authed; } + + virtual const time_t &GetLastPinged( ) const { return m_LastPinged; } + virtual const time_t &GetLastReceived( ) const { return m_LastReceived; } + + virtual const QHostAddress &GetAddress( ) const { return m_Address; } + virtual const quint16 &GetPort( ) const { return m_Port; } + //virtual bool hasAddress(const QHostAddress &a, const quint16 &port) { return m_Address == a && m_Port == port; } + //virtual void Send( const QString &message ) { } +private: + const CRemoteConsole &m_RCon; + QHostAddress m_Address; + quint16 m_Port; + time_t m_LastReceived; + time_t m_LastPinged; + time_t m_BannedUntil; + bool m_Authed; +}; + +class CRemoteConsole : public QObject, public ILogPlugin +{ + Q_OBJECT + Q_INTERFACES(IGHostPlugin) + Q_INTERFACES(ILogPlugin) +public: + virtual void LogInfo( const QString &message ); + virtual void LogWarning( const QString &message ); + virtual void LogError( const QString &message ); +private slots: + void readPendingDatagrams(); +public: + CRemoteConsole( ); + virtual ~CRemoteConsole( ); + virtual QString GetName() const; + virtual void Send( const QString &message ); // output a message to all authed clients + virtual void PluginLoaded( CGHost *ghost, CConfig *cfg ); + //virtual void ConsoleOutput( const QString &message ); +private: + CGHost *m_GHost; // our parent + QUdpSocket *m_UDPSocket; // the socket we use to communicate + QString m_Password; // the password users need to authenticate themselves with + bool m_AnonymousBroadcast; // should everyone requesting a LAN broadcast packet be granted their wish? + bool m_AnonymousAdminGame; // should the admin game also be broadcasted to anonymous requesters? + int m_KeepAliveTime; // time that has to pass before we start asking the client if he is still there + int m_KeepAliveInterval; // time to wait between ping packets when asking if client is still there + int m_Timeout; // time in which the client has to repond to our ping(s) + QList m_KnownClients; // all our console clients (includes authed but banned clients) + void Send( const QString &message, CRemoteConsoleClient *client ); // output a message only to a specific client + static void SplitLine( const QString &input, QString &command, QString &payload, QString &target ); // splits a line received by the rcon socket up into pieces + void ProcessPacket( const QByteArray &data, const QHostAddress &sender, const quint16 &senderPort ); + //virtual void ProcessInput( string cmd, string payload, string target, CRemoteConsoleClient *sender ); // does the actual action based on rcon input +}; + +#endif diff --git a/src/plugins/rcon/rcon.pro b/src/plugins/rcon/rcon.pro new file mode 100755 index 0000000..eb6bf17 --- /dev/null +++ b/src/plugins/rcon/rcon.pro @@ -0,0 +1,11 @@ +! include( ../plugin.pri ) { + error( Couldn't find plugin.pri! ) +} + +QT += network #sql + +HEADERS = rcon.h +SOURCES = rcon.cpp +TARGET = rcon + + diff --git a/update_dota_elo/Makefile b/src/update_dota_elo/Makefile similarity index 100% rename from update_dota_elo/Makefile rename to src/update_dota_elo/Makefile diff --git a/update_dota_elo/elo.cpp b/src/update_dota_elo/elo.cpp similarity index 100% rename from update_dota_elo/elo.cpp rename to src/update_dota_elo/elo.cpp diff --git a/update_dota_elo/elo.h b/src/update_dota_elo/elo.h similarity index 100% rename from update_dota_elo/elo.h rename to src/update_dota_elo/elo.h diff --git a/update_dota_elo/update_dota_elo.cpp b/src/update_dota_elo/update_dota_elo.cpp similarity index 100% rename from update_dota_elo/update_dota_elo.cpp rename to src/update_dota_elo/update_dota_elo.cpp diff --git a/update_dota_elo/update_dota_elo.vcproj b/src/update_dota_elo/update_dota_elo.vcproj similarity index 100% rename from update_dota_elo/update_dota_elo.vcproj rename to src/update_dota_elo/update_dota_elo.vcproj diff --git a/update_w3mmd_elo/Makefile b/src/update_w3mmd_elo/Makefile similarity index 100% rename from update_w3mmd_elo/Makefile rename to src/update_w3mmd_elo/Makefile diff --git a/update_w3mmd_elo/elo.cpp b/src/update_w3mmd_elo/elo.cpp similarity index 100% rename from update_w3mmd_elo/elo.cpp rename to src/update_w3mmd_elo/elo.cpp diff --git a/update_w3mmd_elo/elo.h b/src/update_w3mmd_elo/elo.h similarity index 100% rename from update_w3mmd_elo/elo.h rename to src/update_w3mmd_elo/elo.h diff --git a/update_w3mmd_elo/update_w3mmd_elo.cpp b/src/update_w3mmd_elo/update_w3mmd_elo.cpp similarity index 100% rename from update_w3mmd_elo/update_w3mmd_elo.cpp rename to src/update_w3mmd_elo/update_w3mmd_elo.cpp diff --git a/update_w3mmd_elo/update_w3mmd_elo.vcproj b/src/update_w3mmd_elo/update_w3mmd_elo.vcproj similarity index 100% rename from update_w3mmd_elo/update_w3mmd_elo.vcproj rename to src/update_w3mmd_elo/update_w3mmd_elo.vcproj diff --git a/zlib/DLL_FAQ.txt b/zlib/DLL_FAQ.txt deleted file mode 100644 index ad4286f..0000000 --- a/zlib/DLL_FAQ.txt +++ /dev/null @@ -1,397 +0,0 @@ - - Frequently Asked Questions about ZLIB1.DLL - - -This document describes the design, the rationale, and the usage -of the official DLL build of zlib, named ZLIB1.DLL. If you have -general questions about zlib, you should see the file "FAQ" found -in the zlib distribution, or at the following location: - http://www.gzip.org/zlib/zlib_faq.html - - - 1. What is ZLIB1.DLL, and how can I get it? - - - ZLIB1.DLL is the official build of zlib as a DLL. - (Please remark the character '1' in the name.) - - Pointers to a precompiled ZLIB1.DLL can be found in the zlib - web site at: - http://www.zlib.org/ - - Applications that link to ZLIB1.DLL can rely on the following - specification: - - * The exported symbols are exclusively defined in the source - files "zlib.h" and "zlib.def", found in an official zlib - source distribution. - * The symbols are exported by name, not by ordinal. - * The exported names are undecorated. - * The calling convention of functions is "C" (CDECL). - * The ZLIB1.DLL binary is linked to MSVCRT.DLL. - - The archive in which ZLIB1.DLL is bundled contains compiled - test programs that must run with a valid build of ZLIB1.DLL. - It is recommended to download the prebuilt DLL from the zlib - web site, instead of building it yourself, to avoid potential - incompatibilities that could be introduced by your compiler - and build settings. If you do build the DLL yourself, please - make sure that it complies with all the above requirements, - and it runs with the precompiled test programs, bundled with - the original ZLIB1.DLL distribution. - - If, for any reason, you need to build an incompatible DLL, - please use a different file name. - - - 2. Why did you change the name of the DLL to ZLIB1.DLL? - What happened to the old ZLIB.DLL? - - - The old ZLIB.DLL, built from zlib-1.1.4 or earlier, required - compilation settings that were incompatible to those used by - a static build. The DLL settings were supposed to be enabled - by defining the macro ZLIB_DLL, before including "zlib.h". - Incorrect handling of this macro was silently accepted at - build time, resulting in two major problems: - - * ZLIB_DLL was missing from the old makefile. When building - the DLL, not all people added it to the build options. In - consequence, incompatible incarnations of ZLIB.DLL started - to circulate around the net. - - * When switching from using the static library to using the - DLL, applications had to define the ZLIB_DLL macro and - to recompile all the sources that contained calls to zlib - functions. Failure to do so resulted in creating binaries - that were unable to run with the official ZLIB.DLL build. - - The only possible solution that we could foresee was to make - a binary-incompatible change in the DLL interface, in order to - remove the dependency on the ZLIB_DLL macro, and to release - the new DLL under a different name. - - We chose the name ZLIB1.DLL, where '1' indicates the major - zlib version number. We hope that we will not have to break - the binary compatibility again, at least not as long as the - zlib-1.x series will last. - - There is still a ZLIB_DLL macro, that can trigger a more - efficient build and use of the DLL, but compatibility no - longer dependents on it. - - - 3. Can I build ZLIB.DLL from the new zlib sources, and replace - an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier? - - - In principle, you can do it by assigning calling convention - keywords to the macros ZEXPORT and ZEXPORTVA. In practice, - it depends on what you mean by "an old ZLIB.DLL", because the - old DLL exists in several mutually-incompatible versions. - You have to find out first what kind of calling convention is - being used in your particular ZLIB.DLL build, and to use the - same one in the new build. If you don't know what this is all - about, you might be better off if you would just leave the old - DLL intact. - - - 4. Can I compile my application using the new zlib interface, and - link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or - earlier? - - - The official answer is "no"; the real answer depends again on - what kind of ZLIB.DLL you have. Even if you are lucky, this - course of action is unreliable. - - If you rebuild your application and you intend to use a newer - version of zlib (post- 1.1.4), it is strongly recommended to - link it to the new ZLIB1.DLL. - - - 5. Why are the zlib symbols exported by name, and not by ordinal? - - - Although exporting symbols by ordinal is a little faster, it - is risky. Any single glitch in the maintenance or use of the - DEF file that contains the ordinals can result in incompatible - builds and frustrating crashes. Simply put, the benefits of - exporting symbols by ordinal do not justify the risks. - - Technically, it should be possible to maintain ordinals in - the DEF file, and still export the symbols by name. Ordinals - exist in every DLL, and even if the dynamic linking performed - at the DLL startup is searching for names, ordinals serve as - hints, for a faster name lookup. However, if the DEF file - contains ordinals, the Microsoft linker automatically builds - an implib that will cause the executables linked to it to use - those ordinals, and not the names. It is interesting to - notice that the GNU linker for Win32 does not suffer from this - problem. - - It is possible to avoid the DEF file if the exported symbols - are accompanied by a "__declspec(dllexport)" attribute in the - source files. You can do this in zlib by predefining the - ZLIB_DLL macro. - - - 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling - convention. Why not use the STDCALL convention? - STDCALL is the standard convention in Win32, and I need it in - my Visual Basic project! - - (For readability, we use CDECL to refer to the convention - triggered by the "__cdecl" keyword, STDCALL to refer to - the convention triggered by "__stdcall", and FASTCALL to - refer to the convention triggered by "__fastcall".) - - - Most of the native Windows API functions (without varargs) use - indeed the WINAPI convention (which translates to STDCALL in - Win32), but the standard C functions use CDECL. If a user - application is intrinsically tied to the Windows API (e.g. - it calls native Windows API functions such as CreateFile()), - sometimes it makes sense to decorate its own functions with - WINAPI. But if ANSI C or POSIX portability is a goal (e.g. - it calls standard C functions such as fopen()), it is not a - sound decision to request the inclusion of , or to - use non-ANSI constructs, for the sole purpose to make the user - functions STDCALL-able. - - The functionality offered by zlib is not in the category of - "Windows functionality", but is more like "C functionality". - - Technically, STDCALL is not bad; in fact, it is slightly - faster than CDECL, and it works with variable-argument - functions, just like CDECL. It is unfortunate that, in spite - of using STDCALL in the Windows API, it is not the default - convention used by the C compilers that run under Windows. - The roots of the problem reside deep inside the unsafety of - the K&R-style function prototypes, where the argument types - are not specified; but that is another story for another day. - - The remaining fact is that CDECL is the default convention. - Even if an explicit convention is hard-coded into the function - prototypes inside C headers, problems may appear. The - necessity to expose the convention in users' callbacks is one - of these problems. - - The calling convention issues are also important when using - zlib in other programming languages. Some of them, like Ada - (GNAT) and Fortran (GNU G77), have C bindings implemented - initially on Unix, and relying on the C calling convention. - On the other hand, the pre- .NET versions of Microsoft Visual - Basic require STDCALL, while Borland Delphi prefers, although - it does not require, FASTCALL. - - In fairness to all possible uses of zlib outside the C - programming language, we choose the default "C" convention. - Anyone interested in different bindings or conventions is - encouraged to maintain specialized projects. The "contrib/" - directory from the zlib distribution already holds a couple - of foreign bindings, such as Ada, C++, and Delphi. - - - 7. I need a DLL for my Visual Basic project. What can I do? - - - Define the ZLIB_WINAPI macro before including "zlib.h", when - building both the DLL and the user application (except that - you don't need to define anything when using the DLL in Visual - Basic). The ZLIB_WINAPI macro will switch on the WINAPI - (STDCALL) convention. The name of this DLL must be different - than the official ZLIB1.DLL. - - Gilles Vollant has contributed a build named ZLIBWAPI.DLL, - with the ZLIB_WINAPI macro turned on, and with the minizip - functionality built in. For more information, please read - the notes inside "contrib/vstudio/readme.txt", found in the - zlib distribution. - - - 8. I need to use zlib in my Microsoft .NET project. What can I - do? - - - Henrik Ravn has contributed a .NET wrapper around zlib. Look - into contrib/dotzlib/, inside the zlib distribution. - - - 9. If my application uses ZLIB1.DLL, should I link it to - MSVCRT.DLL? Why? - - - It is not required, but it is recommended to link your - application to MSVCRT.DLL, if it uses ZLIB1.DLL. - - The executables (.EXE, .DLL, etc.) that are involved in the - same process and are using the C run-time library (i.e. they - are calling standard C functions), must link to the same - library. There are several libraries in the Win32 system: - CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc. - Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that - depend on it should also be linked to MSVCRT.DLL. - - -10. Why are you saying that ZLIB1.DLL and my application should - be linked to the same C run-time (CRT) library? I linked my - application and my DLLs to different C libraries (e.g. my - application to a static library, and my DLLs to MSVCRT.DLL), - and everything works fine. - - - If a user library invokes only pure Win32 API (accessible via - and the related headers), its DLL build will work - in any context. But if this library invokes standard C API, - things get more complicated. - - There is a single Win32 library in a Win32 system. Every - function in this library resides in a single DLL module, that - is safe to call from anywhere. On the other hand, there are - multiple versions of the C library, and each of them has its - own separate internal state. Standalone executables and user - DLLs that call standard C functions must link to a C run-time - (CRT) library, be it static or shared (DLL). Intermixing - occurs when an executable (not necessarily standalone) and a - DLL are linked to different CRTs, and both are running in the - same process. - - Intermixing multiple CRTs is possible, as long as their - internal states are kept intact. The Microsoft Knowledge Base - articles KB94248 "HOWTO: Use the C Run-Time" and KB140584 - "HOWTO: Link with the Correct C Run-Time (CRT) Library" - mention the potential problems raised by intermixing. - - If intermixing works for you, it's because your application - and DLLs are avoiding the corruption of each of the CRTs' - internal states, maybe by careful design, or maybe by fortune. - - Also note that linking ZLIB1.DLL to non-Microsoft CRTs, such - as those provided by Borland, raises similar problems. - - -11. Why are you linking ZLIB1.DLL to MSVCRT.DLL? - - - MSVCRT.DLL exists on every Windows 95 with a new service pack - installed, or with Microsoft Internet Explorer 4 or later, and - on all other Windows 4.x or later (Windows 98, Windows NT 4, - or later). It is freely distributable; if not present in the - system, it can be downloaded from Microsoft or from other - software provider for free. - - The fact that MSVCRT.DLL does not exist on a virgin Windows 95 - is not so problematic. Windows 95 is scarcely found nowadays, - Microsoft ended its support a long time ago, and many recent - applications from various vendors, including Microsoft, do not - even run on it. Furthermore, no serious user should run - Windows 95 without a proper update installed. - - -12. Why are you not linking ZLIB1.DLL to - <> ? - - - We considered and abandoned the following alternatives: - - * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or - LIBCMT.LIB) is not a good option. People are using the DLL - mainly to save disk space. If you are linking your program - to a static C library, you may as well consider linking zlib - in statically, too. - - * Linking ZLIB1.DLL to CRTDLL.DLL looks appealing, because - CRTDLL.DLL is present on every Win32 installation. - Unfortunately, it has a series of problems: it does not - work properly with Microsoft's C++ libraries, it does not - provide support for 64-bit file offsets, (and so on...), - and Microsoft discontinued its support a long time ago. - - * Linking ZLIB1.DLL to MSVCR70.DLL or MSVCR71.DLL, supplied - with the Microsoft .NET platform, and Visual C++ 7.0/7.1, - raises problems related to the status of ZLIB1.DLL as a - system component. According to the Microsoft Knowledge Base - article KB326922 "INFO: Redistribution of the Shared C - Runtime Component in Visual C++ .NET", MSVCR70.DLL and - MSVCR71.DLL are not supposed to function as system DLLs, - because they may clash with MSVCRT.DLL. Instead, the - application's installer is supposed to put these DLLs - (if needed) in the application's private directory. - If ZLIB1.DLL depends on a non-system runtime, it cannot - function as a redistributable system component. - - * Linking ZLIB1.DLL to non-Microsoft runtimes, such as - Borland's, or Cygwin's, raises problems related to the - reliable presence of these runtimes on Win32 systems. - It's easier to let the DLL build of zlib up to the people - who distribute these runtimes, and who may proceed as - explained in the answer to Question 14. - - -13. If ZLIB1.DLL cannot be linked to MSVCR70.DLL or MSVCR71.DLL, - how can I build/use ZLIB1.DLL in Microsoft Visual C++ 7.0 - (Visual Studio .NET) or newer? - - - Due to the problems explained in the Microsoft Knowledge Base - article KB326922 (see the previous answer), the C runtime that - comes with the VC7 environment is no longer considered a - system component. That is, it should not be assumed that this - runtime exists, or may be installed in a system directory. - Since ZLIB1.DLL is supposed to be a system component, it may - not depend on a non-system component. - - In order to link ZLIB1.DLL and your application to MSVCRT.DLL - in VC7, you need the library of Visual C++ 6.0 or older. If - you don't have this library at hand, it's probably best not to - use ZLIB1.DLL. - - We are hoping that, in the future, Microsoft will provide a - way to build applications linked to a proper system runtime, - from the Visual C++ environment. Until then, you have a - couple of alternatives, such as linking zlib in statically. - If your application requires dynamic linking, you may proceed - as explained in the answer to Question 14. - - -14. I need to link my own DLL build to a CRT different than - MSVCRT.DLL. What can I do? - - - Feel free to rebuild the DLL from the zlib sources, and link - it the way you want. You should, however, clearly state that - your build is unofficial. You should give it a different file - name, and/or install it in a private directory that can be - accessed by your application only, and is not visible to the - others (e.g. it's not in the SYSTEM or the SYSTEM32 directory, - and it's not in the PATH). Otherwise, your build may clash - with applications that link to the official build. - - For example, in Cygwin, zlib is linked to the Cygwin runtime - CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL. - - -15. May I include additional pieces of code that I find useful, - link them in ZLIB1.DLL, and export them? - - - No. A legitimate build of ZLIB1.DLL must not include code - that does not originate from the official zlib source code. - But you can make your own private DLL build, under a different - file name, as suggested in the previous answer. - - For example, zlib is a part of the VCL library, distributed - with Borland Delphi and C++ Builder. The DLL build of VCL - is a redistributable file, named VCLxx.DLL. - - -16. May I remove some functionality out of ZLIB1.DLL, by enabling - macros like NO_GZCOMPRESS or NO_GZIP at compile time? - - - No. A legitimate build of ZLIB1.DLL must provide the complete - zlib functionality, as implemented in the official zlib source - code. But you can make your own private DLL build, under a - different file name, as suggested in the previous answer. - - -17. I made my own ZLIB1.DLL build. Can I test it for compliance? - - - We prefer that you download the official DLL from the zlib - web site. If you need something peculiar from this DLL, you - can send your suggestion to the zlib mailing list. - - However, in case you do rebuild the DLL yourself, you can run - it with the test programs found in the DLL distribution. - Running these test programs is not a guarantee of compliance, - but a failure can imply a detected problem. - -** - -This document is written and maintained by -Cosmin Truta diff --git a/zlib/README.txt b/zlib/README.txt deleted file mode 100644 index 5c1ac22..0000000 --- a/zlib/README.txt +++ /dev/null @@ -1,53 +0,0 @@ - -What's here -=========== - The official ZLIB1.DLL - - -Source -====== - zlib version 1.2.3 - available at http://www.gzip.org/zlib/ - - -Specification and rationale -=========================== - See the accompanying DLL_FAQ.txt - - -Usage -===== - See the accompanying USAGE.txt - - -Build info -========== - Contributed by Gilles Vollant - - Compiler: Microsoft Visual C++ Toolkit 2003 - Library: Microsoft Visual C++ 6.0 (to link with MSVCRT.DLL) - - -Copyright notice -================ - (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - diff --git a/zlib/USAGE.txt b/zlib/USAGE.txt deleted file mode 100644 index 2ba73b9..0000000 --- a/zlib/USAGE.txt +++ /dev/null @@ -1,94 +0,0 @@ - -Installing ZLIB1.DLL -==================== - Copy ZLIB1.DLL to the SYSTEM or the SYSTEM32 directory. - - -Using ZLIB1.DLL with Microsoft Visual C++ -========================================= - 1. Install the supplied header files "zlib.h" and "zconf.h" - into a directory found in the INCLUDE path list. - - 2. Install the supplied library files "zdll.exp" and "zdll.lib" - into a directory found in the LIB path list. - - 3. Add "zdll.exp" or "zdll.lib" to your project. - - Notes: - - Usually, you don't need both the .exp file and the .lib file. - - If you wish, you may rename "zdll.exp" to "zlib1.exp", and/or - rename "zdll.lib" to "zlib1.lib". - - -Using ZLIB1.DLL with Borland C++ -================================ - 1. Install the supplied header files "zlib.h" and "zconf.h" - into a directory found in the INCLUDE path list. - - 2. Build the import library using the IMPLIB tool: - implib -a -c -f lib\zdllbor.lib zlib1.dll - - OR - - 2' Convert the supplied library file "zdll.lib" to OMF format, - using the COFF2OMF tool: - coff2omf lib\zdll.lib lib\zdllbor.lib - - 3. Install "zdllbor.lib" into a directory found in the LIB path - list. - - 4. Add "zdllbor.lib" to your project. - - Notes: - - The modules that are linked with "zdllbor.lib" must be compiled - using a 4-byte alignment (option -a): - bcc32 -a -c myprog.c - bcc32 myprog.obj zdllbor.lib - - If you wish, you may use "zlib1.lib" instead of "zdllbor.lib". - - -Using ZLIB1.DLL with gcc/MinGW -============================== - 1. Install the supplied header files "zlib.h" and "zconf.h" - into the INCLUDE directory. - - 2. Build the import library from the supplied "zlib.def": - dlltool -D zlib1.dll -d lib/zlib.def -l lib/libzdll.a - - OR - - 2' Copy the supplied library file "zdll.lib" to "libzdll.a": - cp lib/zdll.lib lib/libzdll.a - - 3. Install "libzdll.a" into the LIB directory. - - 4. Add "libzdll.a" to your project, or use the -lzdll option. - - -Using ZLIB1.DLL with gcc/Cygwin -=============================== - ZLIB1.DLL is not designed to work with Cygwin. The Cygwin - system has its own DLL build of zlib, named CYGZ.DLL. - - -Rebuilding ZLIB1.DLL -==================== - Depending on your build environment, use the appropriate - makefile from the win32/ directory, found in the zlib source - distribution. - - Your custom build has to comply with the requirements stated - in DLL_FAQ.txt, including (but not limited to) the following: - - It must be built from an unaltered zlib source distribution. - - It must be linked to MSVCRT.DLL. - - The macros that compile out certain portions of the zlib - code (such as NO_GZCOMPRESS, NO_GZIP) must not be enabled. - - The ZLIB_WINAPI macro must not be enabled. - - Furthermore, it has to run successfully with the test suite - found in this package. - - It is recommended, however, to use the supplied ZLIB1.DLL, - instead of rebuilding it yourself. You should rebuild it - only if you have a special reason. - diff --git a/zlib/lib/zdll.exp b/zlib/lib/zdll.exp deleted file mode 100644 index 2ca08c5..0000000 Binary files a/zlib/lib/zdll.exp and /dev/null differ diff --git a/zlib/lib/zdll.lib b/zlib/lib/zdll.lib deleted file mode 100644 index 01f4e10..0000000 Binary files a/zlib/lib/zdll.lib and /dev/null differ diff --git a/zlib/lib/zlib.def b/zlib/lib/zlib.def deleted file mode 100644 index 03bcf1c..0000000 --- a/zlib/lib/zlib.def +++ /dev/null @@ -1,60 +0,0 @@ -LIBRARY -; zlib data compression library - -EXPORTS -; basic functions - zlibVersion - deflate - deflateEnd - inflate - inflateEnd -; advanced functions - deflateSetDictionary - deflateCopy - deflateReset - deflateParams - deflateBound - deflatePrime - inflateSetDictionary - inflateSync - inflateCopy - inflateReset - inflateBack - inflateBackEnd - zlibCompileFlags -; utility functions - compress - compress2 - compressBound - uncompress - gzopen - gzdopen - gzsetparams - gzread - gzwrite - gzprintf - gzputs - gzgets - gzputc - gzgetc - gzungetc - gzflush - gzseek - gzrewind - gztell - gzeof - gzclose - gzerror - gzclearerr -; checksum functions - adler32 - crc32 -; various hacks, don't look :) - deflateInit_ - deflateInit2_ - inflateInit_ - inflateInit2_ - inflateBackInit_ - inflateSyncPoint - get_crc_table - zError diff --git a/zlib/test/example_d.exe b/zlib/test/example_d.exe deleted file mode 100644 index f9d4fab..0000000 Binary files a/zlib/test/example_d.exe and /dev/null differ diff --git a/zlib/test/minigzip_d.exe b/zlib/test/minigzip_d.exe deleted file mode 100644 index 83bfe35..0000000 Binary files a/zlib/test/minigzip_d.exe and /dev/null differ diff --git a/zlib/test/testzlib_d.exe b/zlib/test/testzlib_d.exe deleted file mode 100644 index 7623246..0000000 Binary files a/zlib/test/testzlib_d.exe and /dev/null differ diff --git a/zlib/test/untgz_d.exe b/zlib/test/untgz_d.exe deleted file mode 100644 index b0198a6..0000000 Binary files a/zlib/test/untgz_d.exe and /dev/null differ