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

📄 download.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// Download.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 "Download.h"
#include "Downloads.h"
#include "DownloadTask.h"
#include "DownloadSource.h"
#include "DownloadTransfer.h"
#include "DownloadGroups.h"
#include "Uploads.h"

#include "Library.h"
#include "LibraryBuilder.h"
#include "LibraryHistory.h"
#include "FragmentedFile.h"
#include "BTTrackerRequest.h"
#include "XML.h"

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


//////////////////////////////////////////////////////////////////////
// CDownload construction

CDownload::CDownload()
{
	m_nSerID		= Downloads.GetFreeSID();
	m_bExpanded		= Settings.Downloads.AutoExpand;
	m_bSelected		= FALSE;
	m_bVerify		= TS_UNKNOWN;
	
	m_nRunCookie	= 0;
	m_nSaveCookie	= 0;
	m_nGroupCookie	= 0;
	
	m_bPaused		= FALSE;
	m_bBoosted		= FALSE;
	m_bShared		= Settings.Uploads.SharePartials;
	m_bComplete		= FALSE;
	m_tCompleted	= 0;
	m_tSaved		= 0;
	
	DownloadGroups.Link( this );
}

CDownload::~CDownload()
{
	if ( m_pTask != NULL ) m_pTask->Abort();
	DownloadGroups.Unlink( this );
	
	if ( m_pTorrent.m_nFiles > 1 && m_bComplete )
	{
		CloseTransfers();
		CloseTorrentUploads();
		Uploads.OnRename( m_sLocalName, NULL );
		if ( ! ::DeleteFile( m_sLocalName ) )
			theApp.WriteProfileString( _T("Delete"), m_sLocalName, _T("") );
	}
}

//////////////////////////////////////////////////////////////////////
// CDownload control : pause

void CDownload::Pause()
{
	if ( m_bComplete || m_bPaused ) return;
	m_bPaused = TRUE;
	
	theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_PAUSED, (LPCTSTR)GetDisplayName() );
	
	CloseTransfers();
	CloseFile();
	SetModified();
}

//////////////////////////////////////////////////////////////////////
// CDownload control : resume

void CDownload::Resume()
{
	if ( m_bComplete || ! m_bPaused ) return;
	
	theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_RESUMED, (LPCTSTR)GetDisplayName() );
	
	if ( m_pFile != NULL )
	{
		for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
		{
			pSource->OnResume();
		}
	}
	
	m_bPaused	= FALSE;
	m_bDiskFull	= FALSE;
	m_tReceived	= GetTickCount();
	m_bTorrentTrackerError = FALSE;
	
	SetModified();
	CloseTorrentUploads();
}

//////////////////////////////////////////////////////////////////////
// CDownload control : remove

void CDownload::Remove(BOOL bDelete)
{
	CloseTorrentUploads();
	CloseTransfers();
	CloseFile();
	
	if ( m_pTask != NULL )
	{
		m_pTask->Abort();
		ASSERT( m_pTask == NULL );
	}
	
	if ( bDelete || ! IsCompleted() )
	{
		theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_REMOVE, (LPCTSTR)GetDisplayName() );
	}
	
	DeleteFile( bDelete );
	DeletePreviews();
	
	::DeleteFile( m_sLocalName + _T(".sd") );
	
	Downloads.Remove( this );
}

//////////////////////////////////////////////////////////////////////
// CDownload control : boost

void CDownload::Boost()
{
	if ( m_pFile == NULL || m_bBoosted ) return;
	
	theApp.Message( MSG_SYSTEM, IDS_DOWNLOAD_BOOST, (LPCTSTR)GetDisplayName() );
	
	for ( CDownloadTransfer* pTransfer = GetFirstTransfer() ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
	{
		pTransfer->Boost();
	}
	
	m_bBoosted = TRUE;
	SetModified();
}

//////////////////////////////////////////////////////////////////////
// CDownload control : sharing

void CDownload::Share(BOOL bShared)
{
	m_bShared = bShared;
	SetModified();
}

//////////////////////////////////////////////////////////////////////
// CDownload control : rename

BOOL CDownload::Rename(LPCTSTR pszName)
{
	if ( m_sRemoteName == pszName ) return FALSE;
	m_sRemoteName = pszName;
	SetModified();
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CDownload state checks

BOOL CDownload::IsStarted() const
{
	return ( GetVolumeComplete() > 0 );
}

BOOL CDownload::IsPaused() const
{
	return m_bPaused;
}

BOOL CDownload::IsDownloading() const
{
	return ( GetTransferCount() > 0 );
}

BOOL CDownload::IsMoving() const
{
	return ( m_pFile == NULL );
}

BOOL CDownload::IsCompleted() const
{
	return m_bComplete;
}

BOOL CDownload::IsBoosted() const
{
	return m_bBoosted;
}

BOOL CDownload::IsShared() const
{
#ifdef _DEBUG
	return m_bShared;
#else
	return m_bShared || m_bBTH || Settings.eDonkey.EnableToday;
#endif
}

//////////////////////////////////////////////////////////////////////
// CDownload run handler

void CDownload::OnRun()
{
	DWORD tNow = GetTickCount();
	
	if ( m_bDiskFull && ! m_bPaused ) Pause();
	
	if ( RunTorrent( tNow ) )
	{
		RunSearch( tNow );
		
		if ( m_bPaused == FALSE )
		{
			if ( m_bSeeding )
			{
				RunValidation( TRUE );
			}
			else if ( m_pFile != NULL )
			{
				RunValidation( FALSE );
				
				if ( RunFile( tNow ) )
				{
					if ( ValidationCanFinish() ) OnDownloaded();
				}
				else
				{
					StartTransfersIfNeeded( tNow );
				}
			}
			else if ( m_pFile == NULL && ! m_bComplete && m_pTask == NULL )
			{
				OnDownloaded();
			}
		}
	}
	
	if ( tNow > m_tSaved && tNow - m_tSaved >= Settings.Downloads.SaveInterval )
	{
		if ( m_pFile != NULL && m_pFile->Flush() )
		{
			m_tSaved = tNow;
		}
		
		if ( m_nCookie != m_nSaveCookie )
		{
			Save();
			m_tSaved = tNow;
		}
	}
}

//////////////////////////////////////////////////////////////////////
// CDownload download complete handler

void CDownload::OnDownloaded()
{
	ASSERT( m_bComplete == FALSE );
	
	theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_COMPLETED, (LPCTSTR)GetDisplayName() );
	m_tCompleted = GetTickCount();
	
	CloseTransfers();
	
	if ( m_pFile != NULL )
	{
		m_pFile->Close();
		delete m_pFile;
		m_pFile = NULL;
		AppendMetadata();
	}
	
	ASSERT( m_pTask == NULL );
	m_pTask = new CDownloadTask( this, CDownloadTask::dtaskCopySimple );
	
	SetModified();
}

//////////////////////////////////////////////////////////////////////
// CDownload task completion

void CDownload::OnTaskComplete(CDownloadTask* pTask)
{
	ASSERT( m_pTask == pTask );
	m_pTask = NULL;
	
	if ( pTask->WasAborted() ) return;
	
	if ( pTask->m_nTask == CDownloadTask::dtaskAllocate )
	{
		// allocate complete
	}
	else
	{
		OnMoved( pTask );
	}
}

//////////////////////////////////////////////////////////////////////
// CDownload moved handler

void CDownload::OnMoved(CDownloadTask* pTask)
{
	CString strLocalName = m_sLocalName;
	ASSERT( m_pFile == NULL );
	
	if ( pTask->m_bSuccess )
	{
		m_sLocalName = pTask->m_sFilename;
		
		theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_MOVED,
			(LPCTSTR)GetDisplayName(), (LPCTSTR)m_sLocalName );
		
		if ( m_pXML != NULL && Settings.Downloads.Metadata )
			WriteMetadata( pTask->m_sPath );
	}
	else
	{
		theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CANT_MOVE,
			(LPCTSTR)GetDisplayName(), (LPCTSTR)pTask->m_sPath );
		
		if ( m_pTorrent.IsAvailable() && m_pTorrent.m_nFiles > 1 )
		{
			m_bDiskFull = TRUE;
			return;
		}
	}
	
	m_bComplete		= TRUE;
	m_tCompleted	= GetTickCount();
	
	::DeleteFile( strLocalName + _T(".sd") );
	
	if ( m_nTorrentBlock > 0 && m_nTorrentSuccess >= m_nTorrentBlock )
	{
		CBTTrackerRequest::SendCompleted( this );
	}
	
	LibraryBuilder.RequestPriority( m_sLocalName );
	
	if ( m_bSHA1 || m_bED2K )
	{
		LibraryHistory.Add( m_sLocalName, m_bSHA1 ? &m_pSHA1 : NULL,
			m_bED2K ? &m_pED2K : NULL, GetSourceURLs( NULL, 0, FALSE, NULL ) );
	}
	else
	{
		LibraryHistory.Add( m_sLocalName, NULL, NULL, NULL );
	}
	
	ClearSources();
	SetModified();
	
	if ( IsFullyVerified() ) OnVerify( m_sLocalName, TRUE );
}

//////////////////////////////////////////////////////////////////////
// CDownload verification handler

BOOL CDownload::OnVerify(LPCTSTR pszPath, BOOL bVerified)
{
	if ( m_bVerify != TS_UNKNOWN ) return FALSE;
	if ( m_pFile != NULL ) return FALSE;
	
	if ( pszPath != (LPCTSTR)m_sLocalName &&
		 m_sLocalName.CompareNoCase( pszPath ) != 0 ) return FALSE;
	
	m_bVerify = bVerified ? TS_TRUE : TS_FALSE;
	SetModified();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CDownload load and save

BOOL CDownload::Load(LPCTSTR pszName)
{
	BOOL bSuccess = FALSE;
	CFile pFile;
	
	m_sLocalName = pszName;
	m_sLocalName = m_sLocalName.Left( m_sLocalName.GetLength() - 3 );
	
	if ( pFile.Open( m_sLocalName + _T(".sd"), CFile::modeRead ) )
	{
		try
		{
			CArchive ar( &pFile, CArchive::load );
			Serialize( ar, 0 );
			bSuccess = TRUE;
		}
		catch ( CException* pException )
		{
			pException->Delete();
		}
		
		pFile.Close();
	}
	
	if ( ! bSuccess && pFile.Open( m_sLocalName + _T(".sd.sav"), CFile::modeRead ) )
	{
		try
		{
			CArchive ar( &pFile, CArchive::load );
			Serialize( ar, 0 );
			bSuccess = TRUE;
		}
		catch ( CException* pException )
		{
			pException->Delete();
		}
		
		pFile.Close();
		if ( bSuccess ) Save();
	}
	
	m_nSaveCookie = m_nCookie;
	
	return bSuccess;
}

BOOL CDownload::Save(BOOL bFlush)
{
	CFile pFile;
	
	m_nSaveCookie = m_nCookie;
	m_tSaved = GetTickCount();
	
	if ( m_bComplete ) return TRUE;
	
	GenerateLocalName();
	::DeleteFile( m_sLocalName + _T(".sd.sav") );
	
	if ( ! pFile.Open( m_sLocalName + _T(".sd.sav"),
		CFile::modeReadWrite|CFile::modeCreate|CFile::osWriteThrough ) ) return FALSE;
	
	BYTE* pBuffer = new BYTE[ 4096 ];
	{
		CArchive ar( &pFile, CArchive::store, 4096, pBuffer );
		Serialize( ar, 0 );
		ar.Close();
	}
	delete [] pBuffer;
	
	if ( Settings.Downloads.FlushSD || bFlush ) pFile.Flush();
	pFile.SeekToBegin();
	CHAR szID[3] = { 0, 0, 0 };
	pFile.Read( szID, 3 );
	pFile.Close();
	
	if ( szID[0] == 'S' && szID[1] == 'D' && szID[2] == 'L' )
	{
		::DeleteFile( m_sLocalName + _T(".sd") );
		MoveFile( m_sLocalName + _T(".sd.sav"), m_sLocalName + _T(".sd") );
		return TRUE;
	}
	else
	{
		::DeleteFile( m_sLocalName + _T(".sd.sav") );
		return FALSE;
	}
}

//////////////////////////////////////////////////////////////////////
// CDownload serialize

#define DOWNLOAD_SER_VERSION	30

void CDownload::Serialize(CArchive& ar, int nVersion)
{
	ASSERT( ! m_bComplete );
	
	if ( nVersion == 0 )
	{
		nVersion = DOWNLOAD_SER_VERSION;
		
		if ( ar.IsStoring() )
		{
			ar.Write( "SDL", 3 );
			ar << nVersion;
		}
		else
		{
			CHAR szID[3];
			ar.Read( szID, 3 );
			if ( strncmp( szID, "SDL", 3 ) ) AfxThrowUserException();
			ar >> nVersion;
			if ( nVersion <= 0 || nVersion > DOWNLOAD_SER_VERSION ) AfxThrowUserException();
		}
	}
	else if ( nVersion < 11 && ar.IsLoading() )
	{
		SerializeOld( ar, nVersion );
		return;
	}
	
	CDownloadWithExtras::Serialize( ar, nVersion );
	
	if ( ar.IsStoring() )
	{
		ar << m_bExpanded;
		ar << m_bPaused;
		ar << m_bBoosted;
		ar << m_bShared;
		
		ar << m_nSerID;
	}
	else
	{
		ar >> m_bExpanded;
		ar >> m_bPaused;
		ar >> m_bBoosted;
		if ( nVersion >= 14 ) ar >> m_bShared;
		if ( nVersion >= 26 ) ar >> m_nSerID;
		
		DownloadGroups.Link( this );
	}
}

void CDownload::SerializeOld(CArchive& ar, int nVersion)
{
	ASSERT( ar.IsLoading() );
	
	ar >> m_sLocalName;
	ar >> m_sRemoteName;
	
	DWORD nSize;
	ar >> nSize;
	m_nSize = nSize;
	
	ar >> m_bSHA1;
	if ( m_bSHA1 ) ar.Read( &m_pSHA1, sizeof(SHA1) );
	
	ar >> m_bPaused;
	ar >> m_bExpanded;
	if ( nVersion >= 6 ) ar >> m_bBoosted;
	
	m_pFile->Serialize( ar, nVersion );
	GenerateLocalName();
	
	for ( int nSources = ar.ReadCount() ; nSources ; nSources-- )
	{
		CDownloadSource* pSource = new CDownloadSource( this );
		pSource->Serialize( ar, nVersion );
		AddSourceInternal( pSource );
	}
	
	if ( nVersion >= 3 && ar.ReadCount() )
	{
		m_pXML = new CXMLElement();
		m_pXML->Serialize( ar );
	}
}

⌨️ 快捷键说明

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