bool MP3_CheckFormat ( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* file, XMPFiles * parent ) { IgnoreParam(filePath); IgnoreParam(parent); //supress warnings XMP_Assert ( format == kXMP_MP3File ); //standard assert if ( file->Length() < 10 ) return false; file ->Rewind(); XMP_Uns8 header[3]; file->ReadAll ( header, 3 ); if ( ! CheckBytes( &header[0], "ID3", 3 ) ) return (parent->format == kXMP_MP3File); XMP_Uns8 major = XIO::ReadUns8( file ); XMP_Uns8 minor = XIO::ReadUns8( file ); if ( (major < 2) || (major > 4) || (minor == 0xFF) ) return false; XMP_Uns8 flags = XIO::ReadUns8 ( file ); //TODO if ( flags & 0x10 ) XMP_Throw ( "no support for MP3 with footer", kXMPErr_Unimplemented ); if ( flags & 0x80 ) return false; //no support for unsynchronized MP3 (as before, also see [1219125]) if ( flags & 0x0F ) XMP_Throw ( "illegal header lower bits", kXMPErr_Unimplemented ); XMP_Uns32 size = XIO::ReadUns32_BE ( file ); if ( (size & 0x80808080) != 0 ) return false; //if any bit survives -> not a valid synchsafe 32 bit integer return true; } // MP3_CheckFormat
bool ID3v2Frame::advancePastCOMMDescriptor ( XMP_Int32& pos ) { if ( (this->contentSize - pos) <= 3 ) return false; // silent error, no room left behing language tag if ( ! CheckBytes ( &this->content[pos], "eng", 3 ) ) return false; // not an error, but leave all non-eng tags alone... pos += 3; // skip lang tag if ( pos >= this->contentSize ) return false; // silent error while ( pos < this->contentSize ) { if ( this->content[pos++] == 0x00 ) break; } if ( (pos < this->contentSize) && (this->content[pos] == 0x00) ) pos++; if ( (pos == 5) && (this->contentSize == 6) && (GetUns16BE(&this->content[4]) == 0x0031) ) { return false; } if ( pos > 4 ) { std::string descriptor = std::string ( &this->content[4], pos-1 ); if ( 0 == descriptor.substr(0,4).compare( "iTun" ) ) { // begins with engiTun ? return false; // leave alone, then } } return true; //o.k., descriptor skipped, time for the real thing. } // ID3v2Frame::advancePastCOMMDescriptor
// ================================================================================================= // MP3_CheckFormat // =============== // For MP3 we check parts .... See the MP3 spec for offset info. bool MP3_CheckFormat ( XMP_FileFormat format, XMP_StringPtr filePath, LFA_FileRef file, XMPFiles * parent ) { IgnoreParam(filePath); IgnoreParam(parent); //supress warnings XMP_Assert ( format == kXMP_MP3File ); //standard assert LFA_Rewind( file ); XMP_Uns8 header[3]; LFA_Read( file, header, 3, true ); if ( !CheckBytes( &header[0], "ID3", 3 )) return (parent->format == kXMP_MP3File); // No ID3 signature -> depend on first call hint. XMP_Uns8 major = LFA_ReadUns8( file ); XMP_Uns8 minor = LFA_ReadUns8( file ); if ( (major<3 || major>4) || (minor == 0xFF) ) return false; // only support IDv2.3 and ID3v2.4, minor must not be 0xFF XMP_Uns8 flags = LFA_ReadUns8( file ); //TODO if ( flags & 0x10 ) XMP_Throw("no support for MP3 with footer",kXMPErr_Unimplemented); //no support for MP3 with footer if ( flags & 0x80 ) return false; //no support for unsynchronized MP3 (as before, also see [1219125]) if ( flags & 0x0F ) XMP_Throw("illegal header lower bits",kXMPErr_Unimplemented); XMP_Uns32 size = LFA_ReadUns32_BE( file ); if ( size & 0x80808080 ) return false; //if any bit survives -> not a valid synchsafe 32 bit integer return true; } // MP3_CheckFormat
void FileInfo::CheckFormat ( LFA_FileRef fileRef ) { IOBuffer ioBuf; LFA_Seek ( fileRef, 0, SEEK_SET ); if ( CheckFileSpace ( fileRef, &ioBuf, SWF_SIGNATURE_LEN ) ) { if ( CheckBytes ( ioBuf.ptr, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) { this->compressedFile = false; } else if ( CheckBytes ( ioBuf.ptr, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) { this->compressedFile = true; } LFA_Seek ( fileRef, 4, SEEK_SET ); XMP_Uns8 buffer[4]; LFA_Read ( fileRef, buffer, 4 ); iSize = GetUns32LE ( buffer ); } LFA_Seek ( fileRef, 0, SEEK_SET ); } // FileInfo::CheckFormat
bool GIF_CheckFormat ( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* fileRef, XMPFiles * parent ) { IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent); XMP_Assert ( format == kXMP_GIFFile ); if ( fileRef->Length() < GIF_89_Header_LEN ) return false; XMP_Uns8 buffer[ GIF_89_Header_LEN ]; fileRef->Rewind(); fileRef->Read( buffer, GIF_89_Header_LEN ); if ( !CheckBytes( buffer, GIF_89_Header_DATA, GIF_89_Header_LEN ) ) return false; return true; } // GIF_CheckFormat
bool ID3Header::read ( XMP_IO* file ) { XMP_Assert ( sizeof(fields) == kID3_TagHeaderSize ); file->ReadAll ( this->fields, kID3_TagHeaderSize ); if ( ! CheckBytes ( &this->fields[ID3Header::o_id], "ID3", 3 ) ) { // chuck in default contents: const static char defaultHeader[kID3_TagHeaderSize] = { 'I', 'D', '3', 3, 0, 0, 0, 0, 0, 0 }; memcpy ( this->fields, defaultHeader, kID3_TagHeaderSize ); return false; // no header found (o.k.) thus stick with new, default header constructed above } XMP_Uns8 major = this->fields[o_vMajor]; XMP_Uns8 minor = this->fields[o_vMinor]; XMP_Validate ( ((2 <= major) && (major <= 4)), "Invalid ID3 major version", kXMPErr_BadFileFormat ); return true; }
// ================================================================================================= // MP3_MetaHandler::CacheFileData // ============================== void MP3_MetaHandler::CacheFileData() { //*** abort procedures this->containsXMP = false; //assume no XMP for now LFA_FileRef file = this->parent->fileRef; XMP_PacketInfo &packetInfo = this->packetInfo; LFA_Rewind(file); hasID3Tag = id3Header.read( file ); majorVersion = id3Header.fields[ID3Header::o_version_major]; minorVersion = id3Header.fields[ID3Header::o_version_minor]; hasExtHeader = (0 != ( 0x40 & id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag hasFooter = ( 0 != ( 0x10 & id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag // stored size is w/o initial header (thus adding 10) // + but extended header (if existing) // + padding + frames after unsynchronisation (?) // (if no ID3 tag existing, constructed default correctly sets size to 10.) oldTagSize = 10 + synchToInt32(GetUns32BE( &id3Header.fields[ID3Header::o_size] )); if (hasExtHeader) { extHeaderSize = synchToInt32( LFA_ReadInt32_BE( file)); XMP_Uns8 extHeaderNumFlagBytes = LFA_ReadUns8( file ); // v2.3 doesn't include the size, while v2.4 does if ( majorVersion < 4 ) extHeaderSize += 4; XMP_Validate( extHeaderSize >= 6, "extHeader size too small", kXMPErr_BadFileFormat ); bool ok; LFA_Seek(file, extHeaderSize - 6, SEEK_CUR , &ok); XMP_Assert(ok); } else { extHeaderSize = 0; // := there is no such header. } this->framesVector.clear(); //mac precaution ID3v2Frame* curFrame = 0; // reusable //////////////////////////////////////////////////// // read frames while ( LFA_Tell(file) < oldTagSize ) { curFrame = new ID3v2Frame(); try { XMP_Int64 frameSize = curFrame->read( file, majorVersion ); if (frameSize == 0) // no more frames coming => proceed to padding { delete curFrame; // ..since not becoming part of vector for latter delete. break; // not a throw. There's nothing wrong with padding. } this->containsXMP = true; } catch( XMP_Error e) { delete curFrame; XMP_Throw( e.GetErrMsg(), e.GetID()); // rethrow } // these are both pointer assignments, no (copy) construction // (MemLeak Note: for all things pushed, memory cleanup is taken care of in destructor.) this->framesVector.push_back( curFrame ); //remember XMP-Frame, if it occurs: if ( CheckBytes( &curFrame->fields[ID3v2Frame::o_id], "PRIV", 4 )) if( curFrame->contentSize > 8 ) // to avoid adress violation on very small non-XMP PRIV frames if( CheckBytes( &curFrame->content[0], "XMP\0", 4 )) { // be sure that this is the first packet (all else would be illegal format) XMP_Validate( framesMap[ XMP_FRAME_ID] == 0, "two XMP packets in one file", kXMPErr_BadFileFormat ); //add this to map, needed on reconciliation framesMap[ XMP_FRAME_ID ] = curFrame; this->packetInfo.length = curFrame->contentSize - 4; // content minus "XMP\0" this->packetInfo.offset = ( LFA_Tell(file) - this->packetInfo.length ); this->xmpPacket.erase(); //safety this->xmpPacket.assign( &curFrame->content[4], curFrame->contentSize - 4 ); this->containsXMP = true; // do this last, after all possible failure } // No space for another frame? => assume into ID3v2.4 padding. if ( LFA_Tell(file) + 10 >= oldTagSize ) break; } //////////////////////////////////////////////////// // padding oldPadding = oldTagSize - LFA_Tell( file ); oldFramesSize = oldTagSize - 10 - oldPadding; XMP_Validate( oldPadding >= 0, "illegal oldTagSize or padding value", kXMPErr_BadFileFormat ); for ( XMP_Int64 i = oldPadding; i > 0;) { if ( i >= 8 ) // worthwhile optimization { if ( LFA_ReadInt64_BE(file) != 0 ) XMP_Throw ( "padding not nulled out.", kXMPErr_BadFileFormat ); i -= 8; continue; } if ( LFA_ReadUns8(file) != 0) XMP_Throw ( "padding(2) not nulled out.", kXMPErr_BadFileFormat ); i--; } //// read ID3v1 tag if ( ! this->containsXMP ) // all else has priority { this->containsXMP = id3v1Tag.read( file, &this->xmpObj ); } } // MP3_MetaHandler::CacheFileData
HRESULT COSPServiceMgr::DoAddSourceFilter(IGraphBuilder* pGb, LPCWSTR aFile, IOSPGraphBuilderCallback* aCallback, LPVOID aPrivate) { if (!aFile) return E_INVALIDARG; URL_COMPONENTS url; memset(&url, 0, sizeof(URL_COMPONENTS)); url.dwStructSize = sizeof(URL_COMPONENTS); url.dwSchemeLength = 1; url.dwUrlPathLength = 1; url.dwExtraInfoLength = 1; if (!InternetCrackUrl(aFile, 0, 0, &url)) { memset(&url, 0, sizeof(URL_COMPONENTS)); url.dwStructSize = sizeof(URL_COMPONENTS); url.nScheme = INTERNET_SCHEME_FILE; url.lpszUrlPath = (LPWSTR)aFile; url.dwUrlPathLength = wcslen(aFile); } HRESULT hRes = VFW_E_UNSUPPORTED_STREAM; CString strScheme(url.lpszScheme, url.dwSchemeLength); CString strExtension = CPathW(CString(url.lpszUrlPath, url.dwUrlPathLength)).GetExtension(); strExtension.Trim(L'.'); if (strScheme.GetLength() > 1 && strScheme.CompareNoCase(L"file") != 0) { } else //local file. { std::map<wstring, std::multimap<long, long, std::greater<long> > >::iterator itr = m_extensionSource.find((LPCTSTR)strExtension); if (itr != m_extensionSource.end()) { std::multimap<long, long, std::greater<long> >::iterator itr2 = itr->second.begin(); for (; itr2 != itr->second.end(); itr2++) { if (SUCCEEDED(hRes = DoAddSourceFilter(pGb, aFile, m_allFilters[itr2->second], aCallback, aPrivate))) { return hRes; } } } HANDLE hFile = ::CreateFile(aFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { return VFW_E_NOT_FOUND; } { vector<SourceFilter*>::iterator itr = m_sourceFilters.begin(); for (; itr != m_sourceFilters.end(); itr++) { if (CheckBytes(*itr, hFile)) { if (SUCCEEDED(hRes = DoAddSourceFilter(pGb, aFile, &(*itr)->filterBase, aCallback, aPrivate))) { CloseHandle(hFile); return hRes; } } } CloseHandle(hFile); } } return hRes; }
void MP3_MetaHandler::CacheFileData() { //*** abort procedures this->containsXMP = false; //assume no XMP for now XMP_IO* file = this->parent->ioRef; XMP_PacketInfo &packetInfo = this->packetInfo; file->Rewind(); this->hasID3Tag = this->id3Header.read( file ); this->majorVersion = this->id3Header.fields[ID3Header::o_vMajor]; this->minorVersion = this->id3Header.fields[ID3Header::o_vMinor]; this->hasExtHeader = (0 != ( 0x40 & this->id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag this->hasFooter = ( 0 != ( 0x10 & this->id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag // stored size is w/o initial header (thus adding 10) // + but extended header (if existing) // + padding + frames after unsynchronisation (?) // (if no ID3 tag existing, constructed default correctly sets size to 10.) this->oldTagSize = ID3Header::kID3_TagHeaderSize + synchToInt32(GetUns32BE( &id3Header.fields[ID3Header::o_size] )); if ( ! hasExtHeader ) { this->extHeaderSize = 0; // := there is no such header. } else { this->extHeaderSize = synchToInt32( XIO::ReadInt32_BE( file)); XMP_Uns8 extHeaderNumFlagBytes = XIO::ReadUns8( file ); // v2.3 doesn't include the size, while v2.4 does if ( this->majorVersion < 4 ) this->extHeaderSize += 4; XMP_Validate( this->extHeaderSize >= 6, "extHeader size too small", kXMPErr_BadFileFormat ); file->Seek ( this->extHeaderSize - 6, kXMP_SeekFromCurrent ); } this->framesVector.clear(); //mac precaution ID3v2Frame* curFrame = 0; // reusable //////////////////////////////////////////////////// // read frames XMP_Uns32 xmpID = XMP_V23_ID; if ( this->majorVersion == 2 ) xmpID = XMP_V22_ID; while ( file->Offset() < this->oldTagSize ) { curFrame = new ID3v2Frame(); try { XMP_Int64 frameSize = curFrame->read ( file, this->majorVersion ); if ( frameSize == 0 ) { delete curFrame; // ..since not becoming part of vector for latter delete. break; // not a throw. There's nothing wrong with padding. } this->containsXMP = true; } catch ( ... ) { delete curFrame; throw; } // these are both pointer assignments, no (copy) construction // (MemLeak Note: for all things pushed, memory cleanup is taken care of in destructor.) this->framesVector.push_back ( curFrame ); //remember XMP-Frame, if it occurs: if ( (curFrame->id ==xmpID) && (curFrame->contentSize > 8) && CheckBytes ( &curFrame->content[0], "XMP\0", 4 ) ) { // be sure that this is the first packet (all else would be illegal format) XMP_Validate ( this->framesMap[xmpID] == 0, "two XMP packets in one file", kXMPErr_BadFileFormat ); //add this to map, needed on reconciliation this->framesMap[xmpID] = curFrame; this->packetInfo.length = curFrame->contentSize - 4; // content minus "XMP\0" this->packetInfo.offset = ( file->Offset() - this->packetInfo.length ); this->xmpPacket.erase(); //safety this->xmpPacket.assign( &curFrame->content[4], curFrame->contentSize - 4 ); this->containsXMP = true; // do this last, after all possible failure } // No space for another frame? => assume into ID3v2.4 padding. XMP_Int64 newPos = file->Offset(); XMP_Int64 spaceLeft = this->oldTagSize - newPos; // Depends on first check below! if ( (newPos > this->oldTagSize) || (spaceLeft < (XMP_Int64)ID3Header::kID3_TagHeaderSize) ) break; } //////////////////////////////////////////////////// // padding this->oldPadding = this->oldTagSize - file->Offset(); this->oldFramesSize = this->oldTagSize - ID3Header::kID3_TagHeaderSize - this->oldPadding; XMP_Validate ( (this->oldPadding >= 0), "illegal oldTagSize or padding value", kXMPErr_BadFileFormat ); for ( XMP_Int64 i = this->oldPadding; i > 0; ) { if ( i >= 8 ) { if ( XIO::ReadInt64_BE(file) != 0 ) XMP_Throw ( "padding not nulled out", kXMPErr_BadFileFormat ); i -= 8; continue; } if ( XIO::ReadUns8(file) != 0) XMP_Throw ( "padding(2) not nulled out", kXMPErr_BadFileFormat ); i--; } //// read ID3v1 tag if ( ! this->containsXMP ) this->containsXMP = id3v1Tag.read ( file, &this->xmpObj ); } // MP3_MetaHandler::CacheFileData