void TagTree::addOffset(LFA_FileRef file) { // 3 points for doing it here: shortness, convenience, 64bit forks needed #if WIN_ENV addComment( "offset: 0x%I64X", LFA_Tell( file ) ); #else addComment( "offset: 0x%ll.16X", LFA_Tell( file ) ); #endif }
//*** kind of a hack, TOTEST bool LFA_isEof( LFA_FileRef file ) { #if XMP_MacBuild long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast. XMP_Int64 position, length; OSErr err = FSGetForkPosition( refNum, &position ); if ( err != noErr ) LFA_Throw ( "LFA_isEOF:FSGetForkPosition failure", kLFAErr_ExternalFailure ); err = FSGetForkSize ( refNum, &length ); if ( err != noErr ) LFA_Throw ( "LFA_isEof: FSGetForkSize failure", kLFAErr_ExternalFailure ); return position==length; #endif #if XMP_WinBuild HANDLE handle = (HANDLE)file; XMP_Int64 filepos = LFA_Tell(file); DWORD lowWord, highWord; lowWord = GetFileSize(handle, &highWord); XMP_Int64 filesize = ( ((XMP_Int64)highWord) << 32 | lowWord ); return filesize == filepos; #endif #if XMP_UNIXBuild || XMP_iOSBuild int descr = (int)file; struct stat info; if (fstat(descr,&info) == -1) LFA_Throw ( "LFA_isEof: fstat failed.", kLFAErr_ExternalFailure ); return LFA_Tell(file) == info.st_size; #endif }
// ================================================================================================= // 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