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

📄 library.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// Library.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 "Library.h"
#include "LibraryMaps.h"
#include "LibraryFolders.h"
#include "LibraryDictionary.h"
#include "LibraryBuilder.h"
#include "LibraryHistory.h"
#include "HashDatabase.h"
#include "SharedFolder.h"
#include "SharedFile.h"
#include "AlbumFolder.h"

#include "QuerySearch.h"
#include "Application.h"

#include "XML.h"
#include "Schema.h"
#include "SchemaCache.h"

#include "SHA.h"
#include "ED2K.h"
#include "TigerTree.h"

IMPLEMENT_DYNAMIC(CLibrary, CComObject)

BEGIN_INTERFACE_MAP(CLibrary, CComObject)
	INTERFACE_PART(CLibrary, IID_ILibrary, Library)
END_INTERFACE_MAP()

CLibrary Library;


//////////////////////////////////////////////////////////////////////
// CLibrary construction

CLibrary::CLibrary()
{
	EnableDispatch( IID_ILibrary );
	
	m_nUpdateSaved	= 0;
	m_nScanCount	= 0;
	
	m_hThread		= NULL;
	m_bThread		= TRUE;
	m_nScanCookie	= 1;
	m_nUpdateCookie	= 0;
	m_nUpdateSaved	= 0;
	m_nFileSwitch	= 0;
	m_nInhibit		= 0;
	
	m_pfnGFAEW		= NULL;
	m_pfnGFAEA		= NULL;
	
	if ( m_hKernel = LoadLibrary( _T("kernel32") ) )
	{
		(FARPROC&)m_pfnGFAEW = GetProcAddress( m_hKernel, "GetFileAttributesExW" );
		(FARPROC&)m_pfnGFAEA = GetProcAddress( m_hKernel, "GetFileAttributesExA" );
	}
}

CLibrary::~CLibrary()
{
	if ( m_hKernel != NULL ) FreeLibrary( m_hKernel );
}

//////////////////////////////////////////////////////////////////////
// CLibrary locking

BOOL CLibrary::Lock(DWORD nTimeout)
{
	return m_pSection.Lock( nTimeout );
}

void CLibrary::Unlock(BOOL bSetUpdated)
{
	if ( bSetUpdated ) m_nUpdateCookie = GetTickCount();
	m_pSection.Unlock();
}

void CLibrary::Inhibit(BOOL bInhibit)
{
	if ( bInhibit )
		InterlockedIncrement( (PLONG)&m_nInhibit );
	else
		InterlockedDecrement( (PLONG)&m_nInhibit );
}

//////////////////////////////////////////////////////////////////////
// CLibrary file and folder operations

CLibraryFile* CLibrary::LookupFile(DWORD nIndex, BOOL bLockOnSuccess, BOOL bSharedOnly, BOOL bAvailableOnly)
{
	return LibraryMaps.LookupFile( nIndex, bLockOnSuccess, bSharedOnly, bAvailableOnly );
}

CAlbumFolder* CLibrary::GetAlbumRoot()
{
	return LibraryFolders.GetAlbumRoot();
}

void CLibrary::AddFile(CLibraryFile* pFile)
{
	LibraryMaps.OnFileAdd( pFile );
	
	if ( pFile->m_bSHA1 )
	{
		LibraryDictionary.Add( pFile );
	}
	
	if ( pFile->IsAvailable() )
	{
		if ( pFile->m_bSHA1 || pFile->m_bTiger || pFile->m_bMD5 || pFile->m_bED2K )
		{
			LibraryHistory.Submit( pFile );
			GetAlbumRoot()->OrganiseFile( pFile );
		}
		
		if ( ! pFile->m_bSHA1 || ! pFile->m_bTiger || ! pFile->m_bMD5 || ! pFile->m_bED2K )
		{
			LibraryBuilder.Add( pFile );
		}
	}
}

void CLibrary::RemoveFile(CLibraryFile* pFile)
{
	LibraryMaps.OnFileRemove( pFile );
	
	if ( pFile->m_nIndex )
	{
		LibraryBuilder.Remove( pFile );
		LibraryDictionary.Remove( pFile );
	}
}

void CLibrary::OnFileDelete(CLibraryFile* pFile)
{
	LibraryFolders.OnFileDelete( pFile );
	LibraryHistory.OnFileDelete( pFile );
	LibraryHashDB.DeleteAll( pFile->m_nIndex );
}

//////////////////////////////////////////////////////////////////////
// CLibrary search

CPtrList* CLibrary::Search(CQuerySearch* pSearch, int nMaximum, BOOL bLocal)
{
	if ( ! m_pSection.Lock( 50 ) ) return NULL;
	
	CPtrList* pHits = LibraryMaps.Search( pSearch, nMaximum, bLocal );
	
	if ( pHits == NULL && pSearch != NULL )
	{
		pHits = LibraryDictionary.Search( pSearch, nMaximum, bLocal );
	}
	
	if ( pHits == NULL ) m_pSection.Unlock();
	
	return pHits;
}

//////////////////////////////////////////////////////////////////////
// CLibrary clear

void CLibrary::Clear()
{
	StopThread();
	
	CSingleLock pLock( &m_pSection, TRUE );
	
	LibraryHistory.Clear();
	LibraryDictionary.Clear();
	LibraryFolders.Clear();
	LibraryMaps.Clear();
	
	m_nUpdateCookie++;
}

//////////////////////////////////////////////////////////////////////
// CLibrary load from disk

BOOL CLibrary::Load()
{
	CSingleLock pLock( &m_pSection, TRUE );
	
	GetAlbumRoot();
	
	FILETIME pFileTime1 = { 0, 0 }, pFileTime2 = { 0, 0 };
	CFile pFile1, pFile2;
	BOOL bFile1, bFile2;
	CString strFile;
	
	strFile = Settings.General.Path + _T("\\Data\\Library");
	
	bFile1 = pFile1.Open( strFile + _T("1.dat"), CFile::modeRead );
	bFile2 = pFile2.Open( strFile + _T("2.dat"), CFile::modeRead );
	
	if ( bFile1 || bFile2 )
	{
		if ( bFile1 ) bFile1 = pFile1.Read( &pFileTime1, sizeof(FILETIME) ) == sizeof(FILETIME);
		if ( bFile2 ) bFile2 = pFile2.Read( &pFileTime2, sizeof(FILETIME) ) == sizeof(FILETIME);
	}
	else
	{
		bFile1 = pFile1.Open( strFile + _T(".dat"), CFile::modeRead );
		pFileTime1.dwHighDateTime++;
	}
	
	if ( bFile1 || bFile2 )
	{
		CFile* pNewest	= ( CompareFileTime( &pFileTime1, &pFileTime2 ) >= 0 )
						? &pFile1 : &pFile2;
		
		try
		{
			CArchive ar( pNewest, CArchive::load, 40960 );
			Serialize( ar );
			ar.Close();
		}
		catch ( CException* pException )
		{
			pException->Delete();
			Clear();
			
			if ( pNewest == &pFile1 && bFile2 )
				pNewest = &pFile2;
			else if ( pNewest == &pFile2 && bFile1 )
				pNewest = &pFile1;
			else
				pNewest = NULL;
			
			if ( pNewest != NULL )
			{
				try
				{
					CArchive ar( pNewest, CArchive::load, 40960 );
					Serialize( ar );
					ar.Close();
				}
				catch ( CException* pException )
				{
					pException->Delete();
				}
			}
		}
		
		pNewest->Close();
	}
	else
	{
		CreateDirectory( Settings.Downloads.CompletePath, NULL );
		LibraryFolders.AddFolder( Settings.Downloads.CompletePath );
	}
	
	LibraryFolders.CreateAlbumTree();
	LibraryHashDB.Create();
	StartThread();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CLibrary save to disk

void CLibrary::Save()
{
	CSingleLock pLock( &m_pSection, TRUE );
	
	FILETIME pFileTime = { 0, 0 };
	SYSTEMTIME pSystemTime;
	CString strFile;
	CFile pFile;
	
	strFile.Format( _T("%s\\Data\\Library%i.dat"),
		(LPCTSTR)Settings.General.Path, m_nFileSwitch + 1 );
	
	m_nFileSwitch = ( m_nFileSwitch == 0 ) ? 1 : 0;
	
	if ( ! pFile.Open( strFile, CFile::modeWrite|CFile::modeCreate ) ) return;
	
	pFile.Write( &pFileTime, sizeof(FILETIME) );
	
	CArchive ar( &pFile, CArchive::store, 40960 );
	Serialize( ar );
	ar.Close();
	pFile.Flush();
	
	GetSystemTime( &pSystemTime );
	SystemTimeToFileTime( &pSystemTime, &pFileTime );
	pFile.Seek( 0, 0 );
	pFile.Write( &pFileTime, sizeof(FILETIME) );
	pFile.Close();
}

//////////////////////////////////////////////////////////////////////
// CLibrary serialize

#define LIBRARY_SER_VERSION	22

void CLibrary::Serialize(CArchive& ar)
{
	int nVersion = LIBRARY_SER_VERSION;
	
	if ( ar.IsStoring() )
	{
		ar << nVersion;
	}
	else
	{
		Clear();
		ar >> nVersion;
		if ( nVersion < 1 || nVersion > LIBRARY_SER_VERSION ) AfxThrowUserException();
	}
	
	LibraryMaps.Serialize1( ar, nVersion );
	LibraryFolders.Serialize( ar, nVersion );
	LibraryHistory.Serialize( ar, nVersion );
	LibraryMaps.Serialize2( ar, nVersion );
}

//////////////////////////////////////////////////////////////////////
// CLibrary thread control

void CLibrary::StartThread()
{
	if ( m_hThread == NULL )
	{
		m_bThread = TRUE;
		CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_BELOW_NORMAL );
		m_hThread = pThread->m_hThread;
	}
	
	LibraryBuilder.StartThread();
}

void CLibrary::StopThread()
{
	LibraryBuilder.StopThread();
	
	if ( m_hThread != NULL )
	{
		m_bThread = FALSE;
		m_pWakeup.SetEvent();
		
		for ( int nAttempt = 10 ; nAttempt > 0 ; nAttempt-- )
		{
			DWORD nCode;
			if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
			if ( nCode != STILL_ACTIVE ) break;
			Sleep( 200 );
		}
		
		if ( nAttempt == 0 )
		{
			TerminateThread( m_hThread, 0 );
			theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CLibrary thread.") );
			Sleep( 100 );
		}
		
		m_hThread = NULL;
	}
}

//////////////////////////////////////////////////////////////////////
// CLibrary thread run

UINT CLibrary::ThreadStart(LPVOID pParam)
{
	CLibrary* pLibrary = (CLibrary*)pParam;
	pLibrary->OnRun();
	return 0;
}

void CLibrary::OnRun()
{
	while ( m_bThread )
	{
		if ( m_nInhibit == 0 ) ThreadScan();
		WaitForSingleObject( m_pWakeup, 500 );
	}
}

//////////////////////////////////////////////////////////////////////
// CLibrary threaded scan

BOOL CLibrary::ThreadScan()
{
	BOOL bChanged = LibraryFolders.ThreadScan( &m_bThread, FALSE );
	
	CSingleLock pLock( &m_pSection, TRUE );
	
	m_nScanCount++;
	if ( bChanged ) m_nUpdateCookie = GetTickCount();
	
	if ( m_nUpdateCookie - m_nUpdateSaved > 5000 )
	{
		Save();
		m_nUpdateSaved = m_nUpdateCookie = GetTickCount();
	}
	
	LibraryDictionary.BuildHashTable();
	StartThread();
	
	return bChanged;
}

//////////////////////////////////////////////////////////////////////
// CLibrary library download queue

IMPLEMENT_DISPATCH_DISPATCH(CLibrary, Library)

STDMETHODIMP_(ULONG) CLibrary::XLibrary::AddRef()
{
	METHOD_PROLOGUE( CLibrary, Library )
	pThis->m_pSection.Lock();
	return pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CLibrary::XLibrary::Release()
{
	METHOD_PROLOGUE( CLibrary, Library )
	pThis->m_pSection.Unlock();
	return pThis->ExternalRelease();
}

STDMETHODIMP CLibrary::XLibrary::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE( CLibrary, Library )
	HRESULT hr = pThis->ExternalQueryInterface( &iid, ppvObj );
	if ( SUCCEEDED(hr) ) pThis->m_pSection.Lock();
	return hr;
}

STDMETHODIMP CLibrary::XLibrary::get_Application(IApplication FAR* FAR* ppApplication)
{
	METHOD_PROLOGUE( CLibrary, Library )
	if ( ppApplication == NULL ) return E_INVALIDARG;
	*ppApplication = Application.GetApp();
	return S_OK;
}

STDMETHODIMP CLibrary::XLibrary::get_Library(ILibrary FAR* FAR* ppLibrary)
{
	METHOD_PROLOGUE( CLibrary, Library )
	if ( ppLibrary == NULL ) return E_INVALIDARG;
	*ppLibrary = (ILibrary*)pThis->GetInterface( IID_ILibrary, TRUE );
	return S_OK;
}

STDMETHODIMP CLibrary::XLibrary::get_Folders(ILibraryFolders FAR* FAR* ppFolders)
{
	METHOD_PROLOGUE( CLibrary, Library )
	if ( ppFolders == NULL ) return E_INVALIDARG;
	*ppFolders = (ILibraryFolders*)pThis->GetInterface( IID_ILibraryFolders, TRUE );
	return S_OK;
}

STDMETHODIMP CLibrary::XLibrary::get_Albums(IUnknown FAR* FAR* ppAlbums)
{
	METHOD_PROLOGUE( CLibrary, Library )
	if ( ppAlbums == NULL ) return E_INVALIDARG;
	return E_NOTIMPL;
}

STDMETHODIMP CLibrary::XLibrary::get_Files(ILibraryFiles FAR* FAR* ppFiles)
{
	METHOD_PROLOGUE( CLibrary, Library )
	if ( ppFiles == NULL ) return E_INVALIDARG;
	*ppFiles = (ILibraryFiles*)pThis->GetInterface( IID_ILibraryFiles, TRUE );
	return S_OK;
}

STDMETHODIMP CLibrary::XLibrary::FindByName(BSTR sName, ILibraryFile FAR* FAR* ppFile)
{
	METHOD_PROLOGUE( CLibrary, Library )
	CLibraryFile* pFile = LibraryMaps.LookupFileByName( CString( sName ) );
	*ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
	return pFile ? S_OK : S_FALSE;
}

STDMETHODIMP CLibrary::XLibrary::FindByPath(BSTR sPath, ILibraryFile FAR* FAR* ppFile)
{
	METHOD_PROLOGUE( CLibrary, Library )
	CLibraryFile* pFile = LibraryMaps.LookupFileByPath( CString( sPath ) );
	*ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
	return pFile ? S_OK : S_FALSE;
}

STDMETHODIMP CLibrary::XLibrary::FindByURN(BSTR sURN, ILibraryFile FAR* FAR* ppFile)
{
	METHOD_PROLOGUE( CLibrary, Library )
	CLibraryFile* pFile = LibraryMaps.LookupFileByURN( CString( sURN ) );
	*ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
	return pFile ? S_OK : S_FALSE;
}

STDMETHODIMP CLibrary::XLibrary::FindByIndex(LONG nIndex, ILibraryFile FAR* FAR* ppFile)
{
	METHOD_PROLOGUE( CLibrary, Library )
	CLibraryFile* pFile = pThis->LookupFile( (DWORD)nIndex );
	*ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
	return pFile ? S_OK : S_FALSE;
}

⌨️ 快捷键说明

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