Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Library.cpp

Go to the documentation of this file.
00001 //
00002 // Library.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Library.h"
00026 #include "LibraryMaps.h"
00027 #include "LibraryFolders.h"
00028 #include "LibraryDictionary.h"
00029 #include "LibraryBuilder.h"
00030 #include "LibraryHistory.h"
00031 #include "HashDatabase.h"
00032 #include "SharedFolder.h"
00033 #include "SharedFile.h"
00034 #include "AlbumFolder.h"
00035 
00036 #include "QuerySearch.h"
00037 #include "Application.h"
00038 
00039 #include "XML.h"
00040 #include "Schema.h"
00041 #include "SchemaCache.h"
00042 
00043 #include "SHA.h"
00044 #include "ED2K.h"
00045 #include "TigerTree.h"
00046 
00047 IMPLEMENT_DYNAMIC(CLibrary, CComObject)
00048 
00049 BEGIN_INTERFACE_MAP(CLibrary, CComObject)
00050         INTERFACE_PART(CLibrary, IID_ILibrary, Library)
00051 END_INTERFACE_MAP()
00052 
00053 CLibrary Library;
00054 
00055 
00057 // CLibrary construction
00058 
00059 CLibrary::CLibrary()
00060 {
00061         EnableDispatch( IID_ILibrary );
00062 
00063         m_nUpdateSaved  = 0;
00064         m_nScanCount    = 0;
00065 
00066         m_hThread               = NULL;
00067         m_bThread               = TRUE;
00068         m_nScanCookie   = 1;
00069         m_nUpdateCookie = 0;
00070         m_nUpdateSaved  = 0;
00071         m_nFileSwitch   = 0;
00072         m_nInhibit              = 0;
00073 
00074         m_pfnGFAEW              = NULL;
00075         m_pfnGFAEA              = NULL;
00076 
00077         if ( m_hKernel = LoadLibrary( _T("kernel32") ) )
00078         {
00079                 (FARPROC&)m_pfnGFAEW = GetProcAddress( m_hKernel, "GetFileAttributesExW" );
00080                 (FARPROC&)m_pfnGFAEA = GetProcAddress( m_hKernel, "GetFileAttributesExA" );
00081         }
00082 }
00083 
00084 CLibrary::~CLibrary()
00085 {
00086         if ( m_hKernel != NULL ) FreeLibrary( m_hKernel );
00087 }
00088 
00090 // CLibrary locking
00091 
00092 void CLibrary::Inhibit(BOOL bInhibit)
00093 {
00094         if ( bInhibit )
00095                 InterlockedIncrement( (PLONG)&m_nInhibit );
00096         else
00097                 InterlockedDecrement( (PLONG)&m_nInhibit );
00098 }
00099 
00101 // CLibrary file and folder operations
00102 
00103 CLibraryFile* CLibrary::LookupFile(DWORD nIndex, BOOL bSharedOnly, BOOL bAvailableOnly)
00104 {
00105         return LibraryMaps.LookupFile( nIndex, bSharedOnly, bAvailableOnly );
00106 }
00107 
00108 CAlbumFolder* CLibrary::GetAlbumRoot()
00109 {
00110         return LibraryFolders.GetAlbumRoot();
00111 }
00112 
00113 void CLibrary::AddFile(CLibraryFile* pFile)
00114 {
00115         LibraryMaps.OnFileAdd( pFile );
00116 
00117         if ( pFile->m_bSHA1 )
00118         {
00119                 LibraryDictionary.Add( pFile );
00120         }
00121 
00122         if ( pFile->IsAvailable() )
00123         {
00124                 if ( pFile->m_bSHA1 || pFile->m_bTiger || pFile->m_bMD5 || pFile->m_bED2K )
00125                 {
00126                         LibraryHistory.Submit( pFile );
00127                         GetAlbumRoot()->OrganiseFile( pFile );
00128                 }
00129 
00130                 if ( ! pFile->m_bSHA1 || ! pFile->m_bTiger || ! pFile->m_bMD5 || ! pFile->m_bED2K )
00131                 {
00132                         LibraryBuilder.Add( pFile );
00133                 }
00134         }
00135 }
00136 
00137 void CLibrary::RemoveFile(CLibraryFile* pFile)
00138 {
00139         LibraryMaps.OnFileRemove( pFile );
00140 
00141         if ( pFile->m_nIndex )
00142         {
00143                 LibraryBuilder.Remove( pFile );
00144                 LibraryDictionary.Remove( pFile );
00145         }
00146 }
00147 
00148 void CLibrary::OnFileDelete(CLibraryFile* pFile)
00149 {
00150         ASSERT( pFile != NULL );
00151         
00152         LibraryFolders.OnFileDelete( pFile );
00153         LibraryHistory.OnFileDelete( pFile );
00154         LibraryHashDB.DeleteAll( pFile->m_nIndex );
00155 }
00156 
00158 // CLibrary search
00159 
00160 CPtrList* CLibrary::Search(CQuerySearch* pSearch, int nMaximum, BOOL bLocal)
00161 {
00162         CSingleLock oLock( &m_pSection );
00163 
00164         if ( !oLock.Lock( 50 ) ) return NULL;
00165 
00166         CPtrList* pHits = LibraryMaps.Search( pSearch, nMaximum, bLocal );
00167 
00168         if ( pHits == NULL && pSearch != NULL )
00169         {
00170                 pHits = LibraryDictionary.Search( pSearch, nMaximum, bLocal );
00171         }
00172 
00173         return pHits;
00174 }
00175 
00177 // CLibrary clear
00178 
00179 void CLibrary::Clear()
00180 {
00181         StopThread();
00182 
00183         CSingleLock pLock( &m_pSection, TRUE );
00184 
00185         LibraryHistory.Clear();
00186         LibraryDictionary.Clear();
00187         LibraryFolders.Clear();
00188         LibraryMaps.Clear();
00189 
00190         m_nUpdateCookie++;
00191 }
00192 
00194 // CLibrary load from disk
00195 
00196 BOOL CLibrary::Load()
00197 {
00198         CSingleLock pLock( &m_pSection, TRUE );
00199 
00200         GetAlbumRoot();
00201 
00202         FILETIME pFileTime1 = { 0, 0 }, pFileTime2 = { 0, 0 };
00203         CFile pFile1, pFile2;
00204         BOOL bFile1, bFile2;
00205         CString strFile;
00206 
00207         strFile = Settings.General.UserPath + _T("\\Data\\Library");
00208 
00209         bFile1 = pFile1.Open( strFile + _T("1.dat"), CFile::modeRead );
00210         bFile2 = pFile2.Open( strFile + _T("2.dat"), CFile::modeRead );
00211 
00212         if ( bFile1 || bFile2 )
00213         {
00214                 if ( bFile1 ) bFile1 = pFile1.Read( &pFileTime1, sizeof(FILETIME) ) == sizeof(FILETIME);
00215                 if ( bFile2 ) bFile2 = pFile2.Read( &pFileTime2, sizeof(FILETIME) ) == sizeof(FILETIME);
00216         }
00217         else
00218         {
00219                 bFile1 = pFile1.Open( strFile + _T(".dat"), CFile::modeRead );
00220                 pFileTime1.dwHighDateTime++;
00221         }
00222 
00223         if ( bFile1 || bFile2 )
00224         {
00225                 CFile* pNewest  = ( CompareFileTime( &pFileTime1, &pFileTime2 ) >= 0 )
00226                                                 ? &pFile1 : &pFile2;
00227 
00228                 try
00229                 {
00230                         CArchive ar( pNewest, CArchive::load, 40960 );
00231                         Serialize( ar );
00232                         ar.Close();
00233                 }
00234                 catch ( CException* pException )
00235                 {
00236                         pException->Delete();
00237                         Clear();
00238 
00239                         if ( pNewest == &pFile1 && bFile2 )
00240                                 pNewest = &pFile2;
00241                         else if ( pNewest == &pFile2 && bFile1 )
00242                                 pNewest = &pFile1;
00243                         else
00244                                 pNewest = NULL;
00245 
00246                         if ( pNewest != NULL )
00247                         {
00248                                 try
00249                                 {
00250                                         CArchive ar( pNewest, CArchive::load, 40960 );
00251                                         Serialize( ar );
00252                                         ar.Close();
00253                                 }
00254                                 catch ( CException* pException )
00255                                 {
00256                                         pException->Delete();
00257                                 }
00258                         }
00259                 }
00260 
00261                 pNewest->Close();
00262         }
00263         else
00264         {
00265                 CreateDirectory( Settings.Downloads.CompletePath, NULL );
00266                 LibraryFolders.AddFolder( Settings.Downloads.CompletePath );
00267 
00268                 CreateDirectory( Settings.Downloads.CollectionPath, NULL );
00269                 LibraryFolders.AddFolder( Settings.Downloads.CollectionPath );
00270 
00271                 //CreateDirectory( Settings.Downloads.TorrentPath, NULL );
00272                 //LibraryFolders.AddFolder( Settings.Downloads.TorrentPath, FALSE );
00273         }
00274 
00275         LibraryFolders.CreateAlbumTree();
00276         LibraryHashDB.Create();
00277         StartThread();
00278 
00279         LibraryBuilder.BoostPriority( Settings.Library.HighPriorityHash );
00280 
00281         return TRUE;
00282 }
00283 
00285 // CLibrary save to disk
00286 
00287 void CLibrary::Save()
00288 {
00289         CSingleLock pLock( &m_pSection, TRUE );
00290 
00291         FILETIME pFileTime = { 0, 0 };
00292         SYSTEMTIME pSystemTime;
00293         CString strFile;
00294         CFile pFile;
00295 
00296         strFile.Format( _T("%s\\Data\\Library%i.dat"),
00297                 (LPCTSTR)Settings.General.UserPath, m_nFileSwitch + 1 );
00298 
00299         m_nFileSwitch = ( m_nFileSwitch == 0 ) ? 1 : 0;
00300 
00301         if ( ! pFile.Open( strFile, CFile::modeWrite|CFile::modeCreate ) ) return;
00302 
00303         pFile.Write( &pFileTime, sizeof(FILETIME) );
00304 
00305         CArchive ar( &pFile, CArchive::store, 40960 );
00306         Serialize( ar );
00307         ar.Close();
00308         pFile.Flush();
00309 
00310         GetSystemTime( &pSystemTime );
00311         SystemTimeToFileTime( &pSystemTime, &pFileTime );
00312         pFile.Seek( 0, 0 );
00313         pFile.Write( &pFileTime, sizeof(FILETIME) );
00314         pFile.Close();
00315 }
00316 
00318 // CLibrary serialize
00319 
00320 #define LIBRARY_SER_VERSION     23
00321 
00322 void CLibrary::Serialize(CArchive& ar)
00323 {
00324         int nVersion = LIBRARY_SER_VERSION;
00325 
00326         if ( ar.IsStoring() )
00327         {
00328                 ar << nVersion;
00329         }
00330         else
00331         {
00332                 Clear();
00333                 ar >> nVersion;
00334                 if ( nVersion < 1 || nVersion > LIBRARY_SER_VERSION ) AfxThrowUserException();
00335         }
00336 
00337         LibraryMaps.Serialize1( ar, nVersion );
00338         LibraryFolders.Serialize( ar, nVersion );
00339         LibraryHistory.Serialize( ar, nVersion );
00340         LibraryMaps.Serialize2( ar, nVersion );
00341 }
00342 
00344 // CLibrary thread control
00345 
00346 void CLibrary::StartThread()
00347 {
00348         if ( m_hThread == NULL )
00349         {
00350                 m_bThread = TRUE;
00351                 CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_BELOW_NORMAL );
00352                 m_hThread = pThread->m_hThread;
00353         }
00354 
00355         LibraryBuilder.StartThread();
00356 }
00357 
00358 void CLibrary::StopThread()
00359 {
00360         LibraryBuilder.StopThread();
00361 
00362         if ( m_hThread != NULL )
00363         {
00364                 m_bThread = FALSE;
00365                 m_pWakeup.SetEvent();
00366 
00367         int nAttempt = 10;
00368                 for ( ; nAttempt > 0 ; nAttempt-- )
00369                 {
00370                         DWORD nCode;
00371                         if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00372                         if ( nCode != STILL_ACTIVE ) break;
00373                         Sleep( 200 );
00374                 }
00375 
00376                 if ( nAttempt == 0 )
00377                 {
00378                         TerminateThread( m_hThread, 0 );
00379                         theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CLibrary thread.") );
00380                         Sleep( 100 );
00381                 }
00382 
00383                 m_hThread = NULL;
00384         }
00385 }
00386 
00388 // CLibrary thread run
00389 
00390 UINT CLibrary::ThreadStart(LPVOID pParam)
00391 {
00392         CLibrary* pLibrary = (CLibrary*)pParam;
00393         pLibrary->OnRun();
00394         return 0;
00395 }
00396 
00397 void CLibrary::OnRun()
00398 {
00399         while ( m_bThread )
00400         {
00401                 if ( m_nInhibit == 0 ) ThreadScan();
00402                 WaitForSingleObject( m_pWakeup, 500 );
00403         }
00404 }
00405 
00407 // CLibrary threaded scan
00408 
00409 BOOL CLibrary::ThreadScan()
00410 {
00411         BOOL bChanged = LibraryFolders.ThreadScan( &m_bThread, FALSE );
00412 
00413         CSingleLock pLock( &m_pSection, TRUE );
00414 
00415         m_nScanCount++;
00416         if ( bChanged ) m_nUpdateCookie = GetTickCount();
00417 
00418         if ( m_nUpdateCookie - m_nUpdateSaved > 5000 )
00419         {
00420                 Save();
00421                 m_nUpdateSaved = m_nUpdateCookie = GetTickCount();
00422         }
00423 
00424         LibraryDictionary.BuildHashTable();
00425         StartThread();
00426 
00427         return bChanged;
00428 }
00429 
00431 // CLibrary library download queue
00432 
00433 IMPLEMENT_DISPATCH_DISPATCH(CLibrary, Library)
00434 
00435 STDMETHODIMP_(ULONG) CLibrary::XLibrary::AddRef()
00436 {
00437         METHOD_PROLOGUE( CLibrary, Library )
00438         pThis->m_pSection.Lock();
00439         return pThis->ExternalAddRef();
00440 }
00441 
00442 STDMETHODIMP_(ULONG) CLibrary::XLibrary::Release()
00443 {
00444         METHOD_PROLOGUE( CLibrary, Library )
00445         pThis->m_pSection.Unlock();
00446         return pThis->ExternalRelease();
00447 }
00448 
00449 STDMETHODIMP CLibrary::XLibrary::QueryInterface(REFIID iid, LPVOID* ppvObj)
00450 {
00451         METHOD_PROLOGUE( CLibrary, Library )
00452         HRESULT hr = pThis->ExternalQueryInterface( &iid, ppvObj );
00453         if ( SUCCEEDED(hr) ) pThis->m_pSection.Lock();
00454         return hr;
00455 }
00456 
00457 STDMETHODIMP CLibrary::XLibrary::get_Application(IApplication FAR* FAR* ppApplication)
00458 {
00459         METHOD_PROLOGUE( CLibrary, Library )
00460         if ( ppApplication == NULL ) return E_INVALIDARG;
00461         *ppApplication = Application.GetApp();
00462         return S_OK;
00463 }
00464 
00465 STDMETHODIMP CLibrary::XLibrary::get_Library(ILibrary FAR* FAR* ppLibrary)
00466 {
00467         METHOD_PROLOGUE( CLibrary, Library )
00468         if ( ppLibrary == NULL ) return E_INVALIDARG;
00469         *ppLibrary = (ILibrary*)pThis->GetInterface( IID_ILibrary, TRUE );
00470         return S_OK;
00471 }
00472 
00473 STDMETHODIMP CLibrary::XLibrary::get_Folders(ILibraryFolders FAR* FAR* ppFolders)
00474 {
00475         METHOD_PROLOGUE( CLibrary, Library )
00476         if ( ppFolders == NULL ) return E_INVALIDARG;
00477         *ppFolders = (ILibraryFolders*)pThis->GetInterface( IID_ILibraryFolders, TRUE );
00478         return S_OK;
00479 }
00480 
00481 STDMETHODIMP CLibrary::XLibrary::get_Albums(IUnknown FAR* FAR* ppAlbums)
00482 {
00483         METHOD_PROLOGUE( CLibrary, Library )
00484         if ( ppAlbums == NULL ) return E_INVALIDARG;
00485         return E_NOTIMPL;
00486 }
00487 
00488 STDMETHODIMP CLibrary::XLibrary::get_Files(ILibraryFiles FAR* FAR* ppFiles)
00489 {
00490         METHOD_PROLOGUE( CLibrary, Library )
00491         if ( ppFiles == NULL ) return E_INVALIDARG;
00492         *ppFiles = (ILibraryFiles*)pThis->GetInterface( IID_ILibraryFiles, TRUE );
00493         return S_OK;
00494 }
00495 
00496 STDMETHODIMP CLibrary::XLibrary::FindByName(BSTR sName, ILibraryFile FAR* FAR* ppFile)
00497 {
00498         METHOD_PROLOGUE( CLibrary, Library )
00499         CLibraryFile* pFile = LibraryMaps.LookupFileByName( CString( sName ) );
00500         *ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
00501         return pFile ? S_OK : S_FALSE;
00502 }
00503 
00504 STDMETHODIMP CLibrary::XLibrary::FindByPath(BSTR sPath, ILibraryFile FAR* FAR* ppFile)
00505 {
00506         METHOD_PROLOGUE( CLibrary, Library )
00507         CLibraryFile* pFile = LibraryMaps.LookupFileByPath( CString( sPath ) );
00508         *ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
00509         return pFile ? S_OK : S_FALSE;
00510 }
00511 
00512 STDMETHODIMP CLibrary::XLibrary::FindByURN(BSTR sURN, ILibraryFile FAR* FAR* ppFile)
00513 {
00514         METHOD_PROLOGUE( CLibrary, Library )
00515         CLibraryFile* pFile = LibraryMaps.LookupFileByURN( CString( sURN ) );
00516         *ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
00517         return pFile ? S_OK : S_FALSE;
00518 }
00519 
00520 STDMETHODIMP CLibrary::XLibrary::FindByIndex(LONG nIndex, ILibraryFile FAR* FAR* ppFile)
00521 {
00522         METHOD_PROLOGUE( CLibrary, Library )
00523         CLibraryFile* pFile = pThis->LookupFile( (DWORD)nIndex );
00524         *ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
00525         return pFile ? S_OK : S_FALSE;
00526 }

Generated on Thu Dec 15 10:39:43 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2