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

DownloadWithFile.cpp

Go to the documentation of this file.
00001 //
00002 // DownloadWithFile.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 "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 // CDownloadWithFile construction
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 // CDownloadWithFile open the file
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 // CDownloadWithFile close the file
00121 
00122 void CDownloadWithFile::CloseFile()
00123 {
00124         if ( m_pFile != NULL ) m_pFile->Close();
00125 }
00126 
00128 // CDownloadWithFile prepare file
00129 
00130 BOOL CDownloadWithFile::PrepareFile()
00131 {
00132         return OpenFile() && m_pFile->GetRemaining() > 0;
00133 }
00134 
00136 // CDownloadWithFile delete the file
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 // CDownloadWithFile statistics
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 // CDownloadWithFile get the first empty fragment
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 // CDownloadWithFile get a list of possible download fragments
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         // ToDo: add a function to FF::detail::List<...> to do that more efficiently
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 // CDownloadWithFile select a fragment for a transfer
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 // CDownloadWithFile check if a byte position is empty
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 // CDownloadWithFile check if a range would "help"
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 // like IsRangeUseful( ) but take the amount of useful ranges relative to the amount of garbage
00395 // and source speed into account
00396 BOOL CDownloadWithFile::IsRangeUsefulEnough(CDownloadTransfer* pTransfer, QWORD nOffset, QWORD nLength)
00397 {
00398         if ( m_pFile == NULL || ! m_pFile->IsValid() ) return FALSE;
00399         // range is useful if at least byte within the next amount of data transferable within the next 5 seconds
00400         // is useful
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 // CDownloadWithFile get a string of available ranges
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 // CDownloadWithFile clip a range to valid portions
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 // CDownloadWithFile select a random range of available data
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 // CDownloadWithFile submit data
00487 
00488 BOOL CDownloadWithFile::SubmitData(QWORD nOffset, LPBYTE pData, QWORD nLength)
00489 {
00490         SetModified();
00491         m_tReceived = GetTickCount();
00492         
00493         if ( m_bBTH )   // Hack: Only do this for BitTorrent
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 // CDownloadWithFile erase a range
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 // CDownloadWithFile make the file appear complete
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 // CDownloadWithFile run the file
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 // CDownloadWithFile write the metadata
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 // CDownloadWithFile append intrinsic metadata
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 // CDownloadWithFile serialize
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 }

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