⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ggep.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// GGEP.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "GGEP.h"
#include "G1Packet.h"
#include "ZLib.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// CGGEPBlock construction

CGGEPBlock::CGGEPBlock()
{
	m_pFirst = m_pLast = NULL;

	m_pInput = NULL;
	m_nInput = 0;
}

CGGEPBlock::~CGGEPBlock()
{
	Clear();
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock clear

void CGGEPBlock::Clear()
{
	while ( m_pFirst )
	{
		CGGEPItem* pNext = m_pFirst->m_pNext;
		delete m_pFirst;
		m_pFirst = pNext;
	}

	m_pLast = NULL;
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock add

CGGEPItem* CGGEPBlock::Add(LPCTSTR pszID)
{
	if ( ! pszID || ! *pszID ) return NULL;
	
	CGGEPItem* pItem = new CGGEPItem( pszID );
	
	if ( ! m_pFirst ) m_pFirst = pItem;
	if ( m_pLast ) m_pLast->m_pNext = pItem;
	m_pLast = pItem;
	
	return pItem;
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock find

CGGEPItem* CGGEPBlock::Find(LPCTSTR pszID, DWORD nMinLength)
{
	if ( ! pszID || ! *pszID ) return NULL;

	for ( CGGEPItem* pItem = m_pFirst ; pItem ; pItem = pItem->m_pNext )
	{
		if ( pItem->m_sID.CompareNoCase( pszID ) == 0 && pItem->m_nLength >= nMinLength )
			return pItem;
	}
	
	return NULL;
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock from packet

CGGEPBlock* CGGEPBlock::FromPacket(CPacket* pPacket)
{
	CGGEPBlock* pBlock = new CGGEPBlock();
	if ( pBlock->ReadFromPacket( pPacket ) ) return pBlock;
	delete pBlock;
	return NULL;
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock read helpers

BOOL CGGEPBlock::ReadFromPacket(CPacket* pPacket)
{
	m_pInput = pPacket->m_pBuffer + pPacket->m_nPosition;
	m_nInput = pPacket->m_nLength - pPacket->m_nPosition;
	
	BOOL bSuccess = ReadInternal();
	
	pPacket->m_nPosition = pPacket->m_nLength - m_nInput;
	
	return bSuccess;
}

BOOL CGGEPBlock::ReadFromString(LPCTSTR pszData)
{
	m_pInput = (BYTE*)pszData;
	m_nInput = _tcslen( pszData );
	
	return ReadInternal();
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock read internal

BOOL CGGEPBlock::ReadInternal()
{
	while ( m_nInput )
	{
		if ( ReadByte() == GGEP_MAGIC ) break;
	}
	
	if ( ! m_nInput ) return FALSE;
	
	while ( m_nInput >= 3 )
	{
		BYTE nFlags = ReadByte();
		if ( ! ( nFlags & GGEP_HDR_IDLEN ) ) return FALSE;
		
		CGGEPItem* pItem = new CGGEPItem();
		
		if ( pItem->ReadFrom( this, nFlags ) )
		{
			if ( ! m_pFirst ) m_pFirst = pItem;
			if ( m_pLast ) m_pLast->m_pNext = pItem;
			m_pLast = pItem;
		}
		else
		{
			delete pItem;
			return FALSE;
		}
		
		if ( nFlags & GGEP_HDR_LAST ) return TRUE;
	}
	
	return FALSE;
}

BYTE CGGEPBlock::ReadByte()
{
	if ( m_nInput < 1 ) AfxThrowUserException();
	m_nInput--;
	return *m_pInput++;
}

//////////////////////////////////////////////////////////////////////
// CGGEPBlock write helpers

void CGGEPBlock::Write(CPacket* pPacket)
{
	if ( ! m_pFirst ) return;
	
	pPacket->WriteByte( GGEP_MAGIC );
	
	for ( CGGEPItem* pItem = m_pFirst ; pItem ; pItem = pItem->m_pNext )
	{
		pItem->WriteTo( pPacket );
	}
	
	Clear();
}

void CGGEPBlock::Write(CString& str)
{
	if ( ! m_pFirst ) return;
	
	str += (TCHAR)GGEP_MAGIC;
	
	for ( CGGEPItem* pItem = m_pFirst ; pItem ; pItem = pItem->m_pNext )
	{
		pItem->WriteTo( str );
	}
	
	Clear();
}


//////////////////////////////////////////////////////////////////////
// CGGEPItem construction

CGGEPItem::CGGEPItem(LPCTSTR pszID)
{
	m_pNext		= NULL;
	m_pBuffer	= NULL;
	m_nLength	= 0;
	m_nPosition	= 0;
	
	if ( pszID ) m_sID = pszID;
}

CGGEPItem::~CGGEPItem()
{
	if ( m_pBuffer ) delete [] m_pBuffer;
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem ID check

BOOL CGGEPItem::IsNamed(LPCTSTR pszID)
{
	return m_sID == pszID;
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem reading and writing

void CGGEPItem::Read(LPVOID pData, int nLength)
{
	if ( m_nPosition + (DWORD)nLength >= m_nLength ) AfxThrowUserException();
	CopyMemory( pData, m_pBuffer + m_nPosition, nLength );
	m_nPosition += nLength;
}

BYTE CGGEPItem::ReadByte()
{
	BYTE nByte;
	Read( &nByte, 1 );
	return nByte;
}

void CGGEPItem::Write(LPCVOID pData, int nLength)
{
	BYTE* pNew = new BYTE[ m_nLength + (DWORD)nLength ];
	
	if ( m_pBuffer )
	{
		CopyMemory( pNew, m_pBuffer, m_nLength );
		delete [] m_pBuffer;
	}
	
	m_pBuffer = pNew;
	CopyMemory( m_pBuffer + m_nLength, pData, nLength );
	m_nLength += nLength;
}

void CGGEPItem::WriteByte(BYTE nValue)
{
	Write( &nValue, 1 );
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem string conversion

CString CGGEPItem::ToString()
{
	CString strValue;
	
	LPTSTR pszOut = strValue.GetBuffer( m_nLength );
	LPCSTR pszIn  = (LPCSTR)m_pBuffer;
	
	for ( DWORD nChar = 0 ; nChar < m_nLength ; nChar++ )
		*pszOut++ = (TCHAR)*pszIn++;
	
	strValue.ReleaseBuffer( m_nLength );
	return strValue;
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem read

BOOL CGGEPItem::ReadFrom(CGGEPBlock* pBlock, BYTE nFlags)
{
	BYTE nLen = ( nFlags & GGEP_HDR_IDLEN );
	
	if ( pBlock->m_nInput <= nLen ) return FALSE;
	
	LPTSTR pszID = m_sID.GetBuffer( nLen );
	for ( BYTE i = nLen ; i && pBlock->m_nInput ; i-- ) *pszID++ = pBlock->ReadByte();
	m_sID.ReleaseBuffer( nLen );
	
	m_nLength = 0;
	
	for ( i = 0 ; i < 3 ; i++ )
	{
		if ( ! pBlock->m_nInput ) return FALSE;
		nLen = pBlock->ReadByte();
		
		m_nLength = ( m_nLength << 6 ) | ( nLen & GGEP_LEN_MASK );
		
		if ( nLen & GGEP_LEN_LAST ) break;
		if ( ! pBlock->m_nInput || ! ( nLen & GGEP_LEN_MORE ) ) return FALSE;
	}
	
	if ( nLen & GGEP_LEN_MORE ) return FALSE;
	if ( ! ( nLen & GGEP_LEN_LAST ) ) return FALSE;
	
	if ( ! m_nLength ) return TRUE;
	
	if ( pBlock->m_nInput < m_nLength ) return FALSE;

	m_pBuffer = new BYTE[ m_nLength ];
	
	CopyMemory( m_pBuffer, pBlock->m_pInput, m_nLength );
	pBlock->m_pInput += m_nLength;
	pBlock->m_nInput -= m_nLength;

	if ( ( nFlags & GGEP_HDR_COBS ) && ! Decode() )
	{
		delete [] m_pBuffer;
		m_pBuffer = NULL;
		return FALSE;
	}
	
	if ( ( nFlags & GGEP_HDR_DEFLATE ) && ! Inflate() )
	{
		delete [] m_pBuffer;
		m_pBuffer = NULL;
		return FALSE;
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem write to packet

void CGGEPItem::WriteTo(CPacket* pPacket)
{
	BYTE nFlags = ( m_sID.GetLength() & GGEP_HDR_IDLEN );
	
	if ( Deflate( TRUE ) ) nFlags |= GGEP_HDR_DEFLATE;
	if ( Encode( TRUE ) ) nFlags |= GGEP_HDR_COBS;
	
	if ( m_pNext == NULL ) nFlags |= GGEP_HDR_LAST;
	
	pPacket->WriteByte( nFlags );
	
	for ( BYTE i = 0 ; i < m_sID.GetLength() ; i++ )
		pPacket->WriteByte( (BYTE)m_sID.GetAt( i ) );
	
	if ( m_nLength & 0x3F000 )
		pPacket->WriteByte( (BYTE)( ( ( m_nLength >> 12 ) & GGEP_LEN_MASK ) | GGEP_LEN_MORE ) );
	
	if ( m_nLength & 0xFC0 )
		pPacket->WriteByte( (BYTE)( ( ( m_nLength >> 6 ) & GGEP_LEN_MASK ) | GGEP_LEN_MORE ) );
	
	if ( m_nLength & 0x3F )
		pPacket->WriteByte( (BYTE)( ( m_nLength & GGEP_LEN_MASK ) | GGEP_LEN_LAST ) );
	
	if ( m_pBuffer && m_nLength )
		pPacket->Write( m_pBuffer, m_nLength );
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem write to string

void CGGEPItem::WriteTo(CString& str)
{
	BYTE nFlags = ( m_sID.GetLength() & GGEP_HDR_IDLEN );
	
	if ( Deflate( TRUE ) ) nFlags |= GGEP_HDR_DEFLATE;
	if ( Encode() ) nFlags |= GGEP_HDR_COBS;
	
	if ( m_pNext == NULL ) nFlags |= GGEP_HDR_LAST;
	
	str += (TCHAR)nFlags;
	str += m_sID;
	
	if ( m_nLength & 0x3F000 )
		str += (TCHAR)( ( ( m_nLength >> 12 ) & GGEP_LEN_MASK ) | GGEP_LEN_MORE );
	
	if ( m_nLength & 0xFC0 )
		str += (TCHAR)( ( ( m_nLength >> 6 ) & GGEP_LEN_MASK ) | GGEP_LEN_MORE );
	
	if ( m_nLength & 0x3F )
		str += (TCHAR)( ( m_nLength & GGEP_LEN_MASK ) | GGEP_LEN_LAST );
	
	if ( m_pBuffer && m_nLength )
	{
		for ( DWORD nLen = 0 ; nLen < m_nLength ; nLen++ )
			str += (TCHAR)m_pBuffer[ nLen ];
	}
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem COBS encoding

BOOL CGGEPItem::Encode(BOOL bIfZeros)
{
	if ( ! m_pBuffer ) return FALSE;
	
	DWORD nLength;
	BYTE* pIn;
	
	if ( bIfZeros )
	{
		for ( pIn = m_pBuffer, nLength = m_nLength ; nLength > 0 ; nLength--, pIn++ )
		{
			if ( *pIn == 0 ) break;
		}
		if ( ! nLength ) return FALSE;
	}
	
	BYTE* pOutput	= new BYTE[ m_nLength * 2 ];
	BYTE* pOut		= pOutput;
	BYTE* pRange	= NULL;
	DWORD nRange	= 0;
	
	for ( pIn = m_pBuffer, nLength = m_nLength ; nLength > 0 ; nLength--, pIn++ )
	{
		if ( *pIn == 0 )
		{
			if ( pRange )
			{
				ASSERT( nRange > 0 && nRange < 254 );
				*pOut++ = (BYTE)( nRange + 1 );
				CopyMemory( pOut, pRange, nRange );
				pOut += nRange;
				pRange = NULL;
				nRange = 0;
			}
			else
			{
				*pOut++ = 1;
			}
		}
		else if ( pRange )
		{
			if ( ++nRange == 254 )
			{
				*pOut++ = 255;
				CopyMemory( pOut, pRange, 254 );
				pOut += 254;
				pRange = NULL;
				nRange = 0;
			}
		}
		else
		{
			pRange = pIn;
			nRange = 1;
		}
	}
	
	if ( pRange )
	{
		ASSERT( nRange > 0 && nRange < 254 );
		*pOut++ = (BYTE)( nRange + 1 );
		CopyMemory( pOut, pRange, nRange );
		pOut += nRange;
		pRange = NULL;
		nRange = 0;
	}
	
	delete [] m_pBuffer;
	
	m_pBuffer = pOutput;
	m_nLength = pOut - pOutput;
	
	return TRUE;
}

BOOL CGGEPItem::Decode()
{
	if ( ! m_pBuffer ) return FALSE;
	
	BYTE* pOutput	= new BYTE[ m_nLength * 2 ];
	BYTE* pOut		= pOutput;
	BYTE* pIn		= m_pBuffer;
	
	for ( DWORD nLength = m_nLength ; nLength > 0 ; nLength--, pIn++ )
	{
		if ( *pIn == 0 )
		{
			break;
		}
		else if ( *pIn == 1 )
		{
			*pOut++ = 0;
			continue;
		}
		
		BOOL bZero = ( *pIn != 255 );
		BYTE nSize = *pIn++ - 1;
		nLength--;
		
		nSize = (BYTE)min( (DWORD)nSize, nLength );
		
		while ( nSize-- )
		{
			*pOut++ = *pIn++;
			nLength--;
		}
		
		if ( bZero && nLength ) *pOut++ = 0;
		
		pIn--;
		nLength++;
	}
	
	delete [] m_pBuffer;
	
	m_pBuffer = pOutput;
	m_nLength = pOut - pOutput;
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CGGEPItem compression

BOOL CGGEPItem::Deflate(BOOL bIfSmaller)
{
	if ( ! m_pBuffer ) return FALSE;
	if ( bIfSmaller && m_nLength < 45 ) return FALSE;

	DWORD nCompressed = 0;
	BYTE* pCompressed = CZLib::Compress( m_pBuffer, m_nLength, &nCompressed );

	if ( ! pCompressed ) return FALSE;

	if ( bIfSmaller && nCompressed >= m_nLength )
	{
		delete [] pCompressed;
		return FALSE;
	}

	delete [] m_pBuffer;
	m_pBuffer = pCompressed;
	m_nLength = nCompressed;

	return TRUE;
}

BOOL CGGEPItem::Inflate()
{
	if ( ! m_pBuffer ) return FALSE;
	
	DWORD nCompressed = 0;
	BYTE* pCompressed = CZLib::Decompress( m_pBuffer, m_nLength, &nCompressed );
	
	if ( ! pCompressed ) return FALSE;
	
	delete [] m_pBuffer;
	m_pBuffer = pCompressed;
	m_nLength = nCompressed;
	
	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -