⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 librarybuilderinternals.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// LibraryBuilderInternals.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "LibraryFolders.h"
#include "LibraryBuilder.h"
#include "LibraryBuilderInternals.h"

#define _ID3_DEFINE_GENRES
#include "Buffer.h"
#include "Schema.h"
#include "XML.h"
#include "ID3.h"
#include "Packet.h"
#include "CollectionFile.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals construction

CLibraryBuilderInternals::CLibraryBuilderInternals(CLibraryBuilder* pBuilder)
{
	m_pBuilder = pBuilder;
}

CLibraryBuilderInternals::~CLibraryBuilderInternals()
{
}

//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals load settings

void CLibraryBuilderInternals::LoadSettings()
{
	m_bEnableMP3	= theApp.GetProfileInt( _T("Library"), _T("ScanMP3"), TRUE );
	m_bEnableEXE	= theApp.GetProfileInt( _T("Library"), _T("ScanEXE"), TRUE );
	m_bEnableImage	= theApp.GetProfileInt( _T("Library"), _T("ScanImage"), TRUE );
	m_bEnableASF	= theApp.GetProfileInt( _T("Library"), _T("ScanASF"), TRUE );
	m_bEnableOGG	= theApp.GetProfileInt( _T("Library"), _T("ScanOGG"), TRUE );
	m_bEnableAPE	= theApp.GetProfileInt( _T("Library"), _T("ScanAPE"), TRUE );
	m_bEnableAVI	= theApp.GetProfileInt( _T("Library"), _T("ScanAVI"), TRUE );
	m_bEnablePDF	= theApp.GetProfileInt( _T("Library"), _T("ScanPDF"), TRUE );
}

//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals extract metadata (threaded)

BOOL CLibraryBuilderInternals::ExtractMetadata( CString& strPath, HANDLE hFile, SHA1* pSHA1)
{
	CString strType;
	
	int nExtPos = strPath.ReverseFind( '.' );
	if ( nExtPos > 0 ) strType = strPath.Mid( nExtPos );
	
	strType.MakeLower();
	
	if ( strType == _T(".mp3") )
	{
		if ( ! m_bEnableMP3 ) return FALSE;
		if ( ReadID3v2( hFile ) ) return TRUE;
		if ( ReadID3v1( hFile ) ) return TRUE;
		if ( ReadMP3Frames( hFile ) ) return TRUE;
		return SubmitCorrupted();
	}
	else if ( strType == _T(".exe") || strType == _T(".dll") )
	{
		if ( ! m_bEnableEXE ) return FALSE;
		return ReadVersion( strPath );
	}
	else if ( strType == _T(".asf") || strType == _T(".wma") || strType == _T(".wmv") )
	{
		if ( ! m_bEnableASF ) return FALSE;
		return ReadASF( hFile );
	}
	else if ( strType == _T(".avi") )
	{
		if ( ! m_bEnableAVI ) return FALSE;
		return ReadAVI( hFile );
	}
	else if ( strType == _T(".mpg") || strType == _T(".mpeg") )
	{
		if ( ! m_bEnableASF ) return FALSE;
		return ReadMPEG( hFile );
	}
	else if ( strType == _T(".ogg") )
	{
		if ( ! m_bEnableOGG ) return FALSE;
        return ReadOGG( hFile );
	}
	else if ( strType == _T(".ape") || strType == _T(".mac") || strType == _T(".apl") )
	{
		if ( ! m_bEnableAPE ) return FALSE;
		return ReadAPE( hFile );
	}
	else if ( strType == _T(".jpg") || strType == _T(".jpeg") )
	{
		if ( ! m_bEnableImage ) return FALSE;
		return ReadJPEG( hFile );
	}
	else if ( strType == _T(".gif") )
	{
		if ( ! m_bEnableImage ) return FALSE;
		return ReadGIF( hFile );
	}
	else if ( strType == _T(".png") )
	{
		if ( ! m_bEnableImage ) return FALSE;
		return ReadPNG( hFile );
	}
	else if ( strType == _T(".bmp") )
	{
		if ( ! m_bEnableImage ) return FALSE;
		return ReadBMP( hFile );
	}
	else if ( strType == _T(".pdf") )
	{
		if ( ! m_bEnablePDF ) return FALSE;
		return ReadPDF( hFile, strPath );
	}
	else if ( strType == _T(".co") || strType == _T(".collection") )
	{
		return ReadCollection( hFile, pSHA1 );
	}
	
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals submit metadata (threaded)

BOOL CLibraryBuilderInternals::SubmitMetadata( LPCTSTR pszSchemaURI, CXMLElement* pXML)
{
	// Ignoring return value from submission
	m_pBuilder->SubmitMetadata( pszSchemaURI, pXML );
	return TRUE;
}

BOOL CLibraryBuilderInternals::SubmitCorrupted()
{
	return m_pBuilder->SubmitCorrupted();
}

//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals ID3v1 (threaded)

BOOL CLibraryBuilderInternals::ReadID3v1( HANDLE hFile, CXMLElement* pXML)
{
	if ( GetFileSize( hFile, NULL ) < 128 ) return FALSE;
	
	ID3V1 pInfo;
	DWORD nRead;

	SetFilePointer( hFile, -128, NULL, FILE_END );
	ReadFile( hFile, &pInfo, sizeof(pInfo), &nRead, NULL );
	
	if ( nRead != sizeof(pInfo) ) return FALSE;
	if ( strncmp( pInfo.szTag, ID3V1_TAG, 3 ) ) return FALSE;
	
	BOOL bIsMP3 = ( pXML == NULL );
	if ( bIsMP3 ) pXML = new CXMLElement( NULL, _T("audio") );
	
	CopyID3v1Field( pXML, _T("title"), pInfo.szSongname, 30 );
	CopyID3v1Field( pXML, _T("artist"), pInfo.szArtist, 30 );
	CopyID3v1Field( pXML, _T("album"), pInfo.szAlbum, 30 );
	CopyID3v1Field( pXML, _T("year"), pInfo.szYear, 4 );
	
	if ( pInfo.nGenre < ID3_GENRES )
	{
		pXML->AddAttribute( _T("genre"), pszID3Genre[ pInfo.nGenre ] );
	}
	
	if ( pInfo.szComment[28] == 0 && pInfo.szComment[29] > 0 )
	{
		CString strTrack;
		strTrack.Format( _T("%i"), (int)pInfo.szComment[29] );
		pXML->AddAttribute( _T("track"), strTrack );
		CopyID3v1Field( pXML, _T("description"), pInfo.szComment, 28 );
	}
	else
	{
		CopyID3v1Field( pXML, _T("description"), pInfo.szComment, 30 );
	}
	
	SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
	
	if ( bIsMP3 )
	{
		ScanMP3Frame( pXML, hFile, sizeof(pInfo) );
		return SubmitMetadata( CSchema::uriAudio, pXML );
	}
	
	return TRUE;
}

BOOL CLibraryBuilderInternals::CopyID3v1Field(CXMLElement* pXML, LPCTSTR pszAttribute, LPCSTR pszValue, int nLength)
{
	CString strValue;
	LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );
	
	for ( int nChar = 0 ; nChar < nLength ; nChar++ ) *pszOutput++ = (TCHAR)*pszValue++;
	*pszOutput++ = 0;
	strValue.ReleaseBuffer();
	
	strValue.TrimLeft();
	strValue.TrimRight();
	if ( strValue.IsEmpty() ) return FALSE;
	
	pXML->AddAttribute( pszAttribute, strValue );
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals ID3v2 (threaded)

BOOL CLibraryBuilderInternals::ReadID3v2( HANDLE hFile)
{
	ID3V2_HEADER pHeader;
	DWORD nRead;
	
	SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
	ReadFile( hFile, &pHeader, sizeof(pHeader), &nRead, NULL );
	if ( nRead != sizeof(pHeader) ) return FALSE;
	
	if ( strncmp( pHeader.szTag, ID3V2_TAG, 3 ) ) return FALSE;
	if ( pHeader.nMajorVersion < 2 || pHeader.nMajorVersion > 4 ) return FALSE;
	if ( pHeader.nFlags & ~ID3V2_KNOWNMASK ) return FALSE;
	if ( pHeader.nFlags & ID3V2_UNSYNCHRONISED ) return FALSE;
	
	DWORD nBuffer = SWAP_LONG( pHeader.nSize );
	ID3_DESYNC_SIZE( nBuffer );
	
	if ( nBuffer > 1024 * 1024 * 2 ) return FALSE;
	
	BYTE* pBuffer	= new BYTE[ nBuffer ];
	BYTE* pRelease	= pBuffer;
	
	ReadFile( hFile, pBuffer, nBuffer, &nRead, NULL );
	if ( nRead != nBuffer )
	{
		delete [] pRelease;
		return FALSE;
	}
	
	if ( ( pHeader.nFlags & ID3V2_EXTENDEDHEADER ) && pHeader.nMajorVersion == 3 )
	{
		if ( nBuffer < sizeof(ID3V2_EXTENDED_HEADER_1) )
		{
			delete [] pRelease;
			return FALSE;
		}
		
		ID3V2_EXTENDED_HEADER_1* pExtended = (ID3V2_EXTENDED_HEADER_1*)pBuffer;
		pBuffer += sizeof(ID3V2_EXTENDED_HEADER_1);
		nBuffer -= sizeof(ID3V2_EXTENDED_HEADER_1);
		
		pExtended->nSize = SWAP_LONG( pExtended->nSize );
		
		if ( nBuffer < pExtended->nSize )
		{
			delete [] pRelease;
			return FALSE;
		}
		
		pBuffer += pExtended->nSize;
		nBuffer -= pExtended->nSize;
	}
	else if ( ( pHeader.nFlags & ID3V2_EXTENDEDHEADER ) && pHeader.nMajorVersion == 4 )
	{
		if ( nBuffer < sizeof(ID3V2_EXTENDED_HEADER_2) )
		{
			delete [] pRelease;
			return FALSE;
		}
		
		ID3V2_EXTENDED_HEADER_2* pExtended = (ID3V2_EXTENDED_HEADER_2*)pBuffer;
		pBuffer += sizeof(ID3V2_EXTENDED_HEADER_2);
		nBuffer -= sizeof(ID3V2_EXTENDED_HEADER_2);
		
		pExtended->nSize = SWAP_LONG( pExtended->nSize );
		ID3_DESYNC_SIZE( pExtended->nSize );
		pExtended->nSize -= 6;
		
		if ( nBuffer < pExtended->nSize )
		{
			delete [] pRelease;
			return FALSE;
		}
		
		pBuffer += pExtended->nSize;
		nBuffer -= pExtended->nSize;
	}
	
	CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
	
	while ( TRUE )
	{
		DWORD nFrameSize = 0;
		CHAR szFrameTag[5];
		
		if ( pHeader.nMajorVersion > 2 )
		{
			ID3V2_FRAME* pFrame = (ID3V2_FRAME*)pBuffer;
			
			if ( nBuffer < sizeof(*pFrame) ) break;
			pBuffer += sizeof(*pFrame);
			nBuffer -= sizeof(*pFrame);
			
			szFrameTag[0] = pFrame->szID[0];
			szFrameTag[1] = pFrame->szID[1];
			szFrameTag[2] = pFrame->szID[2];
			szFrameTag[3] = pFrame->szID[3];
			szFrameTag[4] = 0;
			
			nFrameSize = SWAP_LONG( pFrame->nSize );
			if ( pHeader.nMajorVersion >= 4 ) ID3_DESYNC_SIZE( nFrameSize );
			if ( pFrame->nFlags2 & ~ID3V2_KNOWNFRAME ) szFrameTag[0] = 0;
		}
		else
		{
			ID3V2_FRAME_2* pFrame = (ID3V2_FRAME_2*)pBuffer;
			
			if ( nBuffer < sizeof(*pFrame) ) break;
			pBuffer += sizeof(*pFrame);
			nBuffer -= sizeof(*pFrame);
			
			szFrameTag[0] = pFrame->szID[0];
			szFrameTag[1] = pFrame->szID[1];
			szFrameTag[2] = pFrame->szID[2];
			szFrameTag[3] = szFrameTag[4] = 0;
			nFrameSize = ( pFrame->nSize[0] << 16 ) | ( pFrame->nSize[1] << 8 ) | pFrame->nSize[2];
		}
		
		if ( nBuffer < nFrameSize || ! nFrameSize || ! szFrameTag[0] ) break;
		
		if ( strcmp( szFrameTag, "TIT2" ) == 0 || strcmp( szFrameTag, "TT2" ) == 0)
		{
			CopyID3v2Field( pXML, _T("title"), pBuffer, nFrameSize );
		}
		else if ( strcmp( szFrameTag, "TOPE" ) == 0 || strcmp( szFrameTag, "TOA" ) == 0 || strcmp( szFrameTag, "TPE1" ) == 0 || strcmp( szFrameTag, "TPE2" ) == 0 )
		{
			CopyID3v2Field( pXML, _T("artist"), pBuffer, nFrameSize );
		}
		else if ( strcmp( szFrameTag, "TALB" ) == 0 || strcmp( szFrameTag, "TOT" ) == 0 )
		{
			CopyID3v2Field( pXML, _T("album"), pBuffer, nFrameSize );
		}
		else if ( strcmp( szFrameTag, "TRCK" ) == 0 || strcmp( szFrameTag, "TRK" ) == 0 )
		{
			CopyID3v2Field( pXML, _T("track"), pBuffer, nFrameSize );
		}
		else if ( strcmp( szFrameTag, "TYER" ) == 0 || strcmp( szFrameTag, "TYE" ) == 0 )
		{
			CopyID3v2Field( pXML, _T("year"), pBuffer, nFrameSize );
		}
		else if ( strcmp( szFrameTag, "COMM" ) == 0 || strcmp( szFrameTag, "COM" ) == 0 )
		{
			CopyID3v2Field( pXML, _T("description"), pBuffer, nFrameSize, TRUE );
		}
		else if ( strcmp( szFrameTag, "TLEN" ) == 0 || strcmp( szFrameTag, "TLE" ) == 0 )
		{
			if ( CopyID3v2Field( pXML, _T("seconds"), pBuffer, nFrameSize ) )
			{
				CString strMS = pXML->GetAttributeValue( _T("seconds"), _T("0") );
				int nMS;
				_stscanf( strMS, _T("%lu"), &nMS );
				strMS.Format( _T("%lu"), nMS / 1000 );
				pXML->AddAttribute( _T("seconds"), strMS );
			}
		}
		else if ( strcmp( szFrameTag, "TCON" ) == 0 || strcmp( szFrameTag, "TCO" ) == 0 )
		{
			if ( CopyID3v2Field( pXML, _T("genre"), pBuffer, nFrameSize ) )
			{
				CString strGenre = pXML->GetAttributeValue( _T("genre"), _T("") );
				
				while ( TRUE )
				{
					int nPos1 = strGenre.Find( '(' );
					if ( nPos1 < 0 ) break;
					int nPos2 = strGenre.Find( ')' );
					if ( nPos2 <= nPos1 ) break;
					
					CString strValue = strGenre.Mid( nPos1 + 1, nPos2 - nPos1 - 1 );
					int nGenre = 0;
					
					if ( strValue.CompareNoCase( _T("RX") ) == 0 )
					{
						strValue = _T("Remix");
					}
					else if ( strValue.CompareNoCase( _T("CR") ) == 0 )
					{
						strValue = _T("Cover");
					}
					else if ( _stscanf( strValue, _T("%i"), &nGenre ) == 1 && nGenre < ID3_GENRES )
					{
						if ( _tcsistr( strGenre, pszID3Genre[ nGenre ] ) == NULL )
						{
							strValue = pszID3Genre[ nGenre ];
						}
						else
						{
							strValue.Empty();
						}
					}
					else
					{
						strValue = _T("[") + strValue + _T("]");
					}
					
					strGenre = strGenre.Left( nPos1 ) + strValue + strGenre.Mid( nPos2 + 1 );
				}
				
				Replace( strGenre, _T("["), _T("(") );
				Replace( strGenre, _T("]"), _T(")") );
				
				pXML->AddAttribute( _T("genre"), strGenre );
			}
		}
		
		pBuffer += nFrameSize;
		nBuffer -= nFrameSize;
	}
	
	delete [] pRelease;
	
	ScanMP3Frame( pXML, hFile, 0 );
	
	return SubmitMetadata( CSchema::uriAudio, pXML );
}

BOOL CLibraryBuilderInternals::CopyID3v2Field(CXMLElement* pXML, LPCTSTR pszAttribute, BYTE* pBuffer, DWORD nLength, BOOL bSkipLanguage)
{
	CString strValue;
	
	BYTE nEncoding = *pBuffer++;
	nLength--;
	
	if ( bSkipLanguage )
	{
		if ( nLength < 3 ) return FALSE;
		pBuffer += 3;
		nLength -= 3;
	}
	
	if ( nEncoding == 0 )
	{
		LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );
		
		for ( DWORD nChar = 0, nOut = 0 ; nChar < nLength ; nChar++, nOut++ )
		{
			pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar ];
			if ( pszOutput[ nOut ] == 0 ) break;
		}
		
		strValue.ReleaseBuffer( nOut );
	}
	else if ( nEncoding == 1 )
	{
		if ( nLength < 4 || nLength & 1 ) return FALSE;
		
		nLength = ( nLength - 2 ) / 2;
		LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );

		if ( pBuffer[0] == 0xFF && pBuffer[1] == 0xFE )
		{
			pBuffer += 2;
			for ( DWORD nChar = 0, nOut = 0 ; nChar < nLength ; nChar++, nOut++ )
			{
				pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar*2+0 ] | ( (TCHAR)pBuffer[ nChar*2+1 ] << 8 );
				if ( pszOutput[ nOut ] == 0 ) break;
			}
			strValue.ReleaseBuffer( nOut );
		}
		else if ( pBuffer[0] == 0xFE && pBuffer[1] == 0xFF )
		{
			pBuffer += 2;
			for ( DWORD nChar = 0, nOut = 0 ; nChar < nLength ; nChar++, nOut++ )
			{
				pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar*2+1 ] | ( (TCHAR)pBuffer[ nChar*2+0 ] << 8 );
				if ( pszOutput[ nOut ] == 0 ) break;
			}
			strValue.ReleaseBuffer( nOut );
		}
		else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -