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 "Library.h"
00025 #include "LibraryMaps.h"
00026 #include "SharedFile.h"
00027
00028 #include "Application.h"
00029 #include "QuerySearch.h"
00030
00031 #include "SHA.h"
00032 #include "MD5.h"
00033 #include "ED2K.h"
00034 #include "TigerTree.h"
00035
00036 IMPLEMENT_DYNAMIC(CLibraryMaps, CComObject)
00037
00038 BEGIN_INTERFACE_MAP(CLibraryMaps, CComObject)
00039 INTERFACE_PART(CLibraryMaps, IID_ILibraryFiles, LibraryFiles)
00040 END_INTERFACE_MAP()
00041
00042 #define HASH_SIZE 512
00043 #define HASH_MASK 0x1FF
00044
00045 CLibraryMaps LibraryMaps;
00046
00047
00049
00050
00051 CLibraryMaps::CLibraryMaps()
00052 {
00053 EnableDispatch( IID_ILibraryFiles );
00054
00055 m_pSHA1Map = new CLibraryFile*[HASH_SIZE];
00056 m_pTigerMap = new CLibraryFile*[HASH_SIZE];
00057 m_pED2KMap = new CLibraryFile*[HASH_SIZE];
00058
00059 ZeroMemory( m_pSHA1Map, HASH_SIZE * 4 );
00060 ZeroMemory( m_pTigerMap, HASH_SIZE * 4 );
00061 ZeroMemory( m_pED2KMap, HASH_SIZE * 4 );
00062
00063 m_nNextIndex = 4;
00064 m_nFiles = 0;
00065 m_nVolume = 0;
00066 }
00067
00068 CLibraryMaps::~CLibraryMaps()
00069 {
00070 delete [] m_pED2KMap;
00071 delete [] m_pTigerMap;
00072 delete [] m_pSHA1Map;
00073 }
00074
00076
00077
00078 POSITION CLibraryMaps::GetFileIterator() const
00079 {
00080 return m_pIndexMap.GetStartPosition();
00081 }
00082
00083 CLibraryFile* CLibraryMaps::GetNextFile(POSITION& pos) const
00084 {
00085 LPVOID pIndex;
00086 CLibraryFile* pFile = NULL;
00087 m_pIndexMap.GetNextAssoc( pos, pIndex, (void*&)pFile );
00088 return pFile;
00089 }
00090
00091 int CLibraryMaps::GetFileCount() const
00092 {
00093 return m_pIndexMap.GetCount();
00094 }
00095
00096 void CLibraryMaps::GetStatistics(DWORD* pnFiles, QWORD* pnVolume)
00097 {
00098 if ( pnFiles ) *pnFiles = m_nFiles;
00099 if ( pnVolume ) *pnVolume = m_nVolume;
00100 }
00101
00103
00104
00105 CLibraryFile* CLibraryMaps::LookupFile(DWORD nIndex, BOOL bSharedOnly, BOOL bAvailableOnly)
00106 {
00107 if ( ! nIndex ) return NULL;
00108
00109 CLibraryFile* pFile = NULL;
00110
00111 CQuickLock oLock( Library.m_pSection );
00112
00113 if ( m_pIndexMap.Lookup( (LPVOID)nIndex, (void*&)pFile ) && ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00114 {
00115 return pFile;
00116 }
00117
00118 return NULL;
00119 }
00120
00122
00123
00124 CLibraryFile* CLibraryMaps::LookupFileByName(LPCTSTR pszName, BOOL bSharedOnly, BOOL bAvailableOnly)
00125 {
00126 CLibraryFile* pFile = NULL;
00127 CString strName( pszName );
00128
00129 CQuickLock oLock( Library.m_pSection );
00130 CharLower( strName.GetBuffer() );
00131 strName.ReleaseBuffer();
00132
00133 if ( m_pNameMap.Lookup( strName, (CObject*&)pFile ) && ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00134 {
00135 return pFile;
00136 }
00137
00138 return NULL;
00139 }
00140
00141 CLibraryFile* CLibraryMaps::LookupFileByPath(LPCTSTR pszPath, BOOL bSharedOnly, BOOL bAvailableOnly)
00142 {
00143 CLibraryFile* pFile = NULL;
00144
00145 CQuickLock oLock( Library.m_pSection );
00146
00147 if ( m_pPathMap.Lookup( pszPath, (CObject*&)pFile ) && ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00148 {
00149 return pFile;
00150 }
00151
00152 return NULL;
00153 }
00154
00156
00157
00158 CLibraryFile* CLibraryMaps::LookupFileByURN(LPCTSTR pszURN, BOOL bSharedOnly, BOOL bAvailableOnly)
00159 {
00160 CLibraryFile* pFile;
00161 TIGEROOT pTiger;
00162 SHA1 pSHA1;
00163 MD4 pED2K;
00164
00165 if ( CSHA::HashFromURN( pszURN, &pSHA1 ) )
00166 {
00167 if ( pFile = LookupFileBySHA1( &pSHA1, bSharedOnly ) ) return pFile;
00168 }
00169
00170 if ( CTigerNode::HashFromURN( pszURN, &pTiger ) )
00171 {
00172 if ( pFile = LookupFileByTiger( &pTiger, bSharedOnly ) ) return pFile;
00173 }
00174
00175 if ( CED2K::HashFromURN( pszURN, &pED2K ) )
00176 {
00177 if ( pFile = LookupFileByED2K( &pED2K, bSharedOnly ) ) return pFile;
00178 }
00179
00180 return NULL;
00181 }
00182
00184
00185
00186 CLibraryFile* CLibraryMaps::LookupFileBySHA1(const SHA1* pSHA1,BOOL bSharedOnly, BOOL bAvailableOnly)
00187 {
00188 CQuickLock oLock( Library.m_pSection );
00189
00190 CLibraryFile* pFile = m_pSHA1Map[ *(WORD*)pSHA1 & HASH_MASK ];
00191
00192 for ( ; pFile ; pFile = pFile->m_pNextSHA1 )
00193 {
00194 if ( *pSHA1 == pFile->m_pSHA1 )
00195 {
00196 if ( ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00197 {
00198 return pFile;
00199 }
00200 else
00201 {
00202 return NULL;
00203 }
00204 }
00205 }
00206
00207 return NULL;
00208 }
00209
00210 CLibraryFile* CLibraryMaps::LookupFileByTiger(const TIGEROOT* pTiger, BOOL bSharedOnly, BOOL bAvailableOnly)
00211 {
00212 CQuickLock oLock( Library.m_pSection );
00213
00214 CLibraryFile* pFile = m_pTigerMap[ *(WORD*)pTiger & HASH_MASK ];
00215
00216 for ( ; pFile ; pFile = pFile->m_pNextTiger )
00217 {
00218 if ( *pTiger == pFile->m_pTiger )
00219 {
00220 if ( ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00221 {
00222 return pFile;
00223 }
00224 else
00225 {
00226 return NULL;
00227 }
00228 }
00229 }
00230
00231 return NULL;
00232 }
00233
00234 CLibraryFile* CLibraryMaps::LookupFileByED2K(const MD4* pED2K, BOOL bSharedOnly, BOOL bAvailableOnly)
00235 {
00236 CQuickLock oLock( Library.m_pSection );
00237
00238 CLibraryFile* pFile = m_pED2KMap[ *(WORD*)pED2K & HASH_MASK ];
00239
00240 for ( ; pFile ; pFile = pFile->m_pNextED2K )
00241 {
00242 if ( *pED2K == pFile->m_pED2K )
00243 {
00244 if ( ( ! bSharedOnly || pFile->IsShared() ) && ( ! bAvailableOnly || pFile->IsAvailable() ) )
00245 {
00246 return pFile;
00247 }
00248 else
00249 {
00250 return NULL;
00251 }
00252 }
00253 }
00254
00255 return NULL;
00256 }
00257
00259
00260
00261 void CLibraryMaps::Clear()
00262 {
00263 for ( POSITION pos = GetFileIterator() ; pos ; ) delete GetNextFile( pos );
00264
00265 ASSERT( m_pIndexMap.GetCount() == 0 );
00266 ASSERT( m_pNameMap.GetCount() == 0 );
00267 ASSERT( m_pPathMap.GetCount() == 0 );
00268
00269 ZeroMemory( m_pSHA1Map, HASH_SIZE * 4 );
00270 ZeroMemory( m_pTigerMap, HASH_SIZE * 4 );
00271 ZeroMemory( m_pED2KMap, HASH_SIZE * 4 );
00272
00273 m_nFiles = 0;
00274 m_nVolume = 0;
00275 }
00276
00278
00279
00280 DWORD CLibraryMaps::AllocateIndex()
00281 {
00282 while ( ( m_nNextIndex & 3 ) == 0 || LookupFile( m_nNextIndex ) ) m_nNextIndex++;
00283 return m_nNextIndex;
00284 }
00285
00287
00288
00289 void CLibraryMaps::OnFileAdd(CLibraryFile* pFile)
00290 {
00291 BOOL bSkipStats = FALSE;
00292 if ( pFile->m_nIndex )
00293 {
00294 if ( CLibraryFile* pOld = LookupFile( pFile->m_nIndex ) )
00295 {
00296 if ( pOld != pFile )
00297 {
00298 pFile->m_nIndex = AllocateIndex();
00299 m_pIndexMap.SetAt( (LPVOID)pFile->m_nIndex, pFile );
00300 }
00301 else
00302 {
00303 bSkipStats = TRUE;
00304 }
00305 }
00306 else
00307 {
00308 m_pIndexMap.SetAt( (LPVOID)pFile->m_nIndex, pFile );
00309 }
00310 }
00311 else
00312 {
00313 pFile->m_nIndex = AllocateIndex();
00314 m_pIndexMap.SetAt( (LPVOID)pFile->m_nIndex, pFile );
00315 }
00316
00317 if ( ( pFile->m_pFolder != NULL ) && ( ! bSkipStats ) )
00318 {
00319 m_nVolume += ( pFile->m_nSize >> 10 );
00320 m_nFiles ++;
00321 }
00322
00323 m_pNameMap.SetAt( pFile->GetNameLC(), pFile );
00324
00325 if ( pFile->m_pFolder != NULL )
00326 {
00327 m_pPathMap.SetAt( pFile->GetPath(), pFile );
00328 }
00329 else if ( m_pDeleted.Find( pFile ) == NULL )
00330 {
00331 m_pDeleted.AddTail( pFile );
00332 }
00333
00334 if ( pFile->m_bSHA1 )
00335 {
00336 CLibraryFile** pHash = &m_pSHA1Map[ *(WORD*)&pFile->m_pSHA1 & HASH_MASK ];
00337 pFile->m_pNextSHA1 = *pHash;
00338 *pHash = pFile;
00339 }
00340
00341 if ( pFile->m_bTiger )
00342 {
00343 CLibraryFile** pHash = &m_pTigerMap[ *(WORD*)&pFile->m_pTiger & HASH_MASK ];
00344 pFile->m_pNextTiger = *pHash;
00345 *pHash = pFile;
00346 }
00347
00348 if ( pFile->m_bED2K )
00349 {
00350 CLibraryFile** pHash = &m_pED2KMap[ *(WORD*)&pFile->m_pED2K & HASH_MASK ];
00351 pFile->m_pNextED2K = *pHash;
00352 *pHash = pFile;
00353 }
00354 }
00355
00357
00358
00359 void CLibraryMaps::OnFileRemove(CLibraryFile* pFile)
00360 {
00361 CLibraryFile* pOld;
00362
00363 if ( pFile->m_nIndex )
00364 {
00365 pOld = LookupFile( pFile->m_nIndex );
00366
00367 if ( pOld == pFile )
00368 {
00369 m_pIndexMap.RemoveKey( (LPVOID)pFile->m_nIndex );
00370
00371 if ( pOld->m_pFolder != NULL )
00372 {
00373 m_nFiles --;
00374 m_nVolume -= ( pFile->m_nSize >> 10 );
00375 }
00376 }
00377 }
00378
00379 pOld = LookupFileByName( pFile->GetNameLC() );
00380 if ( pOld == pFile ) m_pNameMap.RemoveKey( pFile->GetNameLC() );
00381
00382 if ( pFile->m_pFolder != NULL )
00383 {
00384 pOld = LookupFileByPath( pFile->GetPath() );
00385 if ( pOld == pFile ) m_pPathMap.RemoveKey( pFile->GetPath() );
00386 }
00387
00388 if ( POSITION pos = m_pDeleted.Find( pFile ) )
00389 m_pDeleted.RemoveAt( pos );
00390
00391 if ( pFile->m_bSHA1 )
00392 {
00393 CLibraryFile** pPrev = &m_pSHA1Map[ *(WORD*)&pFile->m_pSHA1 & HASH_MASK ];
00394
00395 for ( CLibraryFile* pOther = *pPrev ; pOther ; pOther = pOther->m_pNextSHA1 )
00396 {
00397 if ( pOther == pFile )
00398 {
00399 *pPrev = pOther->m_pNextSHA1;
00400 break;
00401 }
00402 pPrev = &pOther->m_pNextSHA1;
00403 }
00404
00405 pFile->m_pNextSHA1 = NULL;
00406 }
00407
00408 if ( pFile->m_bTiger )
00409 {
00410 CLibraryFile** pPrev = &m_pTigerMap[ *(WORD*)&pFile->m_pTiger & HASH_MASK ];
00411
00412 for ( CLibraryFile* pOther = *pPrev ; pOther ; pOther = pOther->m_pNextTiger )
00413 {
00414 if ( pOther == pFile )
00415 {
00416 *pPrev = pOther->m_pNextTiger;
00417 break;
00418 }
00419 pPrev = &pOther->m_pNextTiger;
00420 }
00421
00422 pFile->m_pNextTiger = NULL;
00423 }
00424
00425 if ( pFile->m_bED2K )
00426 {
00427 CLibraryFile** pPrev = &m_pED2KMap[ *(WORD*)&pFile->m_pED2K & HASH_MASK ];
00428
00429 for ( CLibraryFile* pOther = *pPrev ; pOther ; pOther = pOther->m_pNextED2K )
00430 {
00431 if ( pOther == pFile )
00432 {
00433 *pPrev = pOther->m_pNextED2K;
00434 break;
00435 }
00436 pPrev = &pOther->m_pNextED2K;
00437 }
00438
00439 pFile->m_pNextED2K = NULL;
00440 }
00441 }
00442
00444
00445
00446 void CLibraryMaps::CullDeletedFiles(CLibraryFile* pMatch)
00447 {
00448 CSingleLock oLock( &Library.m_pSection );
00449 if ( !oLock.Lock( 100 ) ) return;
00450 CLibraryFile* pFile;
00451
00452 if ( pMatch->m_bSHA1 )
00453 {
00454 if ( pFile = LookupFileBySHA1( &pMatch->m_pSHA1 ) )
00455 {
00456 if ( ! pFile->IsAvailable() ) pFile->Delete();
00457 }
00458 }
00459
00460 if ( pMatch->m_bTiger )
00461 {
00462 if ( pFile = LookupFileByTiger( &pMatch->m_pTiger ) )
00463 {
00464 if ( ! pFile->IsAvailable() ) pFile->Delete();
00465 }
00466 }
00467
00468 if ( pMatch->m_bED2K )
00469 {
00470 if ( pFile = LookupFileByED2K( &pMatch->m_pED2K ) )
00471 {
00472 if ( ! pFile->IsAvailable() ) pFile->Delete();
00473 }
00474 }
00475
00476 }
00477
00479
00480
00481 CPtrList* CLibraryMaps::Search(CQuerySearch* pSearch, int nMaximum, BOOL bLocal)
00482 {
00483 CPtrList* pHits = NULL;
00484
00485 if ( pSearch == NULL )
00486 {
00487 for ( POSITION pos = GetFileIterator() ; pos ; )
00488 {
00489 CLibraryFile* pFile = GetNextFile( pos );
00490
00491 if ( pFile->IsAvailable() )
00492 {
00493 if ( bLocal || ( pFile->IsShared() && pFile->m_bSHA1 ) )
00494 {
00495 if ( ! pHits ) pHits = new CPtrList( 64 );
00496 pHits->AddTail( pFile );
00497 }
00498 }
00499 }
00500 }
00501 else if ( pSearch->m_bSHA1 )
00502 {
00503 if ( CLibraryFile* pFile = LookupFileBySHA1( &pSearch->m_pSHA1 ) )
00504 {
00505 if ( bLocal || pFile->IsShared() )
00506 {
00507 pHits = new CPtrList();
00508 pHits->AddTail( pFile );
00509
00510 if ( ! bLocal )
00511 {
00512 pFile->m_nHitsToday++;
00513 pFile->m_nHitsTotal++;
00514 }
00515 }
00516 }
00517 }
00518 else if ( pSearch->m_bTiger )
00519 {
00520 if ( CLibraryFile* pFile = LookupFileByTiger( &pSearch->m_pTiger ) )
00521 {
00522 if ( bLocal || pFile->IsShared() )
00523 {
00524 pHits = new CPtrList();
00525 pHits->AddTail( pFile );
00526
00527 if ( ! bLocal )
00528 {
00529 pFile->m_nHitsToday++;
00530 pFile->m_nHitsTotal++;
00531 }
00532 }
00533 }
00534 }
00535 else if ( pSearch->m_bED2K )
00536 {
00537 for ( POSITION pos = GetFileIterator() ; pos ; )
00538 {
00539 CLibraryFile* pFile = GetNextFile( pos );
00540
00541 if ( pFile->m_bED2K && pFile->m_pED2K == pSearch->m_pED2K )
00542 {
00543 if ( bLocal || ( pFile->IsShared() && pFile->m_bSHA1 ) )
00544 {
00545 if ( ! pHits ) pHits = new CPtrList( 64 );
00546 pHits->AddTail( pFile );
00547 }
00548 }
00549 }
00550 }
00551
00552 return pHits;
00553 }
00554
00556
00557
00558 void CLibraryMaps::Serialize1(CArchive& ar, int nVersion)
00559 {
00560 if ( ar.IsStoring() )
00561 {
00562 ar << m_nNextIndex;
00563 }
00564 else
00565 {
00566 ar >> m_nNextIndex;
00567 }
00568 }
00569
00570 void CLibraryMaps::Serialize2(CArchive& ar, int nVersion)
00571 {
00572 if ( nVersion < 18 ) return;
00573
00574 if ( ar.IsStoring() )
00575 {
00576 ar.WriteCount( m_pDeleted.GetCount() );
00577
00578 for ( POSITION pos = m_pDeleted.GetHeadPosition() ; pos ; )
00579 {
00580 CLibraryFile* pFile = (CLibraryFile*)m_pDeleted.GetNext( pos );
00581 pFile->Serialize( ar, nVersion );
00582 }
00583 }
00584 else
00585 {
00586 for ( int nCount = ar.ReadCount() ; nCount > 0 ; nCount-- )
00587 {
00588 CLibraryFile* pFile = new CLibraryFile( NULL );
00589 pFile->Serialize( ar, nVersion );
00590 }
00591 }
00592 }
00593
00595
00596
00597 IMPLEMENT_DISPATCH(CLibraryMaps, LibraryFiles)
00598
00599 STDMETHODIMP CLibraryMaps::XLibraryFiles::get_Application(IApplication FAR* FAR* ppApplication)
00600 {
00601 METHOD_PROLOGUE( CLibraryMaps, LibraryFiles )
00602 *ppApplication = Application.GetApp();
00603 return S_OK;
00604 }
00605
00606 STDMETHODIMP CLibraryMaps::XLibraryFiles::get_Library(ILibrary FAR* FAR* ppLibrary)
00607 {
00608 METHOD_PROLOGUE( CLibraryMaps, LibraryFiles )
00609 *ppLibrary = (ILibrary*)Library.GetInterface( IID_ILibrary, TRUE );
00610 return S_OK;
00611 }
00612
00613 STDMETHODIMP CLibraryMaps::XLibraryFiles::get__NewEnum(IUnknown FAR* FAR* ppEnum)
00614 {
00615 METHOD_PROLOGUE( CLibraryMaps, LibraryFiles )
00616 return E_NOTIMPL;
00617 }
00618
00619 STDMETHODIMP CLibraryMaps::XLibraryFiles::get_Item(VARIANT vIndex, ILibraryFile FAR* FAR* ppFile)
00620 {
00621 METHOD_PROLOGUE( CLibraryMaps, LibraryFiles )
00622
00623 CLibraryFile* pFile = NULL;
00624 *ppFile = NULL;
00625
00626 if ( vIndex.vt == VT_BSTR )
00627 {
00628 CString strName( vIndex.bstrVal );
00629 if ( strName.Find( '\\' ) >= 0 )
00630 pFile = pThis->LookupFileByPath( strName );
00631 else
00632 pFile = pThis->LookupFileByName( strName );
00633 }
00634 else
00635 {
00636 VARIANT va;
00637 VariantInit( &va );
00638
00639 if ( FAILED( VariantChangeType( &va, (VARIANT FAR*)&vIndex, 0, VT_I4 ) ) )
00640 return E_INVALIDARG;
00641 if ( va.lVal < 0 || va.lVal >= pThis->GetFileCount() )
00642 return E_INVALIDARG;
00643
00644 for ( POSITION pos = pThis->GetFileIterator() ; pos ; )
00645 {
00646 pFile = pThis->GetNextFile( pos );
00647 if ( va.lVal-- == 0 ) break;
00648 pFile = NULL;
00649 }
00650 }
00651
00652 *ppFile = pFile ? (ILibraryFile*)pFile->GetInterface( IID_ILibraryFile, TRUE ) : NULL;
00653
00654 return S_OK;
00655 }
00656
00657 STDMETHODIMP CLibraryMaps::XLibraryFiles::get_Count(LONG FAR* pnCount)
00658 {
00659 METHOD_PROLOGUE( CLibraryMaps, LibraryFiles )
00660 *pnCount = pThis->GetFileCount();
00661 return S_OK;
00662 }