00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
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
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
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
00272
00273 }
00274
00275 LibraryFolders.CreateAlbumTree();
00276 LibraryHashDB.Create();
00277 StartThread();
00278
00279 LibraryBuilder.BoostPriority( Settings.Library.HighPriorityHash );
00280
00281 return TRUE;
00282 }
00283
00285
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
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
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
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
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
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 }