📄 librarybuilderinternals.cpp
字号:
{
if ( nBuffer < nMinSize ) return NULL;
BYTE* pBuffer = new BYTE[ nBuffer ];
ReadFile( hFile, pBuffer, nBuffer, &nRead, NULL );
if ( nRead == nBuffer ) return pBuffer;
delete [] pBuffer;
}
else
{
SetFilePointer( hFile, nBuffer, NULL, FILE_CURRENT );
nBuffer = nSample;
return (BYTE*)TRUE;
}
return NULL;
}
BOOL CLibraryBuilderInternals::ReadOGGString(BYTE*& pOGG, DWORD& nOGG, CString& str)
{
if ( nOGG < 4 ) return FALSE;
DWORD nLen = *(DWORD*)pOGG;
pOGG += 4; nOGG -= 4;
if ( nOGG < nLen ) return FALSE;
LPTSTR pszOut = str.GetBuffer( nLen + 1 );
for ( ; nLen ; nLen--, nOGG-- ) *pszOut++ = (TCHAR)*pOGG++;
*pszOut++ = 0;
str.ReleaseBuffer();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals APE Monkey's Audio (threaded)
BOOL CLibraryBuilderInternals::ReadAPE( HANDLE hFile)
{
if ( GetFileSize( hFile, NULL ) < sizeof(APE_HEADER) ) return SubmitCorrupted();
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
APE_HEADER pAPE;
DWORD nRead;
ReadFile( hFile, &pAPE, sizeof(pAPE), &nRead, NULL );
if ( nRead != sizeof(pAPE) ) return SubmitCorrupted();
if ( pAPE.cID[0] != 'M' || pAPE.cID[1] != 'A' || pAPE.cID[2] != 'C' ) return SubmitCorrupted();
if ( pAPE.nSampleRate == 0 ) return SubmitCorrupted();
DWORD nBlocksPerFrame = ( pAPE.nVersion >= 3900 || ( pAPE.nVersion >= 3800 &&
pAPE.nCompressionLevel == 4000 ) ) ? 73728 : 9216;
DWORD nBlocks = ( pAPE.nTotalFrames - 1 ) * nBlocksPerFrame + pAPE.nFinalFrameBlocks;
DWORD nSamples = nBlocks * pAPE.nChannels;
if ( pAPE.nFormatFlags & 8 )
nSamples *= 3;
else if ( ( pAPE.nFormatFlags & 1 ) == 0 )
nSamples *= 2;
DWORD nDuration = nSamples / pAPE.nSampleRate;
CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
CString strItem;
strItem.Format( _T("%lu"), nDuration );
pXML->AddAttribute( _T("seconds"), strItem );
strItem.Format( _T("%lu"), pAPE.nSampleRate );
pXML->AddAttribute( _T("sampleRate"), strItem );
if ( ReadID3v1( hFile, pXML ) )
{
return SubmitMetadata( CSchema::uriAudio, pXML );
}
if ( GetFileSize( hFile, NULL ) < sizeof(APE_HEADER) + sizeof(APE_TAG_FOOTER) )
{
return SubmitMetadata( CSchema::uriAudio, pXML );
}
APE_TAG_FOOTER pFooter;
SetFilePointer( hFile, -(LONG)sizeof(pFooter), NULL, FILE_END );
ReadFile( hFile, &pFooter, sizeof(pFooter), &nRead, NULL );
if ( nRead != sizeof(pFooter) || strncmp( pFooter.cID, "APETAGEX", 8 ) ||
(DWORD)pFooter.nFields > 16 ||
( pFooter.nVersion != 1000 && pFooter.nVersion != 2000 ) )
{
return SubmitMetadata( CSchema::uriAudio, pXML );
}
SetFilePointer( hFile, -(LONG)pFooter.nSize, NULL, FILE_END );
for ( int nTag = 0 ; nTag < pFooter.nFields ; nTag++ )
{
DWORD nLength, nFlags;
ReadFile( hFile, &nLength, 4, &nRead, NULL );
if ( nRead != 4 || nLength > 1024 ) break;
ReadFile( hFile, &nFlags, 4, &nRead, NULL );
if ( nRead != 4 ) break;
CString strKey, strValue;
while ( strKey.GetLength() < 64 )
{
BYTE nChar;
ReadFile( hFile, &nChar, 1, &nRead, NULL );
if ( nRead != 1 || nChar == 0 ) break;
strKey += (TCHAR)nChar;
}
if ( nRead != 1 || strKey.GetLength() >= 64 ) break;
LPSTR pszInput = new CHAR[ nLength ];
ReadFile( hFile, pszInput, nLength, &nRead, NULL );
if ( nLength != nRead ) break;
int nWide = MultiByteToWideChar( CP_UTF8, 0, pszInput, nLength, NULL, 0 );
LPWSTR pszWide = new WCHAR[ nWide + 1 ];
MultiByteToWideChar( CP_UTF8, 0, pszInput, nLength, pszWide, nWide );
pszWide[ nWide ] = 0;
strValue = pszWide;
delete [] pszWide;
delete [] pszInput;
strKey.TrimLeft(); strKey.TrimRight();
strValue.TrimLeft(); strValue.TrimRight();
if ( strKey.GetLength() && strValue.GetLength() )
{
strKey.MakeLower();
if ( strKey == _T("title") )
{
pXML->AddAttribute( _T("title"), strValue );
}
else if ( strKey == _T("artist") )
{
pXML->AddAttribute( _T("artist"), strValue );
}
else if ( strKey == _T("album") )
{
pXML->AddAttribute( _T("album"), strValue );
}
else if ( strKey == _T("comment") )
{
pXML->AddAttribute( _T("description"), strValue );
}
else if ( strKey == _T("year") )
{
pXML->AddAttribute( _T("year"), strValue );
}
else if ( strKey == _T("track") )
{
pXML->AddAttribute( _T("track"), strValue );
}
else if ( strKey == _T("genre") )
{
pXML->AddAttribute( _T("genre"), strValue );
}
else if ( strKey.Find( _T(" url") ) > 0 )
{
pXML->AddAttribute( _T("link"), strValue );
}
}
}
return SubmitMetadata( CSchema::uriAudio, pXML );
}
//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals AVI (threaded)
BOOL CLibraryBuilderInternals::ReadAVI( HANDLE hFile)
{
if ( GetFileSize( hFile, NULL ) < sizeof(AVI_HEADER) + 16 ) return SubmitCorrupted();
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
CHAR szID[5] = { 0, 0, 0, 0, 0 };
DWORD nRead;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "RIFF", 4 ) ) return SubmitCorrupted();
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "AVI ", 4 ) ) return SubmitCorrupted();
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "LIST", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "hdrl", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "avih", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
AVI_HEADER pHeader;
ReadFile( hFile, &pHeader, sizeof(pHeader), &nRead, NULL );
if ( nRead != sizeof(pHeader) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "LIST", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "strl", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "strh", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 || strncmp( szID, "vids", 4 ) ) return FALSE;
ReadFile( hFile, szID, 4, &nRead, NULL );
if ( nRead != 4 ) return FALSE;
CXMLElement* pXML = new CXMLElement( NULL, _T("video") );
CString strItem;
double nTime = (double)pHeader.dwMicroSecPerFrame / 1000000.0f;
nTime *= (double)pHeader.dwTotalFrames;
nTime /= 60.0f;
double nRate = 1000000.0f / (double)pHeader.dwMicroSecPerFrame;
strItem.Format( _T("%lu"), pHeader.dwWidth );
pXML->AddAttribute( _T("width"), strItem );
strItem.Format( _T("%lu"), pHeader.dwHeight );
pXML->AddAttribute( _T("height"), strItem );
strItem.Format( _T("%.3f"), nTime );
pXML->AddAttribute( _T("minutes"), strItem );
strItem.Format( _T("%.2f"), nRate );
pXML->AddAttribute( _T("frameRate"), strItem );
pXML->AddAttribute( _T("codec"), CString( szID ) );
return SubmitMetadata( CSchema::uriVideo, pXML );
}
//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals PDF (threaded)
BOOL CLibraryBuilderInternals::ReadPDF( HANDLE hFile, LPCTSTR pszPath)
{
DWORD nOffset, nCount, nPages, nInfo;
CString strLine, strSeek;
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
if ( ReadLine( hFile ).Find( _T("%PDF") ) != 0 ) return FALSE;
SetFilePointer( hFile, -1, NULL, FILE_END );
strLine = ReadLineReverse( hFile );
if ( strLine.IsEmpty() ) strLine = ReadLineReverse( hFile );
if ( strLine != _T("%%EOF") ) return FALSE;
strLine = ReadLineReverse( hFile );
if ( ReadLineReverse( hFile ) != _T("startxref") ) return FALSE;
if ( _stscanf( strLine, _T("%lu"), &nOffset ) != 1 ) return FALSE;
if ( SetFilePointer( hFile, nOffset, NULL, FILE_BEGIN ) != nOffset ) return FALSE;
if ( ReadLine( hFile ) != _T("xref") ) return FALSE;
strLine = ReadLine( hFile );
if ( _stscanf( strLine, _T("%lu %lu"), &nOffset, &nCount ) != 2 ) return FALSE;
if ( nCount > 4096 ) return FALSE;
DWORD* pOffset = new DWORD[ nCount ];
ZeroMemory( pOffset, sizeof(DWORD) * nCount );
for ( nOffset = 0 ; nOffset < nCount ; nOffset++ )
{
strLine = ReadLine( hFile );
strLine.TrimLeft();
strLine.TrimRight();
if ( strLine.GetLength() != 18 || strLine.GetAt( 10 ) != ' ' )
{
delete [] pOffset;
return FALSE;
}
if ( strLine.GetAt( 17 ) == 'n' )
{
for ( LPCTSTR pszInt = strLine ; *pszInt == '0' ; pszInt++ );
if ( *pszInt != 0 )
{
_stscanf( pszInt, _T("%lu"), &pOffset[ nOffset ] );
}
}
}
if ( ReadLine( hFile ) != _T("trailer") ) return FALSE;
if ( ReadLine( hFile ) != _T("<<") ) return FALSE;
for ( nOffset = 0 ; ; )
{
strLine = ReadLine( hFile );
if ( strLine.IsEmpty() || strLine == _T(">>") ) break;
if ( _tcsnicmp( strLine, _T("/Info "), 6 ) == 0 )
{
_stscanf( strLine.Mid( 6 ), _T("%lu"), &nOffset );
break;
}
}
if ( nOffset == 0 )
{
delete [] pOffset;
return FALSE;
}
strSeek.Format( _T("%lu 0 obj"), nOffset );
nPages = nInfo = 0;
for ( nOffset = 0 ; nOffset < nCount ; nOffset++ )
{
if ( pOffset[ nOffset ] == 0 ) continue;
SetFilePointer( hFile, pOffset[ nOffset ], NULL, FILE_BEGIN );
strLine = ReadLine( hFile );
if ( strLine.Find( _T("obj") ) < 0 ) break;
if ( strLine == strSeek )
{
nInfo = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
}
else if ( ReadLine( hFile ) == _T("<<") )
{
if ( ReadLine( hFile ) == _T("/Type /Page") ) nPages++;
}
}
delete [] pOffset;
if ( nInfo == 0 ) return FALSE;
SetFilePointer( hFile, nInfo, NULL, FILE_BEGIN );
if ( ReadLine( hFile ) != _T("<<") ) return FALSE;
BOOL bBook = ( _tcsistr( pszPath, _T("book") ) != NULL );
if ( ! bBook ) return FALSE;
CXMLElement* pXML = new CXMLElement( NULL, bBook ? _T("book") : _T("document") );
if ( LPCTSTR pszName = _tcsrchr( pszPath, '\\' ) )
{
pszName++;
if ( _tcsnicmp( pszName, _T("ebook - "), 8 ) == 0 )
{
strLine = pszName + 8;
strLine = strLine.SpanExcluding( _T(".") );
strLine.TrimLeft();
strLine.TrimRight();
pXML->AddAttribute( _T("title"), strLine );
}
else if ( _tcsnicmp( pszName, _T("(ebook"), 6 ) == 0 )
{
if ( pszName = _tcschr( pszName, ')' ) )
{
if ( _tcsncmp( pszName, _T(") - "), 4 ) == 0 )
strLine = pszName + 4;
else
strLine = pszName + 1;
strLine = strLine.SpanExcluding( _T(".") );
strLine.TrimLeft();
strLine.TrimRight();
pXML->AddAttribute( _T("title"), strLine );
}
}
}
if ( nPages > 0 )
{
strLine.Format( _T("%lu"), nPages );
pXML->AddAttribute( _T("pages"), strLine );
}
while ( TRUE )
{
strLine = ReadLine( hFile );
if ( strLine.IsEmpty() || strLine.GetAt( 0 ) != '/' ) break;
CString strKey = strLine.SpanExcluding( _T(" \t") );
strLine = strLine.Mid( strKey.GetLength() );
strLine.TrimLeft();
strKey.MakeLower();
if ( strLine.GetLength() >= 2 &&
strLine.GetAt( 0 ) == '(' &&
strLine.GetAt( strLine.GetLength() - 1 ) == ')' )
{
strLine = strLine.Mid( 1, strLine.GetLength() - 2 );
}
if ( strLine.IsEmpty() ) continue;
if ( ( strLine.GetLength() & 1 ) == 0 && strLine.GetAt( 0 ) == '<' )
{
CString strTemp;
for ( int nHex = 0 ; nHex < strLine.GetLength() / 2 - 1 ; nHex++ )
{
int nChar;
if ( _stscanf( strLine.Mid( nHex + 1, 2 ), _T("%x"), &nChar ) == 1 )
{
strTemp += (TCHAR)nChar;
}
}
strLine = strTemp;
if ( strLine.IsEmpty() ) continue;
}
if ( strKey == _T("/title") )
{
pXML->AddAttribute( _T("title"), strLine );
}
else if ( strKey == _T("/author") )
{
pXML->AddAttribute( _T("author"), strLine );
}
else if ( strKey == _T("/subject") )
{
pXML->AddAttribute( _T("subject"), strLine );
}
else if ( strKey == _T("/keywords") )
{
pXML->AddAttribute( _T("keywords"), strLine );
}
}
if ( bBook )
{
pXML->AddAttribute( _T("format"), _T("PDF") );
pXML->AddAttribute( _T("back"), _T("Digital") );
}
// TODO: Check bBook, and do uriDocument
return SubmitMetadata( CSchema::uriBook, pXML );
}
CString CLibraryBuilderInternals::ReadLine(HANDLE hFile)
{
DWORD nRead, nLength;
TCHAR cChar;
CString str;
for ( nLength = 0 ; ReadFile( hFile, &cChar, 1, &nRead, NULL ) && nRead == 1 && nLength++ < 4096 ; )
{
if ( cChar == '\r' ) break;
if ( cChar != '\n' ) str += cChar;
}
str.TrimLeft();
str.TrimRight();
return str;
}
CString CLibraryBuilderInternals::ReadLineReverse(HANDLE hFile)
{
DWORD nRead, nLength;
TCHAR cChar;
CString str;
for ( nLength = 0 ; ReadFile( hFile, &cChar, 1, &nRead, NULL ) && nRead == 1 && nLength++ < 4096 ; )
{
if ( SetFilePointer( hFile, -2, NULL, FILE_CURRENT ) == 0 ) break;
if ( cChar == '\r' ) break;
if ( cChar != '\n' ) str = cChar + str;
}
str.TrimLeft();
str.TrimRight();
return str;
}
//////////////////////////////////////////////////////////////////////
// CLibraryBuilderInternals Collection (threaded)
BOOL CLibraryBuilderInternals::ReadCollection( HANDLE hFile, SHA1* pSHA1)
{
CCollectionFile pCollection;
if ( ! pCollection.Attach( hFile ) ) return FALSE;
LibraryFolders.MountCollection( pSHA1, &pCollection );
if ( CXMLElement* pMetadata = pCollection.GetMetadata() )
{
pMetadata = pMetadata->GetFirstElement()->Clone();
return SubmitMetadata( pCollection.GetThisURI(), pMetadata );
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -