www.pudn.com > BTSERVER.rar > bencode.cpp


/***
*
* RainbowBT Beta 7.7 - A C++ BitTorrent Tracker
* Copyright (C) 2003 Trevor Hogan
*
* This 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.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***/

#include "bnbt.h"
#include "atom.h"
#include "bencode.h"
#include "util.h"

string EncodeInt( const CAtomInt &x )
{
	char pBuf[128];

	memset( pBuf, 0, sizeof( char ) * 128 );

	sprintf( pBuf, "%d", x.getValue( ) );

	string strDest;

	strDest += "i";
	strDest += pBuf;
	strDest += "e";

	return strDest;
}

string EncodeLong( const CAtomLong &x )
{
	char pBuf[128];

	memset( pBuf, 0, sizeof( char ) * 128 );

#if defined( WIN32 )
	sprintf( pBuf, "%I64d", x.getValue( ) );
#elif defined( FreeBSD )
	sprintf( pBuf, "%qd", x.getValue( ) );
#else
	sprintf( pBuf, "%lld", x.getValue( ) );
#endif

	string strDest;

	strDest += "i";
	strDest += pBuf;
	strDest += "e";

	return strDest;
}

string EncodeString( const CAtomString &x )
{
	char pBuf[128];

	memset( pBuf, 0, sizeof( char ) * 128 );

	sprintf( pBuf, "%u", (unsigned int)x.getValue( ).size( ) );

	string strDest;

	strDest += pBuf;
	strDest += ":";
	strDest += x.getValue( );

	return strDest;
}

string EncodeList( const CAtomList &x )
{
	vector v = x.getValue( );

	string strDest;

	strDest += "l";

	for( vector :: iterator i = v.begin( ); i != v.end( ); i++ )
	{
		if( dynamic_cast( *i ) )
			strDest += EncodeInt( *dynamic_cast( *i ) );
		else if( dynamic_cast( *i ) )
			strDest += EncodeLong( *dynamic_cast( *i ) );
		else if( dynamic_cast( *i ) )
			strDest += EncodeString( *dynamic_cast( *i ) );
		else if( dynamic_cast( *i ) )
			strDest += EncodeList( *dynamic_cast( *i ) );
		else if( dynamic_cast( *i ) )
			strDest += EncodeDicti( *dynamic_cast( *i ) );
	}

	strDest += "e";

	return strDest;
}

string EncodeDicti( const CAtomDicti &x )
{
	map mapDicti = x.getValue( );

	string strDest;

	strDest += "d";

	for( map :: iterator i = mapDicti.begin( ); i != mapDicti.end( ); i++ )
	{
		strDest += EncodeString( CAtomString( (*i).first ) );

		if( dynamic_cast( (*i).second ) )
			strDest += EncodeInt( *dynamic_cast( (*i).second ) );
		else if( dynamic_cast( (*i).second ) )
			strDest += EncodeLong( *dynamic_cast( (*i).second ) );
		else if( dynamic_cast( (*i).second ) )
			strDest += EncodeString( *dynamic_cast( (*i).second ) );
		else if( dynamic_cast( (*i).second ) )
			strDest += EncodeList( *dynamic_cast( (*i).second ) );
		else if( dynamic_cast( (*i).second ) )
			strDest += EncodeDicti( *dynamic_cast( (*i).second ) );
	}

	strDest += "e";

	return strDest;
}

string Encode( CAtom *pAtom )
{
	if( dynamic_cast( pAtom ) )
		return EncodeInt( *dynamic_cast( pAtom ) );
	else if( dynamic_cast( pAtom ) )
		return EncodeLong( *dynamic_cast( pAtom ) );
	else if( dynamic_cast( pAtom ) )
		return EncodeString( *dynamic_cast( pAtom ) );
	else if( dynamic_cast( pAtom ) )
		return EncodeList( *dynamic_cast( pAtom ) );
	else if( dynamic_cast( pAtom ) )
		return EncodeDicti( *dynamic_cast( pAtom ) );

	return string( );
}

/*

CAtomInt *DecodeInt( const string &x, unsigned long iStart )
{
	string :: size_type iEnd = x.find( "e" );

	if( iEnd == string :: npos )
	{
		UTIL_LogPrint( "error decoding int - couldn't find \"e\", halting decode\n" );

		return NULL;
	}

	return new CAtomInt( atoi( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ) ) );
}

*/

