📄 librarybuilderinternals.cpp
字号:
//
// 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 + -