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 "LibraryFolders.h"
00025 #include "LibraryBuilder.h"
00026 #include "LibraryBuilderInternals.h"
00027
00028 #define _ID3_DEFINE_GENRES
00029 #include "Buffer.h"
00030 #include "Schema.h"
00031 #include "XML.h"
00032 #include "ID3.h"
00033 #include "Packet.h"
00034 #include "CollectionFile.h"
00035
00036 #ifdef _DEBUG
00037 #undef THIS_FILE
00038 static char THIS_FILE[]=__FILE__;
00039 #define new DEBUG_NEW
00040 #endif
00041
00042
00044
00045
00046 CLibraryBuilderInternals::CLibraryBuilderInternals(CLibraryBuilder* pBuilder)
00047 {
00048 m_pBuilder = pBuilder;
00049 }
00050
00051 CLibraryBuilderInternals::~CLibraryBuilderInternals()
00052 {
00053 }
00054
00056
00057
00058 void CLibraryBuilderInternals::LoadSettings()
00059 {
00060 m_bEnableMP3 = theApp.GetProfileInt( _T("Library"), _T("ScanMP3"), TRUE );
00061 m_bEnableEXE = theApp.GetProfileInt( _T("Library"), _T("ScanEXE"), TRUE );
00062 m_bEnableImage = theApp.GetProfileInt( _T("Library"), _T("ScanImage"), TRUE );
00063 m_bEnableASF = theApp.GetProfileInt( _T("Library"), _T("ScanASF"), TRUE );
00064 m_bEnableOGG = theApp.GetProfileInt( _T("Library"), _T("ScanOGG"), TRUE );
00065 m_bEnableAPE = theApp.GetProfileInt( _T("Library"), _T("ScanAPE"), TRUE );
00066 m_bEnableAVI = theApp.GetProfileInt( _T("Library"), _T("ScanAVI"), TRUE );
00067 m_bEnablePDF = theApp.GetProfileInt( _T("Library"), _T("ScanPDF"), TRUE );
00068 m_bEnableCHM = theApp.GetProfileInt( _T("Library"), _T("ScanCHM"), TRUE );
00069 }
00070
00072
00073
00074 BOOL CLibraryBuilderInternals::ExtractMetadata( CString& strPath, HANDLE hFile, SHA1* pSHA1)
00075 {
00076 CString strType;
00077
00078 int nExtPos = strPath.ReverseFind( '.' );
00079 if ( nExtPos > 0 ) strType = strPath.Mid( nExtPos );
00080
00081 CharLower( strType.GetBuffer() );
00082 strType.ReleaseBuffer();
00083
00084 if ( strType == _T(".mp3") )
00085 {
00086 if ( ! m_bEnableMP3 ) return FALSE;
00087 if ( ReadID3v2( hFile ) ) return TRUE;
00088 if ( ReadID3v1( hFile ) ) return TRUE;
00089 if ( ReadMP3Frames( hFile ) ) return TRUE;
00090 return SubmitCorrupted();
00091 }
00092 else if ( strType == _T(".exe") || strType == _T(".dll") )
00093 {
00094 if ( ! m_bEnableEXE ) return FALSE;
00095 return ReadVersion( strPath );
00096 }
00097 else if ( strType == _T(".asf") || strType == _T(".wma") || strType == _T(".wmv") )
00098 {
00099 if ( ! m_bEnableASF ) return FALSE;
00100 return ReadASF( hFile );
00101 }
00102 else if ( strType == _T(".avi") )
00103 {
00104 if ( ! m_bEnableAVI ) return FALSE;
00105 return ReadAVI( hFile );
00106 }
00107 else if ( strType == _T(".mpg") || strType == _T(".mpeg") )
00108 {
00109 if ( ! m_bEnableASF ) return FALSE;
00110 return ReadMPEG( hFile );
00111 }
00112 else if ( strType == _T(".ogg") )
00113 {
00114 if ( ! m_bEnableOGG ) return FALSE;
00115 return ReadOGG( hFile );
00116 }
00117 else if ( strType == _T(".ape") || strType == _T(".mac") || strType == _T(".apl") )
00118 {
00119 if ( ! m_bEnableAPE ) return FALSE;
00120 return ReadAPE( hFile );
00121 }
00122 else if ( strType == _T(".jpg") || strType == _T(".jpeg") )
00123 {
00124 if ( ! m_bEnableImage ) return FALSE;
00125 return ReadJPEG( hFile );
00126 }
00127 else if ( strType == _T(".gif") )
00128 {
00129 if ( ! m_bEnableImage ) return FALSE;
00130 return ReadGIF( hFile );
00131 }
00132 else if ( strType == _T(".png") )
00133 {
00134 if ( ! m_bEnableImage ) return FALSE;
00135 return ReadPNG( hFile );
00136 }
00137 else if ( strType == _T(".bmp") )
00138 {
00139 if ( ! m_bEnableImage ) return FALSE;
00140 return ReadBMP( hFile );
00141 }
00142 else if ( strType == _T(".pdf") )
00143 {
00144 if ( ! m_bEnablePDF ) return FALSE;
00145 return ReadPDF( hFile, strPath );
00146 }
00147 else if ( strType == _T(".co") || strType == _T(".collection") )
00148 {
00149 return ReadCollection( hFile, pSHA1 );
00150 }
00151 else if ( strType == _T(".chm") )
00152 {
00153 if ( ! m_bEnableCHM ) return FALSE;
00154 return ReadCHM( hFile, strPath );
00155 }
00156 return FALSE;
00157 }
00158
00160
00161
00162 BOOL CLibraryBuilderInternals::SubmitMetadata( LPCTSTR pszSchemaURI, CXMLElement* pXML)
00163 {
00164
00165 m_pBuilder->SubmitMetadata( pszSchemaURI, pXML );
00166 return TRUE;
00167 }
00168
00169 BOOL CLibraryBuilderInternals::SubmitCorrupted()
00170 {
00171 return m_pBuilder->SubmitCorrupted();
00172 }
00173
00175
00176
00177 BOOL CLibraryBuilderInternals::ReadID3v1( HANDLE hFile, CXMLElement* pXML)
00178 {
00179 if ( GetFileSize( hFile, NULL ) < 128 ) return FALSE;
00180
00181 ID3V1 pInfo;
00182 DWORD nRead;
00183
00184 SetFilePointer( hFile, -128, NULL, FILE_END );
00185 ReadFile( hFile, &pInfo, sizeof(pInfo), &nRead, NULL );
00186
00187 if ( nRead != sizeof(pInfo) ) return FALSE;
00188 if ( strncmp( pInfo.szTag, ID3V1_TAG, 3 ) ) return FALSE;
00189
00190 BOOL bIsMP3 = ( pXML == NULL );
00191 if ( bIsMP3 ) pXML = new CXMLElement( NULL, _T("audio") );
00192
00193 CopyID3v1Field( pXML, _T("title"), pInfo.szSongname, 30 );
00194 CopyID3v1Field( pXML, _T("artist"), pInfo.szArtist, 30 );
00195 CopyID3v1Field( pXML, _T("album"), pInfo.szAlbum, 30 );
00196 CopyID3v1Field( pXML, _T("year"), pInfo.szYear, 4 );
00197
00198 if ( pInfo.nGenre < ID3_GENRES )
00199 {
00200 pXML->AddAttribute( _T("genre"), pszID3Genre[ pInfo.nGenre ] );
00201 }
00202
00203 if ( pInfo.szComment[28] == 0 && pInfo.szComment[29] > 0 )
00204 {
00205 CString strTrack;
00206 strTrack.Format( _T("%i"), (int)pInfo.szComment[29] );
00207 pXML->AddAttribute( _T("track"), strTrack );
00208 CopyID3v1Field( pXML, _T("description"), pInfo.szComment, 28 );
00209 }
00210 else
00211 {
00212 CopyID3v1Field( pXML, _T("description"), pInfo.szComment, 30 );
00213 }
00214
00215 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00216
00217 if ( bIsMP3 )
00218 {
00219 ScanMP3Frame( pXML, hFile, sizeof(pInfo) );
00220 return SubmitMetadata( CSchema::uriAudio, pXML );
00221 }
00222
00223 return TRUE;
00224 }
00225
00226 BOOL CLibraryBuilderInternals::CopyID3v1Field(CXMLElement* pXML, LPCTSTR pszAttribute, LPCSTR pszValue, int nLength)
00227 {
00228 CString strValue;
00229 int nWide = MultiByteToWideChar( CP_ACP, 0, pszValue, nLength, NULL, 0 );
00230 LPWSTR pszOutput = strValue.GetBuffer( nWide + 1 );
00231 MultiByteToWideChar( CP_ACP, 0, pszValue, nLength, pszOutput, nWide );
00232 pszOutput[ nWide ] = 0;
00233 strValue.ReleaseBuffer();
00234
00235 strValue.TrimLeft();
00236 strValue.TrimRight();
00237 if ( strValue.IsEmpty() ) return FALSE;
00238
00239 pXML->AddAttribute( pszAttribute, strValue );
00240
00241 return TRUE;
00242 }
00243
00245
00246
00247 BOOL CLibraryBuilderInternals::ReadID3v2( HANDLE hFile)
00248 {
00249 ID3V2_HEADER pHeader;
00250 DWORD nRead;
00251
00252 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00253 ReadFile( hFile, &pHeader, sizeof(pHeader), &nRead, NULL );
00254 if ( nRead != sizeof(pHeader) ) return FALSE;
00255
00256 if ( strncmp( pHeader.szTag, ID3V2_TAG, 3 ) ) return FALSE;
00257 if ( pHeader.nMajorVersion < 2 || pHeader.nMajorVersion > 4 ) return FALSE;
00258 if ( pHeader.nFlags & ~ID3V2_KNOWNMASK ) return FALSE;
00259 if ( pHeader.nFlags & ID3V2_UNSYNCHRONISED ) return FALSE;
00260
00261 DWORD nBuffer = SWAP_LONG( pHeader.nSize );
00262 ID3_DESYNC_SIZE( nBuffer );
00263
00264 if ( nBuffer > 1024 * 1024 * 2 ) return FALSE;
00265
00266 BYTE* pBuffer = new BYTE[ nBuffer ];
00267 BYTE* pRelease = pBuffer;
00268
00269 ReadFile( hFile, pBuffer, nBuffer, &nRead, NULL );
00270 if ( nRead != nBuffer )
00271 {
00272 delete [] pRelease;
00273 return FALSE;
00274 }
00275
00276 if ( ( pHeader.nFlags & ID3V2_EXTENDEDHEADER ) && pHeader.nMajorVersion == 3 )
00277 {
00278 if ( nBuffer < sizeof(ID3V2_EXTENDED_HEADER_1) )
00279 {
00280 delete [] pRelease;
00281 return FALSE;
00282 }
00283
00284 ID3V2_EXTENDED_HEADER_1* pExtended = (ID3V2_EXTENDED_HEADER_1*)pBuffer;
00285 pBuffer += sizeof(ID3V2_EXTENDED_HEADER_1);
00286 nBuffer -= sizeof(ID3V2_EXTENDED_HEADER_1);
00287
00288 pExtended->nSize = SWAP_LONG( pExtended->nSize );
00289
00290 if ( nBuffer < pExtended->nSize )
00291 {
00292 delete [] pRelease;
00293 return FALSE;
00294 }
00295
00296 pBuffer += pExtended->nSize;
00297 nBuffer -= pExtended->nSize;
00298 }
00299 else if ( ( pHeader.nFlags & ID3V2_EXTENDEDHEADER ) && pHeader.nMajorVersion == 4 )
00300 {
00301 if ( nBuffer < sizeof(ID3V2_EXTENDED_HEADER_2) )
00302 {
00303 delete [] pRelease;
00304 return FALSE;
00305 }
00306
00307 ID3V2_EXTENDED_HEADER_2* pExtended = (ID3V2_EXTENDED_HEADER_2*)pBuffer;
00308 pBuffer += sizeof(ID3V2_EXTENDED_HEADER_2);
00309 nBuffer -= sizeof(ID3V2_EXTENDED_HEADER_2);
00310
00311 pExtended->nSize = SWAP_LONG( pExtended->nSize );
00312 ID3_DESYNC_SIZE( pExtended->nSize );
00313 pExtended->nSize -= 6;
00314
00315 if ( nBuffer < pExtended->nSize )
00316 {
00317 delete [] pRelease;
00318 return FALSE;
00319 }
00320
00321 pBuffer += pExtended->nSize;
00322 nBuffer -= pExtended->nSize;
00323 }
00324
00325 CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
00326
00327 while ( TRUE )
00328 {
00329 DWORD nFrameSize = 0;
00330 CHAR szFrameTag[5];
00331
00332 if ( pHeader.nMajorVersion > 2 )
00333 {
00334 ID3V2_FRAME* pFrame = (ID3V2_FRAME*)pBuffer;
00335
00336 if ( nBuffer < sizeof(*pFrame) ) break;
00337 pBuffer += sizeof(*pFrame);
00338 nBuffer -= sizeof(*pFrame);
00339
00340 szFrameTag[0] = pFrame->szID[0];
00341 szFrameTag[1] = pFrame->szID[1];
00342 szFrameTag[2] = pFrame->szID[2];
00343 szFrameTag[3] = pFrame->szID[3];
00344 szFrameTag[4] = 0;
00345
00346 nFrameSize = SWAP_LONG( pFrame->nSize );
00347 if ( pHeader.nMajorVersion >= 4 ) ID3_DESYNC_SIZE( nFrameSize );
00348 if ( pFrame->nFlags2 & ~ID3V2_KNOWNFRAME ) szFrameTag[0] = 0;
00349 }
00350 else
00351 {
00352 ID3V2_FRAME_2* pFrame = (ID3V2_FRAME_2*)pBuffer;
00353
00354 if ( nBuffer < sizeof(*pFrame) ) break;
00355 pBuffer += sizeof(*pFrame);
00356 nBuffer -= sizeof(*pFrame);
00357
00358 szFrameTag[0] = pFrame->szID[0];
00359 szFrameTag[1] = pFrame->szID[1];
00360 szFrameTag[2] = pFrame->szID[2];
00361 szFrameTag[3] = szFrameTag[4] = 0;
00362 nFrameSize = ( pFrame->nSize[0] << 16 ) | ( pFrame->nSize[1] << 8 ) | pFrame->nSize[2];
00363 }
00364
00365 if ( nBuffer < nFrameSize || ! szFrameTag[0] ) break;
00366
00367 if ( strcmp( szFrameTag, "TIT2" ) == 0 || strcmp( szFrameTag, "TT2" ) == 0)
00368 {
00369 CopyID3v2Field( pXML, _T("title"), pBuffer, nFrameSize );
00370 }
00371 else if ( strcmp( szFrameTag, "TOPE" ) == 0 || strcmp( szFrameTag, "TOA" ) == 0 || strcmp( szFrameTag, "TPE1" ) == 0 || strcmp( szFrameTag, "TPE2" ) == 0 )
00372 {
00373 CopyID3v2Field( pXML, _T("artist"), pBuffer, nFrameSize );
00374 }
00375 else if ( strcmp( szFrameTag, "TALB" ) == 0 || strcmp( szFrameTag, "TOT" ) == 0 )
00376 {
00377 CopyID3v2Field( pXML, _T("album"), pBuffer, nFrameSize );
00378 }
00379 else if ( strcmp( szFrameTag, "TRCK" ) == 0 || strcmp( szFrameTag, "TRK" ) == 0 )
00380 {
00381 CopyID3v2Field( pXML, _T("track"), pBuffer, nFrameSize );
00382 }
00383 else if ( strcmp( szFrameTag, "TYER" ) == 0 || strcmp( szFrameTag, "TYE" ) == 0 )
00384 {
00385 CopyID3v2Field( pXML, _T("year"), pBuffer, nFrameSize );
00386 }
00387 else if ( strcmp( szFrameTag, "COMM" ) == 0 || strcmp( szFrameTag, "COM" ) == 0 )
00388 {
00389 CopyID3v2Field( pXML, _T("description"), pBuffer, nFrameSize, TRUE );
00390 }
00391 else if ( strcmp( szFrameTag, "TLEN" ) == 0 || strcmp( szFrameTag, "TLE" ) == 0 )
00392 {
00393 if ( CopyID3v2Field( pXML, _T("seconds"), pBuffer, nFrameSize ) )
00394 {
00395 CString strMS = pXML->GetAttributeValue( _T("seconds"), _T("0") );
00396 int nMS;
00397 _stscanf( strMS, _T("%lu"), &nMS );
00398 strMS.Format( _T("%lu"), nMS / 1000 );
00399 pXML->AddAttribute( _T("seconds"), strMS );
00400 }
00401 }
00402 else if ( strcmp( szFrameTag, "TCOP" ) == 0 || strcmp( szFrameTag, "TCR" ) == 0 )
00403 {
00404 CopyID3v2Field( pXML, _T("copyright"), pBuffer, nFrameSize );
00405 }
00406 else if ( strcmp( szFrameTag, "TCON" ) == 0 || strcmp( szFrameTag, "TCO" ) == 0 )
00407 {
00408 if ( CopyID3v2Field( pXML, _T("genre"), pBuffer, nFrameSize ) )
00409 {
00410 CString strGenre = pXML->GetAttributeValue( _T("genre"), _T("") );
00411
00412 while ( TRUE )
00413 {
00414 int nPos1 = strGenre.Find( '(' );
00415 if ( nPos1 < 0 ) break;
00416 int nPos2 = strGenre.Find( ')' );
00417 if ( nPos2 <= nPos1 ) break;
00418
00419 CString strValue = strGenre.Mid( nPos1 + 1, nPos2 - nPos1 - 1 );
00420 int nGenre = 0;
00421
00422 if ( strValue.CompareNoCase( _T("RX") ) == 0 )
00423 {
00424 strValue = _T("Remix");
00425 }
00426 else if ( strValue.CompareNoCase( _T("CR") ) == 0 )
00427 {
00428 strValue = _T("Cover");
00429 }
00430 else if ( _stscanf( strValue, _T("%i"), &nGenre ) == 1 && nGenre < ID3_GENRES )
00431 {
00432 if ( _tcsistr( strGenre, pszID3Genre[ nGenre ] ) == NULL )
00433 {
00434 strValue = pszID3Genre[ nGenre ];
00435 }
00436 else
00437 {
00438 strValue.Empty();
00439 }
00440 }
00441 else
00442 {
00443 strValue = _T("[") + strValue + _T("]");
00444 }
00445
00446 strGenre = strGenre.Left( nPos1 ) + strValue + strGenre.Mid( nPos2 + 1 );
00447 }
00448
00449 Replace( strGenre, _T("["), _T("(") );
00450 Replace( strGenre, _T("]"), _T(")") );
00451
00452 pXML->AddAttribute( _T("genre"), strGenre );
00453 }
00454 }
00455
00456 pBuffer += nFrameSize;
00457 nBuffer -= nFrameSize;
00458 }
00459
00460 delete [] pRelease;
00461
00462 ScanMP3Frame( pXML, hFile, 0 );
00463
00464 return SubmitMetadata( CSchema::uriAudio, pXML );
00465 }
00466
00467 BOOL CLibraryBuilderInternals::CopyID3v2Field(CXMLElement* pXML, LPCTSTR pszAttribute, BYTE* pBuffer, DWORD nLength, BOOL bSkipLanguage)
00468 {
00469 CString strValue;
00470
00471 BYTE nEncoding = *pBuffer++;
00472 nLength--;
00473
00474 if ( bSkipLanguage )
00475 {
00476 if ( nLength < 3 ) return FALSE;
00477 pBuffer += 3;
00478 nLength -= 3;
00479 if ( nLength > 0 && pBuffer[ 0 ] == 0 )
00480 {
00481 pBuffer += 1;
00482 nLength -= 1;
00483 }
00484 }
00485
00486 if ( nEncoding == 0 )
00487 {
00488 LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );
00489
00490 DWORD nOut = 0;
00491 for ( DWORD nChar = 0 ; nChar < nLength ; nChar++, nOut++ )
00492 {
00493 pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar ];
00494 if ( pszOutput[ nOut ] == 0 ) break;
00495 }
00496 strValue.ReleaseBuffer( nOut );
00497
00498 }
00499 else if ( nEncoding == 1 && ( nLength & 1 ) == 0 && nLength >= 2 )
00500 {
00501 nLength = ( nLength - 2 ) / 2;
00502 LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );
00503
00504 if ( pBuffer[0] == 0xFF && pBuffer[1] == 0xFE )
00505 {
00506 pBuffer += 2;
00507 DWORD nOut = 0;
00508 for ( DWORD nChar = 0 ; nChar < nLength ; nChar++, nOut++ )
00509 {
00510 pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar*2+0 ] | ( (TCHAR)pBuffer[ nChar*2+1 ] << 8 );
00511 if ( pszOutput[ nOut ] == 0 ) break;
00512 }
00513 strValue.ReleaseBuffer( nOut );
00514 }
00515 else if ( pBuffer[0] == 0xFE && pBuffer[1] == 0xFF )
00516 {
00517 pBuffer += 2;
00518 DWORD nOut = 0;
00519 for ( DWORD nChar = 0 ; nChar < nLength ; nChar++, nOut++ )
00520 {
00521 pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar*2+1 ] | ( (TCHAR)pBuffer[ nChar*2+0 ] << 8 );
00522 if ( pszOutput[ nOut ] == 0 ) break;
00523 }
00524 strValue.ReleaseBuffer( nOut );
00525 }
00526 else
00527 {
00528 strValue.ReleaseBuffer( 0 );
00529 return FALSE;
00530 }
00531 }
00532 else if ( nEncoding == 2 && ( nLength & 1 ) == 0 )
00533 {
00534 nLength = nLength / 2;
00535 LPTSTR pszOutput = strValue.GetBuffer( nLength + 1 );
00536
00537 DWORD nOut = 0;
00538 for ( DWORD nChar = 0 ; nChar < nLength ; nChar++, nOut++ )
00539 {
00540 pszOutput[ nOut ] = (TCHAR)pBuffer[ nChar*2+1 ] | ( (TCHAR)pBuffer[ nChar*2+0 ] << 8 );
00541 if ( pszOutput[ nOut ] == 0 ) break;
00542 }
00543
00544 strValue.ReleaseBuffer( nOut );
00545 }
00546 else if ( nEncoding == 3 )
00547 {
00548 int nWide = MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pBuffer, nLength, NULL, 0 );
00549 LPTSTR pszOutput = strValue.GetBuffer( nWide + 1 );
00550 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pBuffer, nLength, pszOutput, nWide );
00551 pszOutput[ nWide ] = 0;
00552 strValue.ReleaseBuffer();
00553 }
00554
00555 strValue.TrimLeft();
00556 strValue.TrimRight();
00557
00558 if ( strValue.GetLength() == 0 || _tcslen( strValue ) == 0 ) return FALSE;
00559
00560 pXML->AddAttribute( pszAttribute, strValue );
00561
00562 return TRUE;
00563 }
00564
00566
00567
00568 BOOL CLibraryBuilderInternals::ReadMP3Frames( HANDLE hFile)
00569 {
00570 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00571
00572 CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
00573
00574 if ( ScanMP3Frame( pXML, hFile, 0 ) )
00575 {
00576 return SubmitMetadata( CSchema::uriAudio, pXML );
00577 }
00578 else
00579 {
00580 delete pXML;
00581 return FALSE;
00582 }
00583 }
00584
00585 BOOL CLibraryBuilderInternals::ScanMP3Frame(CXMLElement* pXML, HANDLE hFile, DWORD nIgnore)
00586 {
00587 static DWORD nBitrateTable[16][5] =
00588 {
00589 { 0, 0, 0, 0 }, { 32, 32, 32, 32, 8 }, { 64, 48, 40, 48, 16 },
00590 { 96, 56, 48, 56, 24 }, { 128, 64, 56, 64, 32 }, { 160, 80, 64, 80, 40 },
00591 { 192, 96, 80, 96, 48 }, { 224, 112, 96, 112, 56 }, { 256, 128, 112, 128, 64 },
00592 { 288, 160, 128, 144, 80 }, { 320, 192, 160, 160, 96 }, { 352, 224, 192, 176, 112 },
00593 { 384, 256, 224, 192, 128 }, { 416, 320, 256, 224, 144 },{ 448, 384, 320, 256, 160 },
00594 { 0, 0, 0, 0 }
00595 };
00596
00597 static DWORD nFrequencyTable[4][4] =
00598 {
00599 { 11025, 0, 22050, 44100 },
00600 { 12000, 0, 24000, 48000 },
00601 { 8000, 0, 16000, 32000 },
00602 { 0, 0, 0, 0 }
00603 };
00604
00605 BYTE nLayer = 0;
00606 BOOL bVariable = FALSE;
00607 __int64 nTotalBitrate = 0;
00608 DWORD nBaseBitrate = 0;
00609 DWORD nBaseFrequency = 0;
00610 DWORD nFrameCount = 0;
00611 DWORD nFrameSize = 0;
00612 DWORD nHeader = 0;
00613
00614 DWORD nRead;
00615 ReadFile( hFile, &nHeader, 4, &nRead, NULL );
00616 if ( nRead != 4 ) return FALSE;
00617 nHeader = SWAP_LONG( nHeader );
00618
00619 for ( DWORD nSeek = 0 ; bVariable || ( nFrameCount < 16 && nSeek < 4096 ) ; nSeek++ )
00620 {
00621 DWORD nTime = GetTickCount();
00622
00623 if ( ( nHeader & 0xFFE00000 ) == 0xFFE00000 )
00624 {
00625 BYTE nVersion = (BYTE)( ( nHeader & 0x00180000 ) >> 19 );
00626 nLayer = (BYTE)( ( nHeader & 0x00060000 ) >> 17 );
00627 BYTE nBitIndex = (BYTE)( ( nHeader & 0x0000F000 ) >> 12 );
00628 BYTE nFreqIndex = (BYTE)( ( nHeader & 0x00000C00 ) >> 10 );
00629 BYTE nChannels = (BYTE)( ( nHeader & 0x000000C0 ) >> 6 );
00630 BOOL bPadding = (BOOL)( nHeader & 0x0200 ) ? TRUE : FALSE;
00631
00632 int nBitColumn = 0;
00633
00634 if ( nVersion == 3 )
00635 {
00636 if ( nLayer == 3 ) nBitColumn = 0;
00637 else if ( nLayer == 2 ) nBitColumn = 1;
00638 else if ( nLayer == 1 ) nBitColumn = 2;
00639 }
00640 else
00641 {
00642 if ( nLayer == 3 ) nBitColumn = 3;
00643 else nBitColumn = 4;
00644 }
00645
00646 DWORD nBitrate = nBitrateTable[ nBitIndex ][ nBitColumn ] * 1000;
00647 DWORD nFrequency = nFrequencyTable[ nFreqIndex ][ nVersion ];
00648
00649 if ( ! nFrequency ) return FALSE;
00650
00651 if ( nBaseBitrate )
00652 {
00653 if ( nBaseBitrate != nBitrate ) bVariable = TRUE;
00654 }
00655 else
00656 {
00657 nBaseBitrate = nBitrate;
00658 nBaseFrequency = nFrequency;
00659 }
00660
00661 nFrameSize = ( nLayer == 3 ) ? ( 12 * nBitrate / nFrequency + bPadding ) * 4
00662 : ( 144 * nBitrate / nFrequency + bPadding );
00663
00664 if ( ! nFrameSize ) return FALSE;
00665
00666 nTotalBitrate += nBitrate / 1000;
00667 nFrameCount++;
00668
00669 SetFilePointer( hFile, nFrameSize - 4, NULL, FILE_CURRENT );
00670 ReadFile( hFile, &nHeader, 4, &nRead, NULL );
00671 if ( nRead != 4 ) break;
00672 nHeader = SWAP_LONG( nHeader );
00673 }
00674 else
00675 {
00676 nHeader <<= 8;
00677 ReadFile( hFile, &nHeader, 1, &nRead, NULL );
00678 if ( nRead != 1 ) break;
00679 }
00680
00681 if ( ! m_pBuilder->m_bPriority )
00682 {
00683 m_nSleep = ( GetTickCount() - nTime ) * 3;
00684 if ( m_nSleep > 0 ) Sleep( m_nSleep );
00685 }
00686
00687 if ( ! m_pBuilder->m_bThread ) return FALSE;
00688 }
00689
00690 if ( nFrameCount < 16 || ! nFrameSize ) return FALSE;
00691
00692 if ( bVariable )
00693 {
00694 nBaseBitrate = (DWORD)( nTotalBitrate / nFrameCount ) * 1000;
00695 }
00696 else
00697 {
00698 DWORD dwFilePosition = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
00699 DWORD dwFileSize = GetFileSize( hFile, NULL );
00700 DWORD dwMusicSize = dwFileSize - dwFilePosition - nIgnore + 4;
00701 nFrameCount += ( dwMusicSize / nFrameSize ) - 1;
00702 }
00703
00704 DWORD nFrameTime = ( nLayer == 3 ? 384 : 1152 ) * 100000 / nBaseFrequency;
00705 DWORD nTotalTime = (DWORD)( (__int64)nFrameCount * (__int64)nFrameTime / 100000 );
00706
00707 CString strValue;
00708
00709 strValue.Format( bVariable ? _T("%lu~") : _T("%lu"), nBaseBitrate / 1000 );
00710 pXML->AddAttribute( _T("bitrate"), strValue );
00711
00712 strValue.Format( _T("%lu"), nTotalTime );
00713 pXML->AddAttribute( _T("seconds"), strValue );
00714
00715 strValue.Format( _T("%lu"), nBaseFrequency );
00716 pXML->AddAttribute( _T("sampleRate"), strValue );
00717
00718 return TRUE;
00719 }
00720
00722
00723
00724 BOOL CLibraryBuilderInternals::ReadVersion( LPCTSTR pszPath)
00725 {
00726 DWORD dwSize = GetFileVersionInfoSize( (LPTSTR)pszPath, &dwSize );
00727 if ( dwSize <= 152 ) return FALSE;
00728
00729 BYTE* pBuffer = new BYTE[ dwSize ];
00730
00731 if ( ! GetFileVersionInfo( (LPTSTR)pszPath, NULL, dwSize, pBuffer ) )
00732 {
00733 delete [] pBuffer;
00734 return FALSE;
00735 }
00736
00737 WCHAR* pLanguage = (WCHAR*)pBuffer + 20 + 26 + 18 + 3;
00738
00739 if ( wcslen( pLanguage ) != 8 )
00740 {
00741 delete [] pBuffer;
00742 return FALSE;
00743 }
00744
00745 CXMLElement* pXML = new CXMLElement( NULL, _T("application") );
00746
00747 pXML->AddAttribute( _T("os"), _T("Windows") );
00748 CopyVersionField( pXML, _T("title"), pBuffer, _T("ProductName") );
00749 CopyVersionField( pXML, _T("version"), pBuffer, _T("ProductVersion"), TRUE );
00750 CopyVersionField( pXML, _T("fileDescription"), pBuffer, _T("FileDescription") );
00751 CopyVersionField( pXML, _T("fileVersion"), pBuffer, _T("FileVersion"), TRUE );
00752 CopyVersionField( pXML, _T("originalFileName"), pBuffer, _T("OriginalFilename") );
00753 CopyVersionField( pXML, _T("company"), pBuffer, _T("CompanyName") );
00754 CopyVersionField( pXML, _T("copyright"), pBuffer, _T("LegalCopyright") );
00755 CopyVersionField( pXML, _T("comments"), pBuffer, _T("comments") );
00756
00757 delete [] pBuffer;
00758
00759 return SubmitMetadata( CSchema::uriApplication, pXML );
00760 }
00761
00762 BOOL CLibraryBuilderInternals::CopyVersionField(CXMLElement* pXML, LPCTSTR pszAttribute, BYTE* pBuffer, LPCTSTR pszKey, BOOL bCommaToDot)
00763 {
00764 CString strValue = GetVersionKey( pBuffer, pszKey );
00765
00766 if ( strValue.IsEmpty() ) return FALSE;
00767
00768 if ( bCommaToDot )
00769 {
00770 for ( int nPos = -1 ; ( nPos = strValue.Find( _T(", ") ) ) >= 0 ; )
00771 {
00772 strValue = strValue.Left( nPos ) + '.' + strValue.Mid( nPos + 2 );
00773 }
00774 }
00775
00776 pXML->AddAttribute( pszAttribute, strValue );
00777
00778 return TRUE;
00779 }
00780
00781 CString CLibraryBuilderInternals::GetVersionKey(BYTE* pBuffer, LPCTSTR pszKey)
00782 {
00783 CString strKey, strValue;
00784
00785 WCHAR* pLanguage = (WCHAR*)pBuffer + 20 + 26 + 18 + 3;
00786
00787 strKey = _T("\\StringFileInfo\\");
00788 strKey += pLanguage;
00789 strKey += _T("\\");
00790 strKey += pszKey;
00791
00792 BYTE* pValue = NULL;
00793 DWORD dwSize = 0;
00794
00795 if ( ! VerQueryValue( pBuffer, (LPTSTR)(LPCTSTR)strKey, (void**)&pValue, (UINT*)&dwSize ) )
00796 return strValue;
00797
00798 if ( pValue[1] )
00799 strValue = (LPCSTR)pValue;
00800 else
00801 strValue = (LPCTSTR)pValue;
00802
00803 return strValue;
00804 }
00805
00807
00808
00809 BOOL CLibraryBuilderInternals::ReadJPEG( HANDLE hFile)
00810 {
00811 DWORD nRead = 0;
00812 WORD wMagic = 0;
00813 BYTE nByte = 0;
00814
00815 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00816 ReadFile( hFile, &wMagic, 2, &nRead, NULL );
00817 if ( nRead != 2 || wMagic != 0xD8FF ) return SubmitCorrupted();
00818
00819 BYTE nBits = 0, nComponents = 0;
00820 WORD nWidth = 0, nHeight = 0;
00821 CString strComment;
00822
00823 for ( DWORD nSeek = 512 ; nSeek > 0 ; nSeek-- )
00824 {
00825 ReadFile( hFile, &nByte, 1, &nRead, NULL );
00826 if ( nRead != 1 ) return FALSE;
00827 if ( nByte != 0xFF ) continue;
00828
00829 while ( nByte == 0xFF )
00830 {
00831 ReadFile( hFile, &nByte, 1, &nRead, NULL );
00832 if ( nRead != 1 ) return FALSE;
00833 }
00834
00835 ReadFile( hFile, &wMagic, 2, &nRead, NULL );
00836 wMagic = ( wMagic >> 8 ) | ( wMagic << 8 );
00837 if ( nRead != 2 || wMagic < 2 ) return FALSE;
00838
00839 switch ( nByte )
00840 {
00841 case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC5: case 0xC6: case 0xC7:
00842 case 0xC9: case 0xCA: case 0xCB: case 0xCD: case 0xCE: case 0xCF:
00843 ReadFile( hFile, &nBits, 1, &nRead, NULL );
00844 if ( nRead != 1 ) return FALSE;
00845 ReadFile( hFile, &nHeight, 2, &nRead, NULL );
00846 if ( nRead != 2 ) return FALSE;
00847 nHeight = ( nHeight >> 8 ) | ( nHeight << 8 );
00848 ReadFile( hFile, &nWidth, 2, &nRead, NULL );
00849 if ( nRead != 2 ) return FALSE;
00850 nWidth = ( nWidth >> 8 ) | ( nWidth << 8 );
00851 ReadFile( hFile, &nComponents, 1, &nRead, NULL );
00852 if ( nRead != 1 ) return FALSE;
00853 if ( wMagic < 8 ) return FALSE;
00854 SetFilePointer( hFile, wMagic - 8, NULL, FILE_CURRENT );
00855 break;
00856 case 0xFE: case 0xEC:
00857 if ( wMagic > 2 )
00858 {
00859 CBuffer pComment;
00860 pComment.EnsureBuffer( wMagic - 2 );
00861 pComment.m_nLength = (DWORD)wMagic - 2;
00862 ReadFile( hFile, pComment.m_pBuffer, wMagic - 2, &nRead, NULL );
00863 strComment = pComment.ReadString( nRead );
00864 }
00865 break;
00866 case 0xD9: case 0xDA:
00867 nSeek = 1;
00868 break;
00869 default:
00870 SetFilePointer( hFile, wMagic - 2, NULL, FILE_CURRENT );
00871 break;
00872 }
00873 }
00874
00875 if ( nWidth == 0 || nHeight == 0 ) return FALSE;
00876
00877 strComment.TrimLeft();
00878 strComment.TrimRight();
00879
00880 for ( int nChar = 0 ; nChar < strComment.GetLength() ; nChar++ )
00881 {
00882 if ( strComment[ nChar ] < 32 ) strComment.SetAt( nChar, '?' );
00883 }
00884
00885 CXMLElement* pXML = new CXMLElement( NULL, _T("image") );
00886 CString strItem;
00887
00888 strItem.Format( _T("%lu"), nWidth );
00889 pXML->AddAttribute( _T("width"), strItem );
00890 strItem.Format( _T("%lu"), nHeight );
00891 pXML->AddAttribute( _T("height"), strItem );
00892
00893 if ( nComponents == 3 ) pXML->AddAttribute( _T("colors"), _T("16.7M") );
00894 else if ( nComponents == 1 ) pXML->AddAttribute( _T("colors"), _T("Greyscale") );
00895
00896 if ( strComment.GetLength() ) pXML->AddAttribute( _T("description"), strComment );
00897
00898 return SubmitMetadata( CSchema::uriImage, pXML );
00899 }
00900
00902
00903
00904 BOOL CLibraryBuilderInternals::ReadGIF( HANDLE hFile)
00905 {
00906 CHAR szMagic[6];
00907 DWORD nRead;
00908
00909 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00910 ReadFile( hFile, szMagic, 6, &nRead, NULL );
00911
00912 if ( nRead != 6 || ( strncmp( szMagic, "GIF87a", 6 ) && strncmp( szMagic, "GIF89a", 6 ) ) )
00913 return SubmitCorrupted();
00914
00915 WORD nWidth, nHeight;
00916
00917 ReadFile( hFile, &nWidth, 2, &nRead, NULL );
00918 if ( nRead != 2 || nWidth == 0 ) return FALSE;
00919 ReadFile( hFile, &nHeight, 2, &nRead, NULL );
00920 if ( nRead != 2 || nHeight == 0 ) return FALSE;
00921
00922 CXMLElement* pXML = new CXMLElement( NULL, _T("image") );
00923 CString strItem;
00924
00925 strItem.Format( _T("%lu"), nWidth );
00926 pXML->AddAttribute( _T("width"), strItem );
00927 strItem.Format( _T("%lu"), nHeight );
00928 pXML->AddAttribute( _T("height"), strItem );
00929
00930 pXML->AddAttribute( _T("colors"), _T("256") );
00931
00932 return SubmitMetadata( CSchema::uriImage, pXML );
00933 }
00934
00936
00937
00938 BOOL CLibraryBuilderInternals::ReadPNG( HANDLE hFile)
00939 {
00940 BYTE nMagic[8];
00941 DWORD nRead;
00942
00943 if ( GetFileSize( hFile, NULL ) < 33 ) return SubmitCorrupted();
00944 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
00945
00946 ReadFile( hFile, nMagic, 8, &nRead, NULL );
00947 if ( nRead != 8 ) return SubmitCorrupted();
00948 if ( nMagic[0] != 137 || nMagic[1] != 80 || nMagic[2] != 78 ) return SubmitCorrupted();
00949 if ( nMagic[3] != 71 || nMagic[4] != 13 || nMagic[5] != 10 ) return SubmitCorrupted();
00950 if ( nMagic[6] != 26 || nMagic[7] != 10 ) return SubmitCorrupted();
00951
00952 DWORD nLength, nIHDR;
00953
00954 ReadFile( hFile, &nLength, 4, &nRead, NULL ); nLength = SWAP_LONG( nLength );
00955 if ( nRead != 4 || nLength < 10 ) return FALSE;
00956 ReadFile( hFile, &nIHDR, 4, &nRead, NULL );
00957 if ( nRead != 4 || nIHDR != 'RDHI' ) return FALSE;
00958
00959 DWORD nWidth, nHeight;
00960 BYTE nBits, nColors;
00961
00962 ReadFile( hFile, &nWidth, 4, &nRead, NULL ); nWidth = SWAP_LONG( nWidth );
00963 if ( nRead != 4 || nWidth <= 0 || nWidth > 0xFFFF ) return FALSE;
00964 ReadFile( hFile, &nHeight, 4, &nRead, NULL ); nHeight = SWAP_LONG( nHeight );
00965 if ( nRead != 4 || nHeight <= 0 || nHeight > 0xFFFF ) return FALSE;
00966
00967 ReadFile( hFile, &nBits, 1, &nRead, NULL );
00968 if ( nRead != 1 ) return FALSE;
00969 ReadFile( hFile, &nColors, 1, &nRead, NULL );
00970 if ( nRead != 1 ) return FALSE;
00971
00972 CXMLElement* pXML = new CXMLElement( NULL, _T("image") );
00973 CString strItem;
00974
00975 strItem.Format( _T("%lu"), nWidth );
00976 pXML->AddAttribute( _T("width"), strItem );
00977 strItem.Format( _T("%lu"), nHeight );
00978 pXML->AddAttribute( _T("height"), strItem );
00979
00980
00981
00982
00983
00984
00985
00986
00987 {
00988 switch ( nBits )
00989 {
00990 case 1:
00991 pXML->AddAttribute( _T("colors"), _T("2") );
00992 break;
00993 case 2:
00994 pXML->AddAttribute( _T("colors"), _T("4") );
00995 break;
00996 case 4:
00997 pXML->AddAttribute( _T("colors"), _T("16") );
00998 break;
00999 case 8:
01000 pXML->AddAttribute( _T("colors"), _T("256") );
01001 break;
01002 case 16:
01003 pXML->AddAttribute( _T("colors"), _T("64K") );
01004 break;
01005 }
01006 }
01007
01008 return SubmitMetadata( CSchema::uriImage, pXML );
01009 }
01010
01012
01013
01014 BOOL CLibraryBuilderInternals::ReadBMP( HANDLE hFile)
01015 {
01016 BITMAPFILEHEADER pBFH;
01017 BITMAPINFOHEADER pBIH;
01018 DWORD nRead;
01019
01020 if ( GetFileSize( hFile, NULL ) < sizeof(pBFH) + sizeof(pBIH) ) return SubmitCorrupted();
01021
01022 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01023 ReadFile( hFile, &pBFH, sizeof(pBFH), &nRead, NULL );
01024 if ( nRead != sizeof(pBFH) || pBFH.bfType != 'MB' ) return SubmitCorrupted();
01025
01026 ReadFile( hFile, &pBIH, sizeof(pBIH), &nRead, NULL );
01027 if ( nRead != sizeof(pBIH) || pBIH.biSize != sizeof(pBIH) ) return FALSE;
01028
01029 CXMLElement* pXML = new CXMLElement( NULL, _T("image") );
01030 CString strItem;
01031
01032 strItem.Format( _T("%lu"), pBIH.biWidth );
01033 pXML->AddAttribute( _T("width"), strItem );
01034 strItem.Format( _T("%lu"), pBIH.biHeight );
01035 pXML->AddAttribute( _T("height"), strItem );
01036
01037 switch ( pBIH.biBitCount )
01038 {
01039 case 4:
01040 pXML->AddAttribute( _T("colors"), _T("16") );
01041 break;
01042 case 8:
01043 pXML->AddAttribute( _T("colors"), _T("256") );
01044 break;
01045 case 24:
01046 pXML->AddAttribute( _T("colors"), _T("16.7M") );
01047 break;
01048 }
01049
01050 return SubmitMetadata( CSchema::uriImage, pXML );
01051 }
01052
01054
01055
01056 static const CLSID asfHeader1 =
01057 { 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C } };
01058
01059 static const CLSID asfContent1 =
01060 { 0x75B22633, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C } };
01061
01062 static const CLSID asfProperties1 =
01063 { 0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 } };
01064
01065 static const CLSID asfStream1 =
01066 { 0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 } };
01067
01068 static const CLSID asfVideo1 =
01069 { 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B } };
01070
01071 static const CLSID asfData1 =
01072 { 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c } };
01073
01074
01075 static const CLSID asfHeader2 =
01076 { 0xD6E229D1, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01077
01078
01079 static const CLSID asfData2 =
01080 { 0xD6E229D2, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01081
01082
01083 static const CLSID asfProperties2 =
01084 { 0xD6E229D0, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01085
01086
01087 static const CLSID asfStream2 =
01088 { 0xD6E229D4, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01089
01090
01091 static const CLSID asfContent2 =
01092 { 0xD6E229D5, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01093
01094
01095 static const CLSID asfAudio2 =
01096 { 0xD6E229E2, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01097
01098
01099 static const CLSID asfVideo2 =
01100 { 0xD6E229E3, 0x35DA, 0x11d1, { 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE } };
01101
01102
01103 static const CLSID asfDRM1 =
01104 { 0x2211B3FB, 0xBD23, 0x11D2, { 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E } };
01105
01106
01107 static const CLSID asfDRM2 =
01108 { 0x1EFB1A30, 0x0B62, 0x11D0, { 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 } };
01109
01110 BOOL CLibraryBuilderInternals::ReadASF( HANDLE hFile)
01111 {
01112 QWORD nSize;
01113 DWORD nRead;
01114 GUID pGUID;
01115
01116 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01117 ReadFile( hFile, &pGUID, sizeof(pGUID), &nRead, NULL );
01118 if ( nRead != sizeof(pGUID) || ( pGUID != asfHeader1 && pGUID != asfHeader2 ) )
01119 return SubmitCorrupted();
01120 ReadFile( hFile, &nSize, sizeof(nSize), &nRead, NULL );
01121 if ( nRead != sizeof(nSize) ) return SubmitCorrupted();
01122
01123 if ( pGUID == asfHeader1 ) SetFilePointer( hFile, 6, NULL, FILE_CURRENT );
01124
01125 CString strTitle, strAuthor, strCopyright, strDescription, strRating;
01126 DWORD nBitrate = 0, nVideoWidth = 0, nVideoHeight = 0;
01127 QWORD nContentLength = 0;
01128 BOOL bVideo = FALSE;
01129 BOOL bDRM = FALSE;
01130
01131 while ( TRUE )
01132 {
01133 DWORD dwPosition = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
01134
01135 ReadFile( hFile, &pGUID, sizeof(pGUID), &nRead, NULL );
01136 if ( nRead != sizeof(pGUID) ) break;
01137 ReadFile( hFile, &nSize, sizeof(nSize), &nRead, NULL );
01138 if ( nRead != sizeof(nSize) || nSize >= 0x80000000 ) break;
01139
01140 if ( pGUID == asfProperties1 )
01141 {
01142 SetFilePointer( hFile, 48, NULL, FILE_CURRENT );
01143 ReadFile( hFile, &nContentLength, sizeof(nContentLength), &nRead, NULL );
01144 if ( nRead != sizeof(nContentLength) ) return FALSE;
01145 }
01146 else if ( pGUID == asfProperties2 )
01147 {
01148 SetFilePointer( hFile, 40, NULL, FILE_CURRENT );
01149 ReadFile( hFile, &nContentLength, sizeof(nContentLength), &nRead, NULL );
01150 if ( nRead != sizeof(nContentLength) ) return FALSE;
01151 SetFilePointer( hFile, 8, NULL, FILE_CURRENT );
01152 ReadFile( hFile, &nBitrate, sizeof(nBitrate), &nRead, NULL );
01153 if ( nRead != sizeof(nBitrate) ) return FALSE;
01154 }
01155 else if ( pGUID == asfStream1 )
01156 {
01157 ReadFile( hFile, &pGUID, sizeof(pGUID), &nRead, NULL );
01158 if ( nRead != sizeof(pGUID) ) return FALSE;
01159
01160 if ( pGUID == asfVideo1 )
01161 {
01162 bVideo = TRUE;
01163 SetFilePointer( hFile, 38, NULL, FILE_CURRENT );
01164 ReadFile( hFile, &nVideoWidth, sizeof(nVideoWidth), &nRead, NULL );
01165 if ( nRead != sizeof(nVideoWidth) ) return FALSE;
01166 ReadFile( hFile, &nVideoHeight, sizeof(nVideoHeight), &nRead, NULL );
01167 if ( nRead != sizeof(nVideoHeight) ) return FALSE;
01168 }
01169 }
01170 else if ( pGUID == asfStream2 )
01171 {
01172 ReadFile( hFile, &pGUID, sizeof(pGUID), &nRead, NULL );
01173 if ( nRead != sizeof(pGUID) ) return FALSE;
01174
01175 if ( pGUID == asfVideo2 )
01176 {
01177 bVideo = TRUE;
01178
01179
01180
01181
01182
01183
01184
01185 }
01186 }
01187 else if ( pGUID == asfContent1 )
01188 {
01189 WORD nStrLen[5];
01190 ReadFile( hFile, nStrLen, sizeof(nStrLen), &nRead, NULL );
01191 if ( nRead != sizeof(nStrLen) ) break;
01192
01193 for ( int nStr = 0 ; nStr < 5 ; nStr++ )
01194 {
01195 if ( ! nStrLen[ nStr ] || nStrLen[ nStr ] & 1 ) continue;
01196 WCHAR* pStr = new WCHAR[ nStrLen[ nStr ] / 2 ];
01197 ReadFile( hFile, pStr, nStrLen[ nStr ], &nRead, NULL );
01198 if ( nRead != nStrLen[ nStr ] ) return FALSE;
01199 pStr[ nStrLen[ nStr ] / 2 - 1 ] = 0;
01200
01201 switch ( nStr )
01202 {
01203 case 0:
01204 strTitle = pStr;
01205 break;
01206 case 1:
01207 strAuthor = pStr;
01208 break;
01209 case 2:
01210 strCopyright = pStr;
01211 break;
01212 case 3:
01213 strDescription = pStr;
01214 break;
01215 case 4:
01216 strRating = pStr;
01217 break;
01218 }
01219
01220 delete [] pStr;
01221 }
01222 }
01223 else if ( pGUID == asfContent2 )
01224 {
01225 WORD nCount;
01226 ReadFile( hFile, &nCount, sizeof(nCount), &nRead, NULL );
01227 if ( nRead != sizeof(nCount) ) break;
01228
01229 while ( nCount-- )
01230 {
01231 WORD nLanguageID, nStreamID, nNameLen, nValueLen;
01232 BYTE nFieldType;
01233 WCHAR* pStr;
01234
01235 ReadFile( hFile, &nFieldType, sizeof(nFieldType), &nRead, NULL );
01236 if ( nRead != sizeof(nFieldType) ) return FALSE;
01237 ReadFile( hFile, &nLanguageID, sizeof(nLanguageID), &nRead, NULL );
01238 if ( nRead != sizeof(nLanguageID) ) return FALSE;
01239 ReadFile( hFile, &nStreamID, sizeof(nStreamID), &nRead, NULL );
01240 if ( nRead != sizeof(nStreamID) ) return FALSE;
01241 ReadFile( hFile, &nNameLen, sizeof(nNameLen), &nRead, NULL );
01242 if ( nRead != sizeof(nNameLen) ) return FALSE;
01243 ReadFile( hFile, &nValueLen, sizeof(nValueLen), &nRead, NULL );
01244 if ( nRead != sizeof(nValueLen) ) return FALSE;
01245
01246 pStr = new WCHAR[ nNameLen + 1 ];
01247 ReadFile( hFile, pStr, nNameLen * 2, &nRead, NULL );
01248 if ( nRead != (DWORD)nNameLen * 2 ) return FALSE;
01249 pStr[ nNameLen ] = 0;
01250 delete [] pStr;
01251
01252 pStr = new WCHAR[ nValueLen + 1 ];
01253 ReadFile( hFile, pStr, nValueLen * 2, &nRead, NULL );
01254 if ( nRead != (DWORD)nValueLen * 2 ) return FALSE;
01255 pStr[ nValueLen ] = 0;
01256
01257 switch ( nFieldType )
01258 {
01259 case 1:
01260 strAuthor = pStr;
01261 break;
01262 case 2: case 20:
01263 strTitle = pStr;
01264 break;
01265 case 3:
01266 strCopyright = pStr;
01267 break;
01268 case 4:
01269 strDescription = pStr;
01270 break;
01271 }
01272
01273 delete [] pStr;
01274 }
01275 }
01276 else if ( pGUID == asfDRM1 || pGUID == asfDRM2 )
01277 {
01278 bDRM = TRUE;
01279 }
01280 else if ( pGUID == asfData1 || pGUID == asfData2 )
01281 {
01282 break;
01283 }
01284
01285 SetFilePointer( hFile, dwPosition + (DWORD)nSize, NULL, FILE_BEGIN );
01286 }
01287
01288 CXMLElement* pXML = new CXMLElement( NULL, bVideo ? _T("video") : _T("audio") );
01289 CString strItem;
01290
01291 if ( strTitle.GetLength() ) pXML->AddAttribute( _T("title"), strTitle );
01292
01293 if ( strDescription.GetLength() ) pXML->AddAttribute( _T("description"), strDescription );
01294
01295 if ( bDRM )
01296 {
01297 pXML->AddAttribute( _T("drm"), _T("true") );
01298 }
01299
01300 if ( bVideo )
01301 {
01302 if ( strAuthor.GetLength() ) pXML->AddAttribute( _T("producer"), strAuthor );
01303
01304 if ( strRating.GetLength() ) pXML->AddAttribute( _T("rating"), strRating );
01305
01306 if ( nContentLength > 0 )
01307 {
01308 DWORD nSeconds = (DWORD)( nContentLength / 10000000 );
01309 strItem.Format( _T("%lu.%lu"), nSeconds / 60, ( ( nSeconds % 60 ) * 10 / 60 ) );
01310 pXML->AddAttribute( _T("minutes"), strItem );
01311 }
01312
01313 if ( nVideoWidth > 0 && nVideoHeight > 0 )
01314 {
01315 strItem.Format( _T("%lu"), nVideoWidth );
01316 pXML->AddAttribute( _T("width"), strItem );
01317 strItem.Format( _T("%lu"), nVideoHeight );
01318 pXML->AddAttribute( _T("height"), strItem );
01319 }
01320 }
01321 else
01322 {
01323 if ( strAuthor.GetLength() ) pXML->AddAttribute( _T("artist"), strAuthor );
01324
01325 if ( nContentLength > 0 )
01326 {
01327 strItem.Format( _T("%lu"), (DWORD)( nContentLength / 10000000 ) );
01328 pXML->AddAttribute( _T("seconds"), strItem );
01329 }
01330
01331 if ( nBitrate > 0 )
01332 {
01333 strItem.Format( _T("%lu"), nBitrate / 1000 );
01334 pXML->AddAttribute( _T("bitrate"), strItem );
01335 }
01336 }
01337
01338 pXML->AddAttribute( _T("codec"), _T("WM") );
01339
01340 return SubmitMetadata( bVideo ? CSchema::uriVideo : CSchema::uriAudio, pXML );
01341 }
01342
01344
01345
01346 BOOL CLibraryBuilderInternals::ReadMPEG( HANDLE hFile)
01347 {
01348 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01349
01350 DWORD nHeader = 0;
01351
01352 DWORD nSeek = 8192;
01353 for ( ; nSeek > 0 ; nSeek--, nHeader <<= 8 )
01354 {
01355 DWORD nRead = 0;
01356 ReadFile( hFile, &nHeader, 1, &nRead, NULL );
01357 if ( nRead != 1 ) break;
01358
01359 if ( nHeader == 0x000001B3 ) break;
01360 }
01361
01362 if ( ! nSeek ) return FALSE;
01363
01364 BYTE nBuffer[7];
01365
01366 ReadFile( hFile, nBuffer, 7, &nHeader, NULL );
01367 if ( nHeader != 7 ) return FALSE;
01368
01369 CXMLElement* pXML = new CXMLElement( NULL, _T("video") );
01370 CString strItem;
01371
01372 DWORD nWidth, nHeight;
01373 nWidth = ( (DWORD)nBuffer[0] << 4 ) | (DWORD)nBuffer[1] >> 4;
01374 nHeight = ( ( (DWORD)nBuffer[1] & 0x0F ) << 8 ) | (DWORD)nBuffer[2];
01375
01376 strItem.Format( _T("%lu"), nWidth );
01377 pXML->AddAttribute( _T("width"), strItem );
01378 strItem.Format( _T("%lu"), nHeight );
01379 pXML->AddAttribute( _T("height"), strItem );
01380 pXML->AddAttribute( _T("codec"), _T("MPEG") );
01381
01382 LPCTSTR pszFPS[] = { _T("23.976"), _T("24"), _T("25"), _T("29.97"), _T("30"), _T("50"), _T("59.94"), _T("60") };
01383 int nFrameIndex = ( nBuffer[3] & 0x0F );
01384
01385 if ( nFrameIndex >= 1 && nFrameIndex < 9 )
01386 {
01387 pXML->AddAttribute( _T("frameRate"), pszFPS[ nFrameIndex - 1 ] );
01388 }
01389
01390 return SubmitMetadata( CSchema::uriVideo, pXML );
01391 }
01392
01394
01395
01396 BOOL CLibraryBuilderInternals::ReadOGG( HANDLE hFile)
01397 {
01398 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01399
01400 DWORD nDummy, nHeader = 0;
01401 ReadFile( hFile, &nHeader, 4, &nDummy, NULL );
01402
01403 for ( DWORD nSeek = 0 ; nSeek < 16384 ; nSeek++ )
01404 {
01405 if ( nHeader == 'SggO' ) break;
01406 nHeader >>= 8;
01407 ReadFile( hFile, (BYTE*)&nHeader + 3, 1, &nDummy, NULL );
01408 }
01409
01410 if ( nHeader != 'SggO' ) return SubmitCorrupted();
01411 SetFilePointer( hFile, -4, NULL, FILE_CURRENT );
01412
01413 DWORD nOGG = 0;
01414 BYTE* pOGG = ReadOGGPage( hFile, nOGG, 0x02, 0, 0x1E );
01415
01416 if ( ! pOGG ) return FALSE;
01417
01418 BYTE nChannels = pOGG[ 11 ];
01419 DWORD nFrequency = *(DWORD*)&pOGG[12];
01420 DWORD nBitrate = *(DWORD*)&pOGG[20];
01421
01422 delete [] pOGG;
01423 BYTE* prOGG = pOGG = ReadOGGPage( hFile, nOGG, 0x00, 1, 1+6+4+4 );
01424
01425 if ( ! pOGG ) return FALSE;
01426 pOGG += 1 + 6;
01427 nOGG -= 1 + 6;
01428
01429 CString strComment;
01430
01431 if ( ! ReadOGGString( pOGG, nOGG, strComment ) || nOGG < 4 )
01432 {
01433 free( pOGG );
01434 return FALSE;
01435 }
01436
01437 DWORD nComments = *(DWORD*)pOGG;
01438 pOGG += 4; nOGG -= 4;
01439
01440 CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
01441
01442 for ( ; nComments && nOGG > 4 ; nComments-- )
01443 {
01444 if ( ! ReadOGGString( pOGG, nOGG, strComment ) ) break;
01445
01446 int nEquals = strComment.Find( '=' );
01447 if ( nEquals <= 0 ) continue;
01448
01449 CString strKey = strComment.Left( nEquals );
01450 CString strValue = strComment.Mid( nEquals + 1 );
01451
01452 strKey.TrimLeft(); strKey.TrimRight();
01453 CharUpper( strKey.GetBuffer() );
01454 strKey.ReleaseBuffer();
01455
01456
01457 int nLength = strValue.GetLength();
01458
01459 LPTSTR pszSource = new TCHAR[ nLength + 1 ];
01460 CHAR* pszDest = new CHAR[ nLength + 1 ];
01461
01462 _tcscpy( pszSource, strValue.GetBuffer() );
01463 for ( unsigned int nLen = 0; nLen < _tcslen( pszSource ); nLen++ )
01464 pszDest[ nLen ] = (CHAR) pszSource[ nLen ];
01465 delete pszSource;
01466
01467 int nWide = MultiByteToWideChar( CP_UTF8, 0, pszDest, nLength, NULL, 0 );
01468 LPWSTR pszWide = new WCHAR[ nWide + 1 ];
01469 MultiByteToWideChar( CP_UTF8, 0, pszDest, nLength, pszWide, nWide );
01470 pszWide[ nWide ] = 0;
01471 strValue = pszWide;
01472
01473 delete [] pszWide;
01474 delete pszDest;
01475
01476 strValue.TrimLeft(); strValue.TrimRight();
01477
01478 if ( strValue.IsEmpty() ) continue;
01479
01480 if ( strKey == _T("TITLE") )
01481 {
01482 pXML->AddAttribute( _T("title"), strValue );
01483 }
01484 else if ( strKey == _T("ALBUM") )
01485 {
01486 pXML->AddAttribute( _T("album"), strValue );
01487 }
01488 else if ( strKey == _T("TRACKNUMBER") )
01489 {
01490 pXML->AddAttribute( _T("track"), strValue );
01491 }
01492 else if ( strKey == _T("ARTIST") )
01493 {
01494 pXML->AddAttribute( _T("artist"), strValue );
01495 }
01496 else if ( strKey == _T("DESCRIPTION") )
01497 {
01498 pXML->AddAttribute( _T("description"), strValue );
01499 }
01500 else if ( strKey == _T("GENRE") )
01501 {
01502 pXML->AddAttribute( _T("genre"), strValue );
01503 }
01504 else if ( strKey == _T("DATE") )
01505 {
01506 pXML->AddAttribute( _T("year"), strValue );
01507 }
01508 else if ( strKey == _T("LICENSE") )
01509 {
01510 pXML->AddAttribute( _T("copyright"), strValue );
01511 }
01512 }
01513
01514 delete [] prOGG;
01515
01516 if ( nComments )
01517 {
01518 if ( pXML ) delete pXML;
01519 return FALSE;
01520 }
01521
01522 DWORD nLength = 0;
01523
01524 for ( nComments = 2 ; ; nComments++ )
01525 {
01526 DWORD nTime = GetTickCount();
01527 if ( ! ReadOGGPage( hFile, nOGG, 0xFF, nComments, 0xFFFFFFFF ) ) break;
01528 nLength = max( nLength, nOGG );
01529 m_nSleep = ( GetTickCount() - nTime ) * 3;
01530 if ( m_nSleep > 0 ) Sleep( m_nSleep );
01531 if ( ! m_pBuilder->m_bThread ) break;
01532 }
01533
01534 if ( ! m_pBuilder->m_bThread )
01535 {
01536 delete pXML;
01537 return FALSE;
01538 }
01539
01540 if ( nFrequency > 0 && nLength > 0 && ( nLength / nFrequency ) > 0 )
01541 {
01542 strComment.Format( _T("%lu"), nLength / nFrequency );
01543 pXML->AddAttribute( _T("seconds"), strComment );
01544
01545 nBitrate = GetFileSize( hFile, NULL ) / ( nLength / nFrequency ) * 8;
01546 }
01547
01548 strComment.Format( _T("%lu"), nBitrate / 1000 );
01549 pXML->AddAttribute( _T("bitrate"), strComment );
01550
01551 strComment.Format( _T("%lu"), nFrequency );
01552 pXML->AddAttribute( _T("sampleRate"), strComment );
01553
01554 return SubmitMetadata( CSchema::uriAudio, pXML );
01555 }
01556
01557 BYTE* CLibraryBuilderInternals::ReadOGGPage(HANDLE hFile, DWORD& nBuffer, BYTE nFlags, DWORD nSequence, DWORD nMinSize)
01558 {
01559 DWORD nMagic, nRead, nSample;
01560 BYTE nByte, nChunk;
01561
01562 nBuffer = 0;
01563
01564 ReadFile( hFile, &nMagic, 4, &nRead, NULL );
01565 if ( nRead != 4 || nMagic != 'SggO' ) return NULL;
01566
01567 ReadFile( hFile, &nByte, 1, &nRead, NULL );
01568 if ( nRead != 1 || nByte != 0 ) return NULL;
01569
01570 ReadFile( hFile, &nByte, 1, &nRead, NULL );
01571 if ( nRead != 1 ) return NULL;
01572 if ( nFlags < 0xFF && nByte != nFlags ) return NULL;
01573
01574 ReadFile( hFile, &nSample, 4, &nRead, NULL );
01575 if ( nRead != 4 ) return NULL;
01576
01577 SetFilePointer( hFile, 4 + 4, NULL, FILE_CURRENT );
01578
01579 ReadFile( hFile, &nMagic, 4, &nRead, NULL );
01580 if ( nRead != 4 || nMagic != nSequence ) return NULL;
01581
01582 ReadFile( hFile, &nMagic, 4, &nRead, NULL );
01583 if ( nRead != 4 ) return NULL;
01584
01585 ReadFile( hFile, &nByte, 1, &nRead, NULL );
01586 if ( nRead != 1 ) return NULL;
01587
01588 for ( ; nByte ; nByte-- )
01589 {
01590 ReadFile( hFile, &nChunk, 1, &nRead, NULL );
01591 if ( nRead != 1 ) break;
01592 nBuffer += nChunk;
01593 }
01594
01595 if ( nByte ) return NULL;
01596
01597 if ( nMinSize < 0xFFFFFFFF )
01598 {
01599 if ( nBuffer < nMinSize ) return NULL;
01600
01601 BYTE* pBuffer = new BYTE[ nBuffer ];
01602
01603 ReadFile( hFile, pBuffer, nBuffer, &nRead, NULL );
01604
01605 if ( nRead == nBuffer ) return pBuffer;
01606
01607 delete [] pBuffer;
01608 }
01609 else
01610 {
01611 SetFilePointer( hFile, nBuffer, NULL, FILE_CURRENT );
01612 nBuffer = nSample;
01613 return (BYTE*)TRUE;
01614 }
01615
01616 return NULL;
01617 }
01618
01619 BOOL CLibraryBuilderInternals::ReadOGGString(BYTE*& pOGG, DWORD& nOGG, CString& str)
01620 {
01621 if ( nOGG < 4 ) return FALSE;
01622
01623 DWORD nLen = *(DWORD*)pOGG;
01624 pOGG += 4; nOGG -= 4;
01625
01626 if ( nOGG < nLen ) return FALSE;
01627
01628 LPTSTR pszOut = str.GetBuffer( nLen + 1 );
01629 for ( ; nLen ; nLen--, nOGG-- ) *pszOut++ = (TCHAR)*pOGG++;
01630 *pszOut++ = 0;
01631 str.ReleaseBuffer();
01632
01633 return TRUE;
01634 }
01635
01637
01638
01639 BOOL CLibraryBuilderInternals::ReadAPE( HANDLE hFile)
01640 {
01641 if ( GetFileSize( hFile, NULL ) < sizeof(APE_HEADER) ) return SubmitCorrupted();
01642 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01643
01644 APE_HEADER pAPE;
01645 DWORD nRead;
01646
01647 ReadFile( hFile, &pAPE, sizeof(pAPE), &nRead, NULL );
01648 if ( nRead != sizeof(pAPE) ) return SubmitCorrupted();
01649 if ( pAPE.cID[0] != 'M' || pAPE.cID[1] != 'A' || pAPE.cID[2] != 'C' ) return SubmitCorrupted();
01650 if ( pAPE.nSampleRate == 0 ) return SubmitCorrupted();
01651
01652 DWORD nBlocksPerFrame = ( pAPE.nVersion >= 3900 || ( pAPE.nVersion >= 3800 &&
01653 pAPE.nCompressionLevel == 4000 ) ) ? 73728 : 9216;
01654
01655 DWORD nBlocks = ( pAPE.nTotalFrames - 1 ) * nBlocksPerFrame + pAPE.nFinalFrameBlocks;
01656 DWORD nSamples = nBlocks * pAPE.nChannels;
01657
01658 if ( pAPE.nFormatFlags & 8 )
01659 nSamples *= 3;
01660 else if ( ( pAPE.nFormatFlags & 1 ) == 0 )
01661 nSamples *= 2;
01662
01663 DWORD nDuration = nSamples / pAPE.nSampleRate;
01664
01665 CXMLElement* pXML = new CXMLElement( NULL, _T("audio") );
01666 CString strItem;
01667
01668 strItem.Format( _T("%lu"), nDuration );
01669 pXML->AddAttribute( _T("seconds"), strItem );
01670
01671 strItem.Format( _T("%lu"), pAPE.nSampleRate );
01672 pXML->AddAttribute( _T("sampleRate"), strItem );
01673
01674 if ( ReadID3v1( hFile, pXML ) )
01675 {
01676 return SubmitMetadata( CSchema::uriAudio, pXML );
01677 }
01678
01679 if ( GetFileSize( hFile, NULL ) < sizeof(APE_HEADER) + sizeof(APE_TAG_FOOTER) )
01680 {
01681 return SubmitMetadata( CSchema::uriAudio, pXML );
01682 }
01683
01684 APE_TAG_FOOTER pFooter;
01685
01686 SetFilePointer( hFile, -(LONG)sizeof(pFooter), NULL, FILE_END );
01687 ReadFile( hFile, &pFooter, sizeof(pFooter), &nRead, NULL );
01688
01689 if ( nRead != sizeof(pFooter) || strncmp( pFooter.cID, "APETAGEX", 8 ) ||
01690 (DWORD)pFooter.nFields > 16 ||
01691 ( pFooter.nVersion != 1000 && pFooter.nVersion != 2000 ) )
01692 {
01693 return SubmitMetadata( CSchema::uriAudio, pXML );
01694 }
01695
01696 SetFilePointer( hFile, -(LONG)pFooter.nSize, NULL, FILE_END );
01697
01698 for ( int nTag = 0 ; nTag < pFooter.nFields ; nTag++ )
01699 {
01700 DWORD nLength, nFlags;
01701
01702 ReadFile( hFile, &nLength, 4, &nRead, NULL );
01703 if ( nRead != 4 || nLength > 1024 ) break;
01704 ReadFile( hFile, &nFlags, 4, &nRead, NULL );
01705 if ( nRead != 4 ) break;
01706
01707 CString strKey, strValue;
01708
01709 while ( strKey.GetLength() < 64 )
01710 {
01711 BYTE nChar;
01712 ReadFile( hFile, &nChar, 1, &nRead, NULL );
01713 if ( nRead != 1 || nChar == 0 ) break;
01714 strKey += (TCHAR)nChar;
01715 }
01716
01717 if ( nRead != 1 || strKey.GetLength() >= 64 ) break;
01718
01719 LPSTR pszInput = new CHAR[ nLength ];
01720 ReadFile( hFile, pszInput, nLength, &nRead, NULL );
01721 if ( nLength != nRead ) break;
01722
01723 int nWide = MultiByteToWideChar( CP_UTF8, 0, pszInput, nLength, NULL, 0 );
01724 LPWSTR pszWide = new WCHAR[ nWide + 1 ];
01725 MultiByteToWideChar( CP_UTF8, 0, pszInput, nLength, pszWide, nWide );
01726 pszWide[ nWide ] = 0;
01727 strValue = pszWide;
01728
01729 delete [] pszWide;
01730 delete [] pszInput;
01731
01732 strKey.TrimLeft(); strKey.TrimRight();
01733 strValue.TrimLeft(); strValue.TrimRight();
01734
01735 if ( strKey.GetLength() && strValue.GetLength() )
01736 {
01737 CharLower( strKey.GetBuffer() );
01738 strKey.ReleaseBuffer();
01739
01740 if ( strKey == _T("title") )
01741 {
01742 pXML->AddAttribute( _T("title"), strValue );
01743 }
01744 else if ( strKey == _T("artist") )
01745 {
01746 pXML->AddAttribute( _T("artist"), strValue );
01747 }
01748 else if ( strKey == _T("album") )
01749 {
01750 pXML->AddAttribute( _T("album"), strValue );
01751 }
01752 else if ( strKey == _T("comment") )
01753 {
01754 pXML->AddAttribute( _T("description"), strValue );
01755 }
01756 else if ( strKey == _T("year") )
01757 {
01758 pXML->AddAttribute( _T("year"), strValue );
01759 }
01760 else if ( strKey == _T("track") )
01761 {
01762 pXML->AddAttribute( _T("track"), strValue );
01763 }
01764 else if ( strKey == _T("genre") )
01765 {
01766 pXML->AddAttribute( _T("genre"), strValue );
01767 }
01768 else if ( strKey.Find( _T(" url") ) > 0 )
01769 {
01770 pXML->AddAttribute( _T("link"), strValue );
01771 }
01772 }
01773 }
01774
01775 return SubmitMetadata( CSchema::uriAudio, pXML );
01776 }
01777
01779
01780
01781 BOOL CLibraryBuilderInternals::ReadAVI( HANDLE hFile)
01782 {
01783 if ( GetFileSize( hFile, NULL ) < sizeof(AVI_HEADER) + 16 ) return SubmitCorrupted();
01784 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01785
01786 CHAR szID[5] = { 0, 0, 0, 0, 0 };
01787 DWORD nRead;
01788
01789 ReadFile( hFile, szID, 4, &nRead, NULL );
01790 if ( nRead != 4 || strncmp( szID, "RIFF", 4 ) ) return SubmitCorrupted();
01791 ReadFile( hFile, szID, 4, &nRead, NULL );
01792 if ( nRead != 4 ) return FALSE;
01793 ReadFile( hFile, szID, 4, &nRead, NULL );
01794 if ( nRead != 4 || strncmp( szID, "AVI ", 4 ) ) return SubmitCorrupted();
01795 ReadFile( hFile, szID, 4, &nRead, NULL );
01796 if ( nRead != 4 || strncmp( szID, "LIST", 4 ) ) return FALSE;
01797 ReadFile( hFile, szID, 4, &nRead, NULL );
01798 if ( nRead != 4 ) return FALSE;
01799 ReadFile( hFile, szID, 4, &nRead, NULL );
01800 if ( nRead != 4 || strncmp( szID, "hdrl", 4 ) ) return FALSE;
01801 ReadFile( hFile, szID, 4, &nRead, NULL );
01802 if ( nRead != 4 || strncmp( szID, "avih", 4 ) ) return FALSE;
01803 ReadFile( hFile, szID, 4, &nRead, NULL );
01804 if ( nRead != 4 ) return FALSE;
01805
01806 AVI_HEADER pHeader;
01807 ReadFile( hFile, &pHeader, sizeof(pHeader), &nRead, NULL );
01808 if ( nRead != sizeof(pHeader) ) return FALSE;
01809
01810 ReadFile( hFile, szID, 4, &nRead, NULL );
01811 if ( nRead != 4 || strncmp( szID, "LIST", 4 ) ) return FALSE;
01812 ReadFile( hFile, szID, 4, &nRead, NULL );
01813 if ( nRead != 4 ) return FALSE;
01814 ReadFile( hFile, szID, 4, &nRead, NULL );
01815 if ( nRead != 4 || strncmp( szID, "strl", 4 ) ) return FALSE;
01816 ReadFile( hFile, szID, 4, &nRead, NULL );
01817 if ( nRead != 4 || strncmp( szID, "strh", 4 ) ) return FALSE;
01818 ReadFile( hFile, szID, 4, &nRead, NULL );
01819 if ( nRead != 4 ) return FALSE;
01820 ReadFile( hFile, szID, 4, &nRead, NULL );
01821 if ( nRead != 4 || strncmp( szID, "vids", 4 ) ) return FALSE;
01822 ReadFile( hFile, szID, 4, &nRead, NULL );
01823 if ( nRead != 4 ) return FALSE;
01824
01825 CXMLElement* pXML = new CXMLElement( NULL, _T("video") );
01826 CString strItem;
01827
01828 double nTime = (double)pHeader.dwMicroSecPerFrame / 1000000.0f;
01829 nTime *= (double)pHeader.dwTotalFrames;
01830 nTime /= 60.0f;
01831
01832 double nRate = 1000000.0f / (double)pHeader.dwMicroSecPerFrame;
01833
01834 strItem.Format( _T("%lu"), pHeader.dwWidth );
01835 pXML->AddAttribute( _T("width"), strItem );
01836 strItem.Format( _T("%lu"), pHeader.dwHeight );
01837 pXML->AddAttribute( _T("height"), strItem );
01838 strItem.Format( _T("%.3f"), nTime );
01839 pXML->AddAttribute( _T("minutes"), strItem );
01840 strItem.Format( _T("%.2f"), nRate );
01841 pXML->AddAttribute( _T("frameRate"), strItem );
01842 pXML->AddAttribute( _T("codec"), CString( szID ) );
01843
01844 return SubmitMetadata( CSchema::uriVideo, pXML );
01845 }
01846
01848
01849
01850 BOOL CLibraryBuilderInternals::ReadPDF( HANDLE hFile, LPCTSTR pszPath)
01851 {
01852 DWORD nOffset, nCount, nPages, nInfo;
01853 CString strLine, strSeek;
01854
01855 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
01856 if ( ReadLine( hFile ).Find( _T("%PDF") ) != 0 ) return FALSE;
01857
01858 SetFilePointer( hFile, -1, NULL, FILE_END );
01859 strLine = ReadLineReverse( hFile );
01860 if ( strLine.IsEmpty() ) strLine = ReadLineReverse( hFile );
01861 if ( strLine != _T("%%EOF") ) return FALSE;
01862
01863 strLine = ReadLineReverse( hFile );
01864 if ( ReadLineReverse( hFile ) != _T("startxref") ) return FALSE;
01865
01866 if ( _stscanf( strLine, _T("%lu"), &nOffset ) != 1 ) return FALSE;
01867 if ( SetFilePointer( hFile, nOffset, NULL, FILE_BEGIN ) != nOffset ) return FALSE;
01868
01869 if ( ReadLine( hFile ) != _T("xref") ) return FALSE;
01870 strLine = ReadLine( hFile );
01871 if ( _stscanf( strLine, _T("%lu %lu"), &nOffset, &nCount ) != 2 ) return FALSE;
01872 if ( nCount > 4096 ) return FALSE;
01873
01874 DWORD* pOffset = new DWORD[ nCount ];
01875 ZeroMemory( pOffset, sizeof(DWORD) * nCount );
01876
01877 for ( nOffset = 0 ; nOffset < nCount ; nOffset++ )
01878 {
01879 strLine = ReadLine( hFile );
01880 strLine.TrimLeft();
01881 strLine.TrimRight();
01882
01883 if ( strLine.GetLength() != 18 || strLine.GetAt( 10 ) != ' ' )
01884 {
01885 delete [] pOffset;
01886 return FALSE;
01887 }
01888
01889 if ( strLine.GetAt( 17 ) == 'n' )
01890 {
01891 LPCTSTR pszInt = strLine;
01892 for ( ; *pszInt == '0' ; pszInt++ );
01893
01894 if ( *pszInt != 0 )
01895 {
01896 _stscanf( pszInt, _T("%lu"), &pOffset[ nOffset ] );
01897 }
01898 }
01899 }
01900
01901 if ( ReadLine( hFile ) != _T("trailer") )
01902 {
01903 delete [] pOffset;
01904 return FALSE;
01905 }
01906 if ( ReadLine( hFile ) != _T("<<") )
01907 {
01908 delete [] pOffset;
01909 return FALSE;
01910 }
01911
01912 for ( nOffset = 0 ; ; )
01913 {
01914 strLine = ReadLine( hFile );
01915 if ( strLine.IsEmpty() || strLine == _T(">>") ) break;
01916
01917 if ( _tcsnicmp( strLine, _T("/Info "), 6 ) == 0 )
01918 {
01919 _stscanf( strLine.Mid( 6 ), _T("%lu"), &nOffset );
01920 break;
01921 }
01922 }
01923
01924 if ( nOffset == 0 )
01925 {
01926 delete [] pOffset;
01927 return FALSE;
01928 }
01929
01930 strSeek.Format( _T("%lu 0 obj"), nOffset );
01931 nPages = nInfo = 0;
01932
01933 for ( nOffset = 0 ; nOffset < nCount ; nOffset++ )
01934 {
01935 if ( pOffset[ nOffset ] == 0 ) continue;
01936 SetFilePointer( hFile, pOffset[ nOffset ], NULL, FILE_BEGIN );
01937
01938 strLine = ReadLine( hFile );
01939 if ( strLine.Find( _T("obj") ) < 0 ) break;
01940
01941 if ( strLine == strSeek )
01942 {
01943 nInfo = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );
01944 }
01945 else if ( ReadLine( hFile ) == _T("<<") )
01946 {
01947 if ( ReadLine( hFile ) == _T("/Type /Page") ) nPages++;
01948 }
01949 }
01950
01951 delete [] pOffset;
01952
01953 if ( nInfo == 0 ) return FALSE;
01954 SetFilePointer( hFile, nInfo, NULL, FILE_BEGIN );
01955
01956 if ( ReadLine( hFile ) != _T("<<") ) return FALSE;
01957
01958 BOOL bBook = ( _tcsistr( pszPath, _T("book") ) != NULL );
01959 if ( ! bBook ) return FALSE;
01960
01961 CXMLElement* pXML = new CXMLElement( NULL, bBook ? _T("book") : _T("document") );
01962
01963 if ( LPCTSTR pszName = _tcsrchr( pszPath, '\\' ) )
01964 {
01965 pszName++;
01966
01967 if ( _tcsnicmp( pszName, _T("ebook - "), 8 ) == 0 )
01968 {
01969 strLine = pszName + 8;
01970 strLine = strLine.SpanExcluding( _T(".") );
01971 strLine.TrimLeft();
01972 strLine.TrimRight();
01973 pXML->AddAttribute( _T("title"), strLine );
01974 }
01975 else if ( _tcsnicmp( pszName, _T("(ebook"), 6 ) == 0 )
01976 {
01977 if ( pszName = _tcschr( pszName, ')' ) )
01978 {
01979 if ( _tcsncmp( pszName, _T(") - "), 4 ) == 0 )
01980 strLine = pszName + 4;
01981 else
01982 strLine = pszName + 1;
01983 strLine = strLine.SpanExcluding( _T(".") );
01984 strLine.TrimLeft();
01985 strLine.TrimRight();
01986 pXML->AddAttribute( _T("title"), strLine );
01987 }
01988 }
01989 }
01990
01991 if ( nPages > 0 )
01992 {
01993 strLine.Format( _T("%lu"), nPages );
01994 pXML->AddAttribute( _T("pages"), strLine );
01995 }
01996
01997 while ( TRUE )
01998 {
01999 strLine = ReadLine( hFile );
02000 if ( strLine.IsEmpty() || strLine.GetAt( 0 ) != '/' ) break;
02001
02002 CString strKey = strLine.SpanExcluding( _T(" \t") );
02003 strLine = strLine.Mid( strKey.GetLength() );
02004 strLine.TrimLeft();
02005 CharLower( strKey.GetBuffer() );
02006 strKey.ReleaseBuffer();
02007
02008 if ( strLine.GetLength() >= 2 &&
02009 strLine.GetAt( 0 ) == '(' &&
02010 strLine.GetAt( strLine.GetLength() - 1 ) == ')' )
02011 {
02012 strLine = strLine.Mid( 1, strLine.GetLength() - 2 );
02013 }
02014
02015 if ( strLine.IsEmpty() ) continue;
02016
02017 if ( ( strLine.GetLength() & 1 ) == 0 && strLine.GetAt( 0 ) == '<' )
02018 {
02019 CString strTemp;
02020
02021 for ( int nHex = 0 ; nHex < strLine.GetLength() / 2 - 1 ; nHex++ )
02022 {
02023 int nChar;
02024 if ( _stscanf( strLine.Mid( nHex + 1, 2 ), _T("%x"), &nChar ) == 1 )
02025 {
02026 strTemp += (TCHAR)nChar;
02027 }
02028 }
02029
02030 strLine = strTemp;
02031 if ( strLine.IsEmpty() ) continue;
02032 }
02033
02034 if ( strKey == _T("/title") )
02035 {
02036 pXML->AddAttribute( _T("title"), strLine );
02037 }
02038 else if ( strKey == _T("/author") )
02039 {
02040 pXML->AddAttribute( _T("author"), strLine );
02041 }
02042 else if ( strKey == _T("/subject") )
02043 {
02044 pXML->AddAttribute( _T("subject"), strLine );
02045 }
02046 else if ( strKey == _T("/keywords") )
02047 {
02048 pXML->AddAttribute( _T("keywords"), strLine );
02049 }
02050 }
02051
02052
02053 if ( bBook )
02054 {
02055 pXML->AddAttribute( _T("format"), _T("PDF") );
02056 pXML->AddAttribute( _T("back"), _T("Digital") );
02057 return SubmitMetadata( CSchema::uriBook, pXML );
02058 }
02059 else
02060 {
02061 pXML->AddAttribute( _T("format"), _T("Adobe Acrobat PDF") );
02062
02063
02064
02065 return SubmitMetadata( CSchema::uriDocument, pXML );
02066 }
02067 }
02068
02069 CString CLibraryBuilderInternals::ReadLine(HANDLE hFile)
02070 {
02071 DWORD nRead, nLength;
02072 TCHAR cChar;
02073 CString str;
02074
02075 ZeroMemory( &cChar, sizeof(cChar) );
02076 for ( nLength = 0 ; ReadFile( hFile, &cChar, 1, &nRead, NULL ) && nRead == 1 && nLength++ < 4096 ; )
02077 {
02078 if ( cChar == '\r' ) break;
02079 if ( cChar != '\n' ) str += cChar;
02080 }
02081
02082 str.TrimLeft();
02083 str.TrimRight();
02084
02085 return str;
02086 }
02087
02088 CString CLibraryBuilderInternals::ReadLineReverse(HANDLE hFile)
02089 {
02090 DWORD nRead, nLength;
02091 TCHAR cChar;
02092 CString str;
02093
02094 ZeroMemory( &cChar, sizeof(cChar) );
02095 for ( nLength = 0 ; ReadFile( hFile, &cChar, 1, &nRead, NULL ) && nRead == 1 && nLength++ < 4096 ; )
02096 {
02097 if ( SetFilePointer( hFile, -2, NULL, FILE_CURRENT ) == 0 ) break;
02098 if ( cChar == '\r' ) break;
02099 if ( cChar != '\n' ) str = cChar + str;
02100 }
02101
02102 str.TrimLeft();
02103 str.TrimRight();
02104
02105 return str;
02106 }
02107
02109
02110
02111 BOOL CLibraryBuilderInternals::ReadCollection( HANDLE hFile, SHA1* pSHA1)
02112 {
02113 CCollectionFile pCollection;
02114 if ( ! pCollection.Attach( hFile ) ) return FALSE;
02115
02116 LibraryFolders.MountCollection( pSHA1, &pCollection );
02117
02118 if ( CXMLElement* pMetadata = pCollection.GetMetadata() )
02119 {
02120 pMetadata = pMetadata->GetFirstElement()->Clone();
02121 return SubmitMetadata( pCollection.GetThisURI(), pMetadata );
02122 }
02123
02124 return TRUE;
02125 }
02126
02128
02129
02130 BOOL CLibraryBuilderInternals::ReadCHM(HANDLE hFile, LPCTSTR pszPath)
02131 {
02132 CHAR szMagic[4];
02133 DWORD nVersion, nIHDRSize, nLCID, nRead, nPos, nComprVersion;
02134 QWORD nContentOffset;
02135 const DWORD MAX_LENGTH_ALLOWED = 8192;
02136
02137 SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
02138 ReadFile( hFile, szMagic, 4, &nRead, NULL );
02139
02140 if ( nRead != 4 || strncmp( szMagic, "ITSF", 4 ) )
02141 return SubmitCorrupted();
02142 if ( GetFileSize( hFile, NULL ) < 510 ) return SubmitCorrupted();
02143
02144
02145 ReadFile( hFile, &nVersion, sizeof(nVersion), &nRead, NULL );
02146 if ( nRead != sizeof(nVersion) || nVersion < 3 )
02147 return FALSE;
02148
02149
02150 ReadFile( hFile, &nIHDRSize, sizeof(nIHDRSize), &nRead, NULL );
02151 if ( nRead != sizeof(nIHDRSize) || nIHDRSize == 0 ) return SubmitCorrupted();
02152 nPos = nIHDRSize - sizeof(nContentOffset);
02153
02154
02155
02156 SetFilePointer( hFile, 20, NULL, FILE_BEGIN );
02157 ReadFile( hFile, &nLCID, sizeof(nLCID), &nRead, NULL );
02158 if ( nRead != sizeof(nLCID) ) return SubmitCorrupted();
02159 if ( !IsValidLocale( nLCID, LCID_SUPPORTED ) ) nLCID = 1033;
02160
02161
02162 SetFilePointer( hFile, nPos, NULL, FILE_BEGIN );
02163 ReadFile( hFile, &nContentOffset, sizeof(nContentOffset), &nRead, NULL );
02164 if ( nRead != sizeof(nContentOffset) ) return SubmitCorrupted();
02165 if ( nContentOffset == 0 ) return FALSE;
02166
02167
02168
02169 nContentOffset += 110;
02170 DWORD nError = NO_ERROR;
02171 DWORD nSizeLow = (DWORD)( nContentOffset & 0xFFFFFFFF );
02172 DWORD nSizeHigh = (DWORD)( nContentOffset >> 32 );
02173
02174 nSizeLow = SetFilePointer( hFile, nSizeLow, (long*)&nSizeHigh, FILE_BEGIN );
02175 if ( nSizeLow == INVALID_SET_FILE_POINTER &&
02176 ( nError = GetLastError() ) != NO_ERROR ) return SubmitCorrupted();
02177 ReadFile( hFile, szMagic, 4, &nRead, NULL );
02178 if ( nRead != 4 || strncmp( szMagic, "LZXC", 4 ) )
02179 return FALSE;
02180 ReadFile( hFile, &nComprVersion, sizeof(nComprVersion), &nRead, NULL );
02181 if ( nRead != sizeof(nComprVersion) || nComprVersion != 2 )
02182 return FALSE;
02183
02184
02185 CHAR szByte[1];
02186 CHAR* szFragment = new CHAR[10];
02187 BOOL bCorrupted = FALSE;
02188 BOOL bHFound = FALSE;
02189 int nFragmentPos = 0;
02190
02191 ZeroMemory( szFragment, sizeof(CHAR) * 10 );
02192
02193 for ( nPos = 0; ReadFile( hFile, &szByte, 1, &nRead, NULL ) && nPos++ < MAX_LENGTH_ALLOWED ; )
02194 {
02195 if ( nRead != 1 )
02196 {
02197 bCorrupted = TRUE;
02198 break;
02199 }
02200 if ( szByte[0] == 'H' )
02201 {
02202 nFragmentPos = 0;
02203 szFragment[0] = 'H';
02204 bHFound = TRUE;
02205 }
02206 else
02207 {
02208 nFragmentPos++;
02209 if ( bHFound )
02210 {
02211 if ( IsCharacter( szByte[0] ) )
02212 szFragment[ nFragmentPos ] = szByte[0];
02213 else
02214 szFragment[ nFragmentPos ] = ' ';
02215 }
02216 }
02217 if ( nFragmentPos == 9 )
02218 {
02219 if ( !strncmp( szFragment, "HA Version", 10 ) )
02220 {
02221
02222
02223 nPos = SetFilePointer( hFile, 0, NULL, FILE_CURRENT ) - 15;
02224 break;
02225 }
02226 else
02227 {
02228 nFragmentPos = 0;
02229 bHFound = FALSE;
02230 }
02231 }
02232 }
02233 if ( bCorrupted )
02234 {
02235 delete [] szFragment;
02236 return SubmitCorrupted();
02237 }
02238 if ( strncmp( szFragment, "HA Version", 10 ) && nPos == MAX_LENGTH_ALLOWED + 1 )
02239 {
02240 delete [] szFragment;
02241 return FALSE;
02242 }
02243 delete [] szFragment;
02244
02245
02246 CString strLine;
02247 BOOL bBook = ( _tcsistr( pszPath, _T("book") ) != NULL );
02248
02249 CXMLElement* pXML = new CXMLElement( NULL, bBook ? _T("book") : _T("wordprocessing") );
02250
02251 if ( LPCTSTR pszName = _tcsrchr( pszPath, '\\' ) )
02252 {
02253 pszName++;
02254
02255 if ( _tcsnicmp( pszName, _T("ebook - "), 8 ) == 0 )
02256 {
02257 strLine = pszName + 8;
02258 strLine = strLine.SpanExcluding( _T(".") );
02259 strLine.TrimLeft();
02260 strLine.TrimRight();
02261 pXML->AddAttribute( _T("title"), strLine );
02262 }
02263 else if ( _tcsnicmp( pszName, _T("(ebook"), 6 ) == 0 )
02264 {
02265 if ( pszName = _tcschr( pszName, ')' ) )
02266 {
02267 if ( _tcsncmp( pszName, _T(") - "), 4 ) == 0 )
02268 strLine = pszName + 4;
02269 else
02270 strLine = pszName + 1;
02271 strLine = strLine.SpanExcluding( _T(".") );
02272 strLine.TrimLeft();
02273 strLine.TrimRight();
02274 pXML->AddAttribute( _T("title"), strLine );
02275 }
02276 }
02277 }
02278
02279
02280 WORD nData;
02281 CHARSETINFO csInfo;
02282 CString strTemp;
02283 TCHAR *pszBuffer = NULL;
02284 UINT nCodePage = CP_ACP;
02285 DWORD nCwc;
02286 UINT charSet = DEFAULT_CHARSET;
02287 BOOL bHasTitle = FALSE;
02288
02289
02290 DWORD nLength = GetLocaleInfo( nLCID, LOCALE_IDEFAULTANSICODEPAGE, NULL, 0 );
02291 pszBuffer = (TCHAR*)LocalAlloc( LPTR, ( nLength + 1 ) * sizeof(TCHAR) );
02292 nCwc = GetLocaleInfo( nLCID, LOCALE_IDEFAULTANSICODEPAGE, pszBuffer, nLength );
02293 if ( nCwc > 0 )
02294 {
02295 CString strTemp = pszBuffer;
02296 strTemp = strTemp.Left( nCwc - 1 );
02297 _stscanf( strTemp, _T("%lu"), &charSet );
02298 if ( TranslateCharsetInfo( (LPDWORD)charSet, &csInfo, TCI_SRCCODEPAGE ) )
02299 nCodePage = csInfo.ciACP;
02300 }
02301 SetFilePointer( hFile, nPos, NULL, FILE_BEGIN );
02302
02303 for ( int nCount = 1 ; nCount < 5 && !bCorrupted ; nCount++ )
02304 {
02305
02306 ReadFile( hFile, &nData, sizeof(nData), &nRead, NULL );
02307 if ( nRead != sizeof(nData) ) bCorrupted = TRUE;
02308
02309
02310 ReadFile( hFile, &nData, sizeof(nData), &nRead, NULL );
02311 if ( nRead != sizeof(nData) ) bCorrupted = TRUE;
02312 if ( nData == 0 ) break;
02313 if ( bCorrupted ) nData = 1;
02314
02315 CHAR* szMetadata = new CHAR[ nData ];
02316 ReadFile( hFile, szMetadata, nData, &nRead, NULL );
02317 if ( nRead != nData ) bCorrupted = TRUE;
02318
02319 if ( nCount == 2 )
02320 {
02321 delete [] szMetadata;
02322 continue;
02323 }
02324
02325
02326 int nWide = MultiByteToWideChar( nCodePage, 0, szMetadata, nData, NULL, 0 );
02327 LPWSTR pszOutput = strLine.GetBuffer( nWide + 1 );
02328 MultiByteToWideChar( nCodePage, 0, szMetadata, nData, pszOutput, nWide );
02329 pszOutput[ nWide ] = 0;
02330 strLine.ReleaseBuffer();
02331 strLine.Trim();
02332
02333 int nPos;
02334
02335 switch ( nCount )
02336 {
02337 case 1:
02338 nPos = strLine.ReverseFind( ' ' );
02339 strLine = strLine.Mid( nPos + 1 );
02340 if ( !bBook ) pXML->AddAttribute( _T("formatVersion"), strLine );
02341 break;
02342 case 2:
02343 break;
02344 case 3:
02345 CharLower( strLine.GetBuffer() );
02346 strLine.ReleaseBuffer();
02347 if ( strLine.Left( 7 ) == _T("ms-its:") )
02348 {
02349 nPos = strLine.Find( _T("::"), 7 );
02350 strTemp = _tcsrchr( pszPath, '\\' );
02351 strTemp = strTemp.Mid( 1 );
02352 CharLower( strTemp.GetBuffer() );
02353 strTemp.ReleaseBuffer();
02354 if ( strLine.Mid( 7, nPos - 7 ).Trim() != strTemp )
02355 bCorrupted = TRUE;
02356 }
02357 else if ( strLine.Left( 7 ) == _T("http://") )
02358 bCorrupted = TRUE;
02359 break;
02360 case 4:
02361 if ( strLine.IsEmpty() ) break;
02362 nPos = strLine.Find( ',' );
02363 strTemp = strLine.Left( nPos );
02364 CharLower( strTemp.GetBuffer() );
02365 strTemp.ReleaseBuffer();
02366 if ( strLine.CompareNoCase( _T("htmlhelp") ) != 0 &&
02367 strTemp != _T("arial") && strTemp != _T("tahoma") &&
02368 strTemp != _T("times new roman") && strTemp != _T("verdana") &&
02369 strLine.CompareNoCase( _T("windows") ) != 0 )
02370 {
02371 bHasTitle = TRUE;
02372 nPos = strLine.ReverseFind( '\\' );
02373 strLine = strLine.Mid( nPos + 1 );
02374 pXML->AddAttribute( _T("title"), strLine );
02375 }
02376 break;
02377 }
02378 delete [] szMetadata;
02379 if ( bCorrupted )
02380 {
02381 delete pXML;
02382 return SubmitCorrupted();
02383 }
02384 }
02385
02386 if ( !bHasTitle )
02387 {
02388 delete pXML;
02389 return FALSE;
02390 }
02391
02392 pXML->AddAttribute( _T("format"), _T("Compiled HTML Help") );
02393 if ( bBook )
02394 {
02395 pXML->AddAttribute( _T("back"), _T("Digital") );
02396 strTemp = CSchema::uriBook;
02397 }
02398 else
02399 strTemp = CSchema::uriDocument;
02400
02401 return SubmitMetadata( strTemp, pXML );
02402 }