CAtomLong *DecodeLong( const string &x, unsigned long iStart )
{
	string :: size_type iEnd = x.find( "e", iStart );

	if( iEnd == string :: npos )
	{
		UTIL_LogPrint( "error decoding long - couldn't find \"e\", halting decode\n" );

		return NULL;
	}

	int64 i;

#if defined( WIN32 )
	sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%I64d", &i );
#elif defined( FreeBSD )
	sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%qd", &i );
#else
	sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%lld", &i );
#endif

	return new CAtomLong( i );
}

CAtomString *DecodeString( const string &x, unsigned long iStart )
{
	string :: size_type iSplit = x.find_first_not_of( "1234567890", iStart );

	if( iSplit == string :: npos )
	{
		UTIL_LogPrint( "error decoding string - couldn't find \":\", halting decode\n" );

		return NULL;
	}

	return new CAtomString( x.substr( iSplit + 1, atoi( x.substr( iStart, iSplit - iStart ).c_str( ) ) ) );
}

CAtomList *DecodeList( const string &x, unsigned long iStart )
{
	unsigned long i = iStart + 1;

	CAtomList *pList = new CAtomList( );

	while( i < x.size( ) && x[i] != 'e' )
	{
		CAtom *pAtom = Decode( x, i );

		if( pAtom )
		{
			i += pAtom->EncodedLength( );

			pList->addItem( pAtom );
		}
		else
		{
			UTIL_LogPrint( "error decoding list - error decoding list item, discarding list\n" );

			delete pList;

			return NULL;
		}
	}

	return pList;
}

CAtomDicti *DecodeDicti( const string &x, unsigned long iStart )
{
	unsigned long i = iStart + 1;

	CAtomDicti *pDicti = new CAtomDicti( );

	while( i < x.size( ) && x[i] != 'e' )
	{
		CAtom *pKey = Decode( x, i );

		if( pKey && dynamic_cast( pKey ) )
		{
			i += pKey->EncodedLength( );

			string strKey = pKey->toString( );

			delete pKey;

			if( i < x.size( ) )
			{
				CAtom *pValue = Decode( x, i );

				if( pValue )
				{
					i += pValue->EncodedLength( );

					pDicti->setItem( strKey, pValue );
				}
				else
				{
					UTIL_LogPrint( "error decoding dictionary - error decoding value, discarding dictionary\n" );

					delete pDicti;

					return NULL;
				}
			}
		}
		else
		{
			UTIL_LogPrint( "error decoding dictionary - error decoding key, discarding dictionary\n" );

			delete pDicti;

			return NULL;
		}
	}

	return pDicti;
}

CAtom *Decode( const string &x, unsigned long iStart )
{
	if( iStart < x.size( ) )
	{
		if( x[iStart] == 'i' )
			return DecodeLong( x, iStart );
		else if( isdigit( x[iStart] ) )
			return DecodeString( x, iStart );
		else if( x[iStart] == 'l' )
			return DecodeList( x, iStart );
		else if( x[iStart] == 'd' )
			return DecodeDicti( x, iStart );

		string temp = x.substr( iStart );

		UTIL_LogPrint( "error decoding - found unexpected character %u, halting decode\n", (unsigned char)x[iStart] );
	}
	else
		UTIL_LogPrint( "error decoding - out of range\n" );

	return NULL;
}

CAtom *DecodeFile( const char *szFile )
{
	FILE *pFile = NULL;

	if( ( pFile = fopen( szFile, "rb" ) ) == NULL )
	{
		UTIL_LogPrint( "warning - unable to open %s for reading\n", szFile );

		return NULL;
	}

	fseek( pFile, 0, SEEK_END );
	unsigned long ulFileSize = ftell( pFile );
	fseek( pFile, 0, SEEK_SET );
	char *pData = (char *)malloc( sizeof( char ) * ulFileSize );
	memset( pData, 0, sizeof( char ) * ulFileSize );
	fread( (void *)pData, sizeof( char ), ulFileSize, pFile );
	fclose( pFile );
	string strFile( pData, ulFileSize );
	free( pData );

	return Decode( strFile );
}