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 "Downloads.h"
00026 #include "DownloadWithFile.h"
00027 #include "DownloadSource.h"
00028 #include "DownloadTransfer.h"
00029 #include "DownloadGroups.h"
00030 #include "FragmentedFile.h"
00031 #include "Uploads.h"
00032
00033 #include "ID3.h"
00034 #include "SHA.h"
00035 #include "XML.h"
00036 #include "Schema.h"
00037 #include "LibraryBuilderInternals.h"
00038
00039 #ifdef _DEBUG
00040 #undef THIS_FILE
00041 static char THIS_FILE[]=__FILE__;
00042 #define new DEBUG_NEW
00043 #endif
00044
00045
00047
00048
00049 CDownloadWithFile::CDownloadWithFile()
00050 {
00051 m_pFile = new CFragmentedFile();
00052 m_tReceived = GetTickCount();
00053 m_bDiskFull = FALSE;
00054 }
00055
00056 CDownloadWithFile::~CDownloadWithFile()
00057 {
00058 if ( m_pFile != NULL ) delete m_pFile;
00059 }
00060
00062
00063
00064 BOOL CDownloadWithFile::OpenFile()
00065 {
00066 if ( m_pFile == NULL || m_sRemoteName.IsEmpty() || m_nSize == SIZE_UNKNOWN ) return FALSE;
00067 if ( m_pFile->IsOpen() ) return TRUE;
00068
00069 SetModified();
00070
00071 if ( m_pFile->IsValid() )
00072 {
00073 if ( m_pFile->Open( m_sLocalName ) ) return TRUE;
00074 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILE_OPEN_ERROR, (LPCTSTR)m_sLocalName );
00075 }
00076 else if ( ! Downloads.IsSpaceAvailable( m_nSize, Downloads.dlPathIncomplete ) )
00077 {
00078 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_DISK_SPACE,
00079 (LPCTSTR)m_sRemoteName,
00080 (LPCTSTR)Settings.SmartVolume( m_nSize, FALSE ) );
00081 }
00082 else
00083 {
00084 CString strLocalName = m_sLocalName;
00085 m_sLocalName.Empty();
00086
00087 GenerateLocalName();
00088
00089 for ( int nTry = 0 ; nTry < 5 ; nTry++ )
00090 {
00091 CString strName;
00092
00093 if ( nTry == 0 )
00094 strName = m_sLocalName;
00095 else
00096 strName.Format( _T("%s.x%i"), (LPCTSTR)m_sLocalName, rand() % 128 );
00097
00098 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FILE_CREATE, (LPCTSTR)strName );
00099
00100 if ( m_pFile->Create( strName, m_nSize ) )
00101 {
00102 theApp.WriteProfileString( _T("Delete"), strName, NULL );
00103 MoveFile( strLocalName + _T(".sd"), strName + _T(".sd") );
00104 m_sLocalName = strName;
00105 return TRUE;
00106 }
00107
00108 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILE_CREATE_ERROR, (LPCTSTR)strName );
00109 }
00110
00111 m_sLocalName = strLocalName;
00112 }
00113
00114 m_bDiskFull = TRUE;
00115
00116 return FALSE;
00117 }
00118
00120
00121
00122 void CDownloadWithFile::CloseFile()
00123 {
00124 if ( m_pFile != NULL ) m_pFile->Close();
00125 }
00126
00128
00129
00130 BOOL CDownloadWithFile::PrepareFile()
00131 {
00132 return OpenFile() && m_pFile->GetRemaining() > 0;
00133 }
00134
00136
00137
00138 void CDownloadWithFile::DeleteFile(BOOL bForce)
00139 {
00140 if ( m_pFile != NULL && m_pFile->IsValid() == FALSE ) return;
00141
00142 Uploads.OnRename( m_sLocalName, NULL );
00143
00144 int nPos = m_sLocalName.ReverseFind( '\\' );
00145 CString strMetadata;
00146
00147 if ( nPos > 0 )
00148 {
00149 strMetadata = m_sLocalName.Left( nPos ) + _T("\\Metadata") + m_sLocalName.Mid( nPos ) + _T(".xml");
00150 }
00151
00152 if ( m_pFile != NULL )
00153 {
00154 if ( GetVolumeComplete() == 0 || ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 )
00155 {
00156 if ( ! ::DeleteFile( m_sLocalName ) )
00157 theApp.WriteProfileString( _T("Delete"), m_sLocalName, _T("") );
00158 if ( strMetadata.GetLength() ) ::DeleteFile( strMetadata );
00159 }
00160 else
00161 {
00162 MoveFile( m_sLocalName, m_sLocalName + _T(".aborted") );
00163 }
00164 }
00165 else if ( bForce )
00166 {
00167 if ( ! ::DeleteFile( m_sLocalName ) )
00168 theApp.WriteProfileString( _T("Delete"), m_sLocalName, _T("") );
00169 if ( strMetadata.GetLength() ) ::DeleteFile( strMetadata );
00170 }
00171
00172 SetModified();
00173 }
00174
00176
00177
00178 float CDownloadWithFile::GetProgress() const
00179 {
00180 if ( m_nSize == 0 || m_nSize == SIZE_UNKNOWN ) return 0;
00181 return (float)GetVolumeComplete() / (float)m_nSize;
00182 }
00183
00184 QWORD CDownloadWithFile::GetVolumeComplete() const
00185 {
00186 if ( m_pFile != NULL )
00187 {
00188 if ( m_pFile->IsValid() )
00189 return m_pFile->GetCompleted();
00190 else
00191 return 0;
00192 }
00193 else
00194 {
00195 return m_nSize;
00196 }
00197 }
00198
00199 QWORD CDownloadWithFile::GetVolumeRemaining() const
00200 {
00201 if ( m_pFile != NULL )
00202 {
00203 if ( m_pFile->IsValid() )
00204 return m_pFile->GetRemaining();
00205 else if ( m_nSize != SIZE_UNKNOWN )
00206 return m_nSize;
00207 }
00208
00209 return 0;
00210 }
00211
00212 DWORD CDownloadWithFile::GetTimeRemaining() const
00213 {
00214 QWORD nRemaining = GetVolumeRemaining();
00215 DWORD nSpeed = GetAverageSpeed();
00216 if ( nSpeed == 0 ) return 0xFFFFFFFF;
00217 return (DWORD)( nRemaining / nSpeed );
00218 }
00219
00220 CString CDownloadWithFile::GetDisplayName() const
00221 {
00222 if ( m_sRemoteName.GetLength() ) return m_sRemoteName;
00223
00224 CString strName;
00225
00226 if ( m_bSHA1 )
00227 strName = _T("sha1:") + CSHA::HashToString( &m_pSHA1 );
00228 else
00229 strName = _T("Unknown File");
00230
00231 return strName;
00232 }
00233
00235
00236
00237 const FF::SimpleFragmentList& CDownloadWithFile::GetEmptyFragmentList() const
00238 {
00239 static const FF::SimpleFragmentList dummy( 0 );
00240 return m_pFile ? m_pFile->GetEmptyFragmentList() : dummy;
00241 }
00242
00244
00245
00246 FF::SimpleFragmentList CDownloadWithFile::GetPossibleFragments(
00247 const FF::SimpleFragmentList& oAvailable, FF::SimpleFragment& oLargest)
00248 {
00249 if ( !PrepareFile() ) return FF::SimpleFragmentList( oAvailable.limit() );
00250 FF::SimpleFragmentList oPossible( oAvailable );
00251
00252 if( oAvailable.empty() )
00253 {
00254 oPossible = m_pFile->GetEmptyFragmentList();
00255 }
00256 else
00257 {
00258
00259 FF::SimpleFragmentList tmp( inverse( m_pFile->GetEmptyFragmentList() ) );
00260 oPossible.erase( tmp.begin(), tmp.end() );
00261 }
00262
00263 if ( oPossible.empty() ) return oPossible;
00264
00265 oLargest = *largestFragment( oPossible );
00266
00267 for ( CDownloadTransfer* pTransfer = GetFirstTransfer();
00268 !oPossible.empty() && pTransfer;
00269 pTransfer = pTransfer->m_pDlNext )
00270 {
00271 pTransfer->SubtractRequested( oPossible );
00272 }
00273
00274 return oPossible;
00275 }
00276
00278
00279
00280 BOOL CDownloadWithFile::GetFragment(CDownloadTransfer* pTransfer)
00281 {
00282 if ( ! PrepareFile() ) return NULL;
00283
00284 FF::SimpleFragment oLargest( SIZE_UNKNOWN, SIZE_UNKNOWN );
00285
00286 FF::SimpleFragmentList oPossible = GetPossibleFragments(
00287 pTransfer->m_pSource->m_oAvailable, oLargest );
00288
00289 if ( oLargest.begin() == SIZE_UNKNOWN )
00290 {
00291 ASSERT( oPossible.empty() );
00292 return FALSE;
00293 }
00294
00295 if ( !oPossible.empty() )
00296 {
00297 FF::SimpleFragmentList::ConstIterator pRandom
00298 = oPossible.begin()->begin() == 0
00299 ? oPossible.begin()
00300 : randomFragment( oPossible );
00301
00302 pTransfer->m_nOffset = pRandom->begin();
00303 pTransfer->m_nLength = pRandom->length();
00304
00305 return TRUE;
00306 }
00307 else
00308 {
00309 CDownloadTransfer* pExisting = NULL;
00310
00311 for ( CDownloadTransfer* pOther = GetFirstTransfer() ; pOther ; pOther = pOther->m_pDlNext )
00312 {
00313 if ( pOther->m_bRecvBackwards )
00314 {
00315 if ( pOther->m_nOffset + pOther->m_nLength - pOther->m_nPosition
00316 != oLargest.end() ) continue;
00317 }
00318 else
00319 {
00320 if ( pOther->m_nOffset + pOther->m_nPosition != oLargest.begin() ) continue;
00321 }
00322
00323 pExisting = pOther;
00324 break;
00325 }
00326
00327 if ( pExisting == NULL )
00328 {
00329 pTransfer->m_nOffset = oLargest.begin();
00330 pTransfer->m_nLength = oLargest.length();
00331 return TRUE;
00332 }
00333
00334 if ( oLargest.length() < 32 ) return FALSE;
00335
00336 DWORD nOldSpeed = pExisting->GetAverageSpeed();
00337 DWORD nNewSpeed = pTransfer->GetAverageSpeed();
00338 QWORD nLength = oLargest.length() / 2;
00339
00340 if ( nOldSpeed > 5 && nNewSpeed > 5 )
00341 {
00342 nLength = (QWORD)( (double)oLargest.length() * nNewSpeed / ( nNewSpeed + nOldSpeed ) );
00343 nLength = min( nLength, oLargest.length() );
00344
00345 if ( oLargest.length() > 102400 )
00346 {
00347 nLength = max( nLength, 51200ULL );
00348 nLength = min( nLength, oLargest.length() - 51200ULL );
00349 }
00350 }
00351
00352 if ( pExisting->m_bRecvBackwards )
00353 {
00354 pTransfer->m_nOffset = oLargest.begin();
00355 pTransfer->m_nLength = nLength;
00356 pTransfer->m_bWantBackwards = FALSE;
00357 }
00358 else
00359 {
00360 pTransfer->m_nOffset = oLargest.end() - nLength;
00361 pTransfer->m_nLength = nLength;
00362 pTransfer->m_bWantBackwards = TRUE;
00363 }
00364
00365 return TRUE;
00366 }
00367 }
00368
00370
00371
00372 BOOL CDownloadWithFile::IsPositionEmpty(QWORD nOffset)
00373 {
00374 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00375 return m_pFile->IsPositionRemaining( nOffset );
00376 }
00377
00379
00380
00381 BOOL CDownloadWithFile::AreRangesUseful(const FF::SimpleFragmentList& oAvailable)
00382 {
00383 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00384 return overlaps( m_pFile->GetEmptyFragmentList(), oAvailable );
00385 }
00386
00387 BOOL CDownloadWithFile::IsRangeUseful(QWORD nOffset, QWORD nLength)
00388 {
00389 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00390 return overlaps( m_pFile->GetEmptyFragmentList(),
00391 FF::SimpleFragment( nOffset, nOffset + nLength ) );
00392 }
00393
00394
00395
00396 BOOL CDownloadWithFile::IsRangeUsefulEnough(CDownloadTransfer* pTransfer, QWORD nOffset, QWORD nLength)
00397 {
00398 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00399
00400
00401 DWORD nLength2 = 5 * pTransfer->GetAverageSpeed();
00402 if ( nLength2 < nLength )
00403 {
00404 if ( !pTransfer->m_bRecvBackwards ) nOffset += nLength - nLength2;
00405 nLength = nLength2;
00406 }
00407 return overlaps( m_pFile->GetEmptyFragmentList(),
00408 FF::SimpleFragment( nOffset, nOffset + nLength ) );
00409 }
00410
00412
00413
00414 CString CDownloadWithFile::GetAvailableRanges() const
00415 {
00416 CString strRange, strRanges;
00417
00418 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return strRanges;
00419
00420 const FF::SimpleFragmentList oAvailable = inverse( m_pFile->GetEmptyFragmentList() );
00421
00422 for( FF::SimpleFragmentList::ConstIterator pFragment = oAvailable.begin();
00423 pFragment != oAvailable.end(); ++pFragment )
00424 {
00425 if ( strRanges.IsEmpty() )
00426 {
00427 strRanges = _T("bytes ");
00428 }
00429 else
00430 {
00431 strRanges += ',';
00432 }
00433
00434 strRange.Format( _T("%I64i-%I64i"), pFragment->begin(), pFragment->end() - 1 );
00435 strRanges += strRange;
00436 }
00437
00438 return strRanges;
00439 }
00440
00442
00443
00444 BOOL CDownloadWithFile::ClipUploadRange(QWORD nOffset, QWORD& nLength) const
00445 {
00446 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00447 if ( nOffset >= m_nSize ) return FALSE;
00448
00449 if ( m_pFile->IsPositionRemaining( nOffset ) ) return FALSE;
00450
00451 if ( nOffset + nLength > m_nSize ) nLength = m_nSize - nOffset;
00452
00453 FF::SimpleFragmentList::ConstIteratorPair match
00454 = m_pFile->GetEmptyFragmentList().overlappingRange(
00455 FF::SimpleFragment( nOffset, nOffset + nLength ) );
00456
00457 if ( match.first != match.second )
00458 {
00459 if ( match.first->begin() <= nOffset ) return ( nLength = 0 ) > 0;
00460 nLength = match.first->end() - nOffset;
00461 return TRUE;
00462 }
00463
00464 return nLength > 0;
00465 }
00466
00468
00469
00470 BOOL CDownloadWithFile::GetRandomRange(QWORD& nOffset, QWORD& nLength) const
00471 {
00472 if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00473
00474 if ( m_pFile->GetEmptyFragmentList().missing() == 0 ) return FALSE;
00475
00476 FF::SimpleFragmentList oFilled = inverse( m_pFile->GetEmptyFragmentList() );
00477 FF::SimpleFragmentList::ConstIterator pRandom = randomFragment( oFilled );
00478
00479 nOffset = pRandom->begin();
00480 nLength = pRandom->length();
00481
00482 return TRUE;
00483 }
00484
00486
00487
00488 BOOL CDownloadWithFile::SubmitData(QWORD nOffset, LPBYTE pData, QWORD nLength)
00489 {
00490 SetModified();
00491 m_tReceived = GetTickCount();
00492
00493 if ( m_bBTH )
00494 {
00495 for ( CDownloadTransfer* pTransfer = GetFirstTransfer() ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00496 {
00497 if ( pTransfer->m_nProtocol == PROTOCOL_BT ) pTransfer->UnrequestRange( nOffset, nLength );
00498 }
00499 }
00500
00501 return m_pFile != NULL && m_pFile->WriteRange( nOffset, pData, nLength );
00502 }
00503
00505
00506
00507 QWORD CDownloadWithFile::EraseRange(QWORD nOffset, QWORD nLength)
00508 {
00509 if ( m_pFile == NULL ) return 0;
00510 QWORD nCount = m_pFile->InvalidateRange( nOffset, nLength );
00511 if ( nCount > 0 ) SetModified();
00512 return nCount;
00513 }
00514
00516
00517
00518 BOOL CDownloadWithFile::MakeComplete()
00519 {
00520 if ( m_sLocalName.IsEmpty() ) return FALSE;
00521 if ( ! PrepareFile() ) return FALSE;
00522 return m_pFile->MakeComplete();
00523 }
00524
00526
00527
00528 BOOL CDownloadWithFile::RunFile(DWORD tNow)
00529 {
00530 if ( m_pFile->IsOpen() )
00531 {
00532 if ( m_pFile->GetRemaining() == 0 ) return TRUE;
00533 }
00534
00535 return FALSE;
00536 }
00537
00539
00540
00541 BOOL CDownloadWithFile::WriteMetadata(LPCTSTR pszPath)
00542 {
00543 ASSERT( m_pXML != NULL );
00544
00545 CString strXML = m_pXML->ToString( TRUE, TRUE );
00546 delete m_pXML;
00547 m_pXML = NULL;
00548
00549 CString strMetadata;
00550
00551 strMetadata.Format( _T("%s\\Metadata"), pszPath );
00552 CreateDirectory( strMetadata, NULL );
00553 SetFileAttributes( strMetadata, FILE_ATTRIBUTE_HIDDEN );
00554
00555 strMetadata += m_sLocalName.Mid( m_sLocalName.ReverseFind( '\\' ) );
00556 strMetadata += _T(".xml");
00557
00558 HANDLE hFile = CreateFile( strMetadata, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
00559 FILE_ATTRIBUTE_NORMAL, NULL );
00560
00561 if ( hFile == INVALID_HANDLE_VALUE ) return FALSE;
00562
00563 DWORD nWritten;
00564
00565 int nASCII = WideCharToMultiByte( CP_UTF8, 0, strXML, strXML.GetLength(), NULL, 0, NULL, NULL );
00566 LPSTR pszASCII = new CHAR[ nASCII ];
00567 WideCharToMultiByte( CP_UTF8, 0, strXML, strXML.GetLength(), pszASCII, nASCII, NULL, NULL );
00568 WriteFile( hFile, pszASCII, nASCII, &nWritten, NULL );
00569 delete [] pszASCII;
00570
00571 CloseHandle( hFile );
00572
00573 return TRUE;
00574 }
00575
00577
00578
00579 BOOL CDownloadWithFile::AppendMetadata()
00580 {
00581 if ( ! Settings.Library.VirtualFiles ) return FALSE;
00582
00583 if ( m_pXML == NULL ) return FALSE;
00584 CXMLElement* pXML = m_pXML->GetFirstElement();
00585 if ( pXML == NULL ) return FALSE;
00586
00587 HANDLE hFile = CreateFile( m_sLocalName, GENERIC_READ|GENERIC_WRITE,
00588 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
00589 if ( hFile == INVALID_HANDLE_VALUE ) return FALSE;
00590
00591 CString strURI = m_pXML->GetAttributeValue( CXMLAttribute::schemaName );
00592 BOOL bSuccess = FALSE;
00593
00594 if ( strURI == CSchema::uriAudio )
00595 {
00596 if ( _tcsistr( m_sLocalName, _T(".mp3") ) != NULL )
00597 {
00598 bSuccess |= AppendMetadataID3v1( hFile, pXML );
00599 }
00600 }
00601
00602 CloseHandle( hFile );
00603
00604 return bSuccess;
00605 }
00606
00607 BOOL CDownloadWithFile::AppendMetadataID3v1(HANDLE hFile, CXMLElement* pXML)
00608 {
00609 USES_CONVERSION;
00610 DWORD nBytes;
00611 CString str;
00612 ID3V1 pID3;
00613
00614 ZeroMemory( &pID3, sizeof(pID3) );
00615 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00616 ReadFile( hFile, &pID3, 3, &nBytes, NULL );
00617 if ( memcmp( pID3.szTag, ID3V2_TAG, 3 ) == 0 ) return FALSE;
00618
00619 ZeroMemory( &pID3, sizeof(pID3) );
00620 SetFilePointer( hFile, -(int)sizeof(pID3), NULL, FILE_END );
00621 ReadFile( hFile, &pID3, sizeof(pID3), &nBytes, NULL );
00622 if ( memcmp( pID3.szTag, ID3V1_TAG, 3 ) == 0 ) return FALSE;
00623
00624 ZeroMemory( &pID3, sizeof(pID3) );
00625 memcpy( pID3.szTag, ID3V1_TAG, 3 );
00626
00627 str = pXML->GetAttributeValue( _T("title") );
00628 if ( str.GetLength() > 0 ) strncpy( pID3.szSongname, T2CA( (LPCTSTR)str ), 30 );
00629 str = pXML->GetAttributeValue( _T("artist") );
00630 if ( str.GetLength() > 0 ) strncpy( pID3.szArtist, T2CA( (LPCTSTR)str ), 30 );
00631 str = pXML->GetAttributeValue( _T("album") );
00632 if ( str.GetLength() > 0 ) strncpy( pID3.szAlbum, T2CA( (LPCTSTR)str ), 30 );
00633 str = pXML->GetAttributeValue( _T("year") );
00634 if ( str.GetLength() > 0 ) strncpy( pID3.szYear, T2CA( (LPCTSTR)str ), 4 );
00635
00636 str = pXML->GetAttributeValue( _T("genre") );
00637
00638 for ( int nGenre = 0 ; nGenre < ID3_GENRES ; nGenre ++ )
00639 {
00640 if ( str.CompareNoCase( CLibraryBuilderInternals::pszID3Genre[ nGenre ] ) == 0 )
00641 {
00642 pID3.nGenre = nGenre;
00643 break;
00644 }
00645 }
00646
00647 SetFilePointer( hFile, 0, NULL, FILE_END );
00648 WriteFile( hFile, &pID3, sizeof(pID3), &nBytes, NULL );
00649
00650 return TRUE;
00651 }
00652
00654
00655
00656 void CDownloadWithFile::Serialize(CArchive& ar, int nVersion)
00657 {
00658 CDownloadWithTransfers::Serialize( ar, nVersion );
00659
00660 if ( ar.IsStoring() )
00661 {
00662 ar.WriteCount( m_pFile != NULL );
00663 if ( m_pFile != NULL ) m_pFile->Serialize( ar, nVersion );
00664 }
00665 else
00666 {
00667 if ( nVersion < 28 )
00668 {
00669 CString strLocalName;
00670 ar >> strLocalName;
00671
00672 if ( strLocalName.GetLength() )
00673 {
00674 if ( m_sLocalName.GetLength() )
00675 MoveFile( m_sLocalName + _T(".sd"), strLocalName + _T(".sd") );
00676 m_sLocalName = strLocalName;
00677 }
00678 else
00679 {
00680 GenerateLocalName();
00681 }
00682 }
00683
00684 if ( nVersion < 25 || ar.ReadCount() )
00685 {
00686 m_pFile->Serialize( ar, nVersion );
00687 }
00688 else
00689 {
00690 delete m_pFile;
00691 m_pFile = NULL;
00692 }
00693 }
00694 }