void TIFF_MetaHandler::WriteTempFile ( XMP_IO* tempRef ) { XMP_IO* origRef = this->parent->ioRef; XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; XMP_Int64 fileLen = origRef->Length(); if ( fileLen > 0xFFFFFFFFLL ) { // Check before making a copy of the file. XMP_Throw ( "TIFF fles can't exceed 4GB", kXMPErr_BadTIFF ); } XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( progressTracker != 0 ) progressTracker->BeginWork ( (float)fileLen ); origRef->Rewind ( ); tempRef->Truncate ( 0 ); XIO::Copy ( origRef, tempRef, fileLen, abortProc, abortArg ); try { this->parent->ioRef = tempRef; // ! Make UpdateFile update the temp. this->UpdateFile ( false ); this->parent->ioRef = origRef; } catch ( ... ) { this->parent->ioRef = origRef; throw; } if ( progressTracker != 0 ) progressTracker->WorkComplete(); } // TIFF_MetaHandler::WriteTempFile
void Matroska_MetaHandler::UpdateFile(bool doSafeUpdate) { if (!needsUpdate) return; // If needsUpdate is set then at least the XMP changed. needsUpdate = false; // Make sure only called once. XMP_Assert(!doSafeUpdate); // This should only be called for "unsafe" updates. XMP_Assert(parent && parent->ioRef); XMP_AbortProc abortProc = parent->abortProc; void * abortArg = parent->abortArg; const bool checkAbort = (abortProc != 0); bool localProgressTracking(false); XMP_ProgressTracker* progressTracker = parent->progressTracker; if (progressTracker) { float xmpSize = static_cast<float>(xmpPacket.size()); if (progressTracker->WorkInProgress()) { progressTracker->AddTotalWork(xmpSize); } else { localProgressTracking = true; progressTracker->BeginWork(xmpSize); } } UpdateXMP(); if (localProgressTracking) progressTracker->WorkComplete(); }
void FLV_MetaHandler::UpdateFile ( bool doSafeUpdate ) { if ( ! this->needsUpdate ) return; XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates. XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; const bool checkAbort = (abortProc != 0); XMP_IO* fileRef = this->parent->ioRef; XMP_Uns64 fileSize = fileRef->Length(); // Make sure the XMP has a legacy digest if appropriate. if ( ! this->onMetaData.empty() ) { std::string newDigest; this->MakeLegacyDigest ( &newDigest ); this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "FLV", newDigest.c_str(), kXMP_DeleteExisting ); try { XMP_StringLen xmpLen = (XMP_StringLen)this->xmpPacket.size(); this->xmpObj.SerializeToBuffer ( &this->xmpPacket, (kXMP_UseCompactFormat | kXMP_ExactPacketLength), xmpLen ); } catch ( ... ) { this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } } // Rewrite the packet in-place if it fits. Otherwise rewrite the whole file. if ( this->xmpPacket.size() == (size_t)this->packetInfo.length ) { XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( progressTracker != 0 ) progressTracker->BeginWork ( (float)this->xmpPacket.size() ); fileRef->Seek ( this->packetInfo.offset, kXMP_SeekFromStart ); fileRef->Write ( this->xmpPacket.data(), (XMP_Int32)this->xmpPacket.size() ); if ( progressTracker != 0 ) progressTracker->WorkComplete(); } else { XMP_IO* tempRef = fileRef->DeriveTemp(); if ( tempRef == 0 ) XMP_Throw ( "Failure creating FLV temp file", kXMPErr_InternalFailure ); this->WriteTempFile ( tempRef ); fileRef->AbsorbTemp(); } this->needsUpdate = false; } // FLV_MetaHandler::UpdateFile
void Matroska_MetaHandler::WriteTempFile(XMP_IO* tempRef) { XMP_Assert(needsUpdate); XMP_IO* originalRef = parent->ioRef; bool localProgressTracking(false); XMP_ProgressTracker* progressTracker = parent->progressTracker; if (progressTracker) { float xmpSize = static_cast<float>(xmpPacket.size()); if (progressTracker->WorkInProgress()) { progressTracker->AddTotalWork(xmpSize); } else { localProgressTracking = true; progressTracker->BeginWork(xmpSize); } } XMP_Assert(tempRef); XMP_Assert(originalRef); tempRef->Rewind(); originalRef->Rewind(); XIO::Copy(originalRef, tempRef, originalRef->Length(), parent->abortProc, parent->abortArg); try { parent->ioRef = tempRef; // ! Fool UpdateFile into using the temp file. UpdateFile(false); parent->ioRef = originalRef; } catch (...) { parent->ioRef = originalRef; throw; } if (localProgressTracking) progressTracker->WorkComplete(); }
void ASF_MetaHandler::WriteTempFile ( XMP_IO* tempRef ) { bool ok; XMP_IO* originalRef = this->parent->ioRef; ASF_Support support(0,this->parent->progressTracker); ASF_Support::ObjectState objectState; long numTags = support.OpenASF ( originalRef, objectState ); if ( numTags == 0 ) return; tempRef->Truncate ( 0 ); ASF_Support::ObjectIterator curPos = objectState.objects.begin(); ASF_Support::ObjectIterator endPos = objectState.objects.end(); XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( progressTracker != 0 ) { float nonheadersize = (float)(xmpPacket.size()+kASF_ObjectBaseLen+8); bool legacyChange=this->legacyManager.hasLegacyChanged( ); for ( ; curPos != endPos; ++curPos ) { if (curPos->xmp) continue; //header objects are taken care of in ASF_Support::WriteHeaderObject if ( ! ( IsEqualGUID ( ASF_Header_Object, curPos->guid) && legacyChange ) ) { nonheadersize+=(curPos->len); } } curPos = objectState.objects.begin(); endPos = objectState.objects.end(); progressTracker->BeginWork ( nonheadersize ); } for ( ; curPos != endPos; ++curPos ) { ASF_Support::ObjectData object = *curPos; // discard existing XMP object if ( object.xmp ) continue; // update header-object, when legacy needs update if ( IsEqualGUID ( ASF_Header_Object, object.guid) && this->legacyManager.hasLegacyChanged( ) ) { // rewrite header object ok = support.WriteHeaderObject ( originalRef, tempRef, object, this->legacyManager, false ); if ( ! ok ) XMP_Throw ( "Failure writing ASF header object", kXMPErr_InternalFailure ); } else { // copy any other object ok = ASF_Support::CopyObject ( originalRef, tempRef, object ); if ( ! ok ) XMP_Throw ( "Failure copyinh ASF object", kXMPErr_InternalFailure ); } // write XMP object immediately after the (one and only) top-level DataObject if ( IsEqualGUID ( ASF_Data_Object, object.guid ) ) { XMP_StringPtr packetStr = xmpPacket.c_str(); XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size(); ok = ASF_Support::WriteXMPObject ( tempRef, packetLen, packetStr ); if ( ! ok ) XMP_Throw ( "Failure writing ASF XMP object", kXMPErr_InternalFailure ); } } ok = support.UpdateFileSize ( tempRef ); if ( ! ok ) XMP_Throw ( "Failure updating ASF file size", kXMPErr_InternalFailure ); if ( progressTracker != 0 ) progressTracker->WorkComplete(); } // ASF_MetaHandler::WriteTempFile
void ASF_MetaHandler::UpdateFile ( bool doSafeUpdate ) { bool updated = false; if ( ! this->needsUpdate ) return; XMP_IO* fileRef ( this->parent->ioRef ); if ( fileRef == 0 ) return; ASF_Support support(0,this->parent->progressTracker); ASF_Support::ObjectState objectState; long numTags = support.OpenASF ( fileRef, objectState ); if ( numTags == 0 ) return; XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size(); this->legacyManager.ExportLegacy ( this->xmpObj ); if ( this->legacyManager.hasLegacyChanged() ) { this->legacyManager.SetDigest ( &this->xmpObj ); // serialize with updated digest if ( objectState.xmpLen == 0 ) { // XMP does not exist, use standard padding this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } else { // re-use padding with static XMP size try { XMP_OptionBits compactExact = (kXMP_UseCompactFormat | kXMP_ExactPacketLength); this->xmpObj.SerializeToBuffer ( &this->xmpPacket, compactExact, XMP_StringLen(objectState.xmpLen) ); } catch ( ... ) { // re-use padding with exact packet length failed (legacy-digest needed too much space): try again using standard padding this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } } } XMP_StringPtr packetStr = xmpPacket.c_str(); packetLen = (XMP_StringLen)xmpPacket.size(); if ( packetLen == 0 ) return; // value, when guessing for sufficient legacy padding (line-ending conversion etc.) const int paddingTolerance = 50; bool xmpGrows = ( objectState.xmpLen && (packetLen > objectState.xmpLen) && ( ! objectState.xmpIsLastObject) ); bool legacyGrows = ( this->legacyManager.hasLegacyChanged() && (this->legacyManager.getLegacyDiff() > (this->legacyManager.GetPadding() - paddingTolerance)) ); if ( doSafeUpdate || legacyGrows || xmpGrows ) { // do a safe update in any case updated = SafeWriteFile(); } else { // possibly we can do an in-place update if ( objectState.xmpLen < packetLen ) { updated = SafeWriteFile(); } else { XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( progressTracker != 0 ) progressTracker->BeginWork ( (float)packetLen ); // current XMP chunk size is sufficient -> write (in place update) updated = ASF_Support::WriteBuffer(fileRef, objectState.xmpPos, packetLen, packetStr ); // legacy update if ( updated && this->legacyManager.hasLegacyChanged() ) { ASF_Support::ObjectIterator curPos = objectState.objects.begin(); ASF_Support::ObjectIterator endPos = objectState.objects.end(); for ( ; curPos != endPos; ++curPos ) { ASF_Support::ObjectData object = *curPos; // find header-object if ( IsEqualGUID ( ASF_Header_Object, object.guid ) ) { // update header object updated = support.UpdateHeaderObject ( fileRef, object, legacyManager ); } } } if ( progressTracker != 0 ) progressTracker->WorkComplete(); } } if ( ! updated ) return; // If there's an error writing the chunk, bail. this->needsUpdate = false; } // ASF_MetaHandler::UpdateFile
void TIFF_MetaHandler::UpdateFile ( bool doSafeUpdate ) { XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates. XMP_IO* destRef = this->parent->ioRef; XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; XMP_Int64 oldPacketOffset = this->packetInfo.offset; XMP_Int32 oldPacketLength = this->packetInfo.length; if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks. if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0; bool fileHadXMP = ((oldPacketOffset != 0) && (oldPacketLength != 0)); // Update the IPTC-IIM and native TIFF/Exif metadata. ExportPhotoData also trips the tiff: and // exif: copies from the XMP, so reserialize the now final XMP packet. ExportPhotoData ( kXMP_TIFFFile, &this->xmpObj, &this->tiffMgr, this->iptcMgr, this->psirMgr ); try { XMP_OptionBits options = kXMP_UseCompactFormat; if ( fileHadXMP ) options |= kXMP_ExactPacketLength; this->xmpObj.SerializeToBuffer ( &this->xmpPacket, options, oldPacketLength ); } catch ( ... ) { this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } // Decide whether to do an in-place update. This can only happen if all of the following are true: // - There is an XMP packet in the file. // - The are no changes to the legacy tags. (The IPTC and PSIR are in the TIFF tags.) // - The new XMP can fit in the old space. bool doInPlace = (fileHadXMP && (this->xmpPacket.size() <= (size_t)oldPacketLength)); if ( this->tiffMgr.IsLegacyChanged() ) doInPlace = false; bool localProgressTracking = false; XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( ! doInPlace ) { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", TIFF append update"; #endif if ( (progressTracker != 0) && (! progressTracker->WorkInProgress()) ) { localProgressTracking = true; progressTracker->BeginWork(); } this->tiffMgr.SetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, kTIFF_UndefinedType, (XMP_Uns32)this->xmpPacket.size(), this->xmpPacket.c_str() ); this->tiffMgr.UpdateFileStream ( destRef, progressTracker ); } else { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", TIFF in-place update"; #endif if ( this->xmpPacket.size() < (size_t)this->packetInfo.length ) { // They ought to match, cheap to be sure. size_t extraSpace = (size_t)this->packetInfo.length - this->xmpPacket.size(); this->xmpPacket.append ( extraSpace, ' ' ); } XMP_IO* liveFile = this->parent->ioRef; XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic. if ( progressTracker != 0 ) { if ( progressTracker->WorkInProgress() ) { progressTracker->AddTotalWork ( this->xmpPacket.size() ); } else { localProgressTracking = true; progressTracker->BeginWork ( this->xmpPacket.size() ); } } liveFile->Seek ( oldPacketOffset, kXMP_SeekFromStart ); liveFile->Write ( this->xmpPacket.c_str(), (XMP_Int32)this->xmpPacket.size() ); } if ( localProgressTracking ) progressTracker->WorkComplete(); this->needsUpdate = false; } // TIFF_MetaHandler::UpdateFile
void PSD_MetaHandler::WriteTempFile ( XMP_IO* tempRef ) { XMP_IO* origRef = this->parent->ioRef; XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; const bool checkAbort = (abortProc != 0); XMP_ProgressTracker* progressTracker = this->parent->progressTracker; XMP_Uns64 sourceLen = origRef->Length(); if ( sourceLen == 0 ) return; // Tolerate empty files. // Reconcile the legacy metadata, unless this is called from UpdateFile. Reserialize the XMP to // get standard padding, PutXMP has probably done an in-place serialize. Set the XMP image resource. if ( ! skipReconcile ) { // Update the IPTC-IIM and native TIFF/Exif metadata, and reserialize the now final XMP packet. ExportPhotoData ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->iptcMgr, &this->psirMgr ); this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); this->packetInfo.offset = kXMPFiles_UnknownOffset; this->packetInfo.length = (XMP_StringLen)this->xmpPacket.size(); FillPacketInfo ( this->xmpPacket, &this->packetInfo ); this->psirMgr.SetImgRsrc ( kPSIR_XMP, this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() ); // Calculate the total writes I/O to be done by this method. This includes header section, color // mode section and tail length after the image resources section. The write I/O for image // resources section is added to total work in PSIR_FileWriter::UpdateFileResources. origRef->Seek ( 26, kXMP_SeekFromStart ); //move to the point after Header 26 is the header length XMP_Uns32 cmLen,cmLen1; origRef->Read ( &cmLen, 4 ); // get the length of color mode section cmLen1 = GetUns32BE ( &cmLen ); origRef->Seek ( cmLen1, kXMP_SeekFromCurrent ); //move to the end of color mode section XMP_Uns32 irLen; origRef->Read ( &irLen, 4 ); // Get the source image resource section length. irLen = GetUns32BE ( &irLen ); XMP_Uns64 tailOffset = 26 + 4 + cmLen1 + 4 + irLen; XMP_Uns64 tailLength = sourceLen - tailOffset; // Add work for 26 bytes header, 4 bytes color mode section length, color mode section length // and tail length after the image resources section length. if ( progressTracker != 0 ) progressTracker->BeginWork ( (float)(26.0f + 4.0f + cmLen1 + tailLength) ); // Copy the file header and color mode section, then write the updated image resource section, // and copy the tail of the source file (layer and mask section to EOF). origRef->Rewind ( ); tempRef->Truncate ( 0 ); XIO::Copy ( origRef, tempRef, 26 ); // Copy the file header. origRef->Seek ( 4, kXMP_SeekFromCurrent ); tempRef->Write ( &cmLen, 4 ); // Copy the color mode section length. XIO::Copy ( origRef, tempRef, cmLen1 ); // Copy the color mode section contents. this->psirMgr.UpdateFileResources ( origRef, tempRef, abortProc, abortArg ,progressTracker ); origRef->Seek ( tailOffset, kXMP_SeekFromStart ); tempRef->Seek ( 0, kXMP_SeekFromEnd ); XIO::Copy ( origRef, tempRef, tailLength ); // Copy the tail of the file. this->needsUpdate = false; if ( progressTracker != 0 ) progressTracker->WorkComplete(); } // PSD_MetaHandler::WriteTempFile
void PSD_MetaHandler::UpdateFile ( bool doSafeUpdate ) { XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates. XMP_Int64 oldPacketOffset = this->packetInfo.offset; XMP_Int32 oldPacketLength = this->packetInfo.length; if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks. if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0; bool fileHadXMP = ((oldPacketOffset != 0) && (oldPacketLength != 0)); // Update the IPTC-IIM and native TIFF/Exif metadata. ExportPhotoData also trips the tiff: and // exif: copies from the XMP, so reserialize the now final XMP packet. ExportPhotoData ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, this->iptcMgr, &this->psirMgr ); try { XMP_OptionBits options = kXMP_UseCompactFormat; if ( fileHadXMP ) options |= kXMP_ExactPacketLength; this->xmpObj.SerializeToBuffer ( &this->xmpPacket, options, oldPacketLength ); } catch ( ... ) { this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); } // Decide whether to do an in-place update. This can only happen if all of the following are true: // - There is an XMP packet in the file. // - The are no changes to the legacy image resources. (The IPTC and EXIF are in the PSIR.) // - The new XMP can fit in the old space. bool doInPlace = (fileHadXMP && (this->xmpPacket.size() <= (size_t)oldPacketLength)); if ( this->psirMgr.IsLegacyChanged() ) doInPlace = false; XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( doInPlace ) { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", PSD in-place update"; #endif if ( this->xmpPacket.size() < (size_t)this->packetInfo.length ) { // They ought to match, cheap to be sure. size_t extraSpace = (size_t)this->packetInfo.length - this->xmpPacket.size(); this->xmpPacket.append ( extraSpace, ' ' ); } XMP_IO* liveFile = this->parent->ioRef; XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic. if ( progressTracker != 0 ) progressTracker->BeginWork ( this->xmpPacket.size() ); liveFile->Seek ( oldPacketOffset, kXMP_SeekFromStart ); liveFile->Write ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() ); if ( progressTracker != 0 ) progressTracker->WorkComplete(); } else { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", PSD copy update"; #endif XMP_IO* origRef = this->parent->ioRef; XMP_IO* tempRef = origRef->DeriveTemp(); try { XMP_Assert ( ! this->skipReconcile ); this->skipReconcile = true; this->WriteTempFile ( tempRef ); this->skipReconcile = false; } catch ( ... ) { this->skipReconcile = false; origRef->DeleteTemp(); throw; } origRef->AbsorbTemp(); } this->needsUpdate = false; } // PSD_MetaHandler::UpdateFile
void FLV_MetaHandler::WriteTempFile ( XMP_IO* tempRef ) { if ( ! this->needsUpdate ) return; XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; const bool checkAbort = (abortProc != 0); XMP_IO* originalRef = this->parent->ioRef; XMP_Uns64 sourceLen = originalRef->Length(); XMP_Uns64 sourcePos = 0; originalRef->Rewind(); tempRef->Rewind(); tempRef->Truncate ( 0 ); XMP_ProgressTracker* progressTracker = this->parent->progressTracker; if ( progressTracker != 0 ) { float fileSize=(float)(this->xmpPacket.size()+48); if ( this->omdTagPos == 0 ) { sourcePos=(this->flvHeaderLen+4); fileSize+=sourcePos; } else { if ( this->xmpTagPos < this->omdTagPos ) { fileSize+=this->xmpTagPos; } fileSize+=(this->omdTagPos + this->omdTagLen- ((this->xmpTagPos!=0 && this->xmpTagPos < this->omdTagPos)? (this->xmpTagPos + this->xmpTagLen):0)); sourcePos =this->omdTagPos + this->omdTagLen; } if ( (this->xmpTagPos != 0) && (this->xmpTagPos >= sourcePos) ) { fileSize+=(this->xmpTagPos - sourcePos); sourcePos=this->xmpTagPos + this->xmpTagLen; } fileSize+=(sourceLen - sourcePos); sourcePos=0; progressTracker->BeginWork ( fileSize ); } // First do whatever is needed to put the new XMP after any existing onMetaData tag, or as the // first time 0 tag. if ( this->omdTagPos == 0 ) { // There is no onMetaData tag. Copy the file header, then write the new XMP as the first tag. // Allow the degenerate case of a file with just a header, no initial back pointer or tags. originalRef->Seek ( sourcePos, kXMP_SeekFromStart ); XIO::Copy ( originalRef, tempRef, this->flvHeaderLen, abortProc, abortArg ); XMP_Uns32 zero = 0; // Ensure that the initial back offset really is zero. tempRef->Write ( &zero, 4 ); sourcePos = this->flvHeaderLen + 4; WriteOnXMP ( tempRef, this->xmpPacket ); } else { // There is an onMetaData tag. Copy the front of the file through the onMetaData tag, // skipping any XMP that happens to be in the way. The XMP should not be before onMetaData, // but let's be robust. Write the new XMP immediately after onMetaData, at the same time. XMP_Uns64 omdEnd = this->omdTagPos + this->omdTagLen; if ( (this->xmpTagPos != 0) && (this->xmpTagPos < this->omdTagPos) ) { // The XMP tag was in front of the onMetaData tag. Copy up to it, then skip it. originalRef->Seek ( sourcePos, kXMP_SeekFromStart ); XIO::Copy ( originalRef, tempRef, this->xmpTagPos, abortProc, abortArg ); sourcePos = this->xmpTagPos + this->xmpTagLen; // The tag length includes the trailing size field. } // Copy through the onMetaData tag, then write the XMP. originalRef->Seek ( sourcePos, kXMP_SeekFromStart ); XIO::Copy ( originalRef, tempRef, (omdEnd - sourcePos), abortProc, abortArg ); sourcePos = omdEnd; WriteOnXMP ( tempRef, this->xmpPacket ); } // Copy the rest of the file, skipping any XMP that is in the way. if ( (this->xmpTagPos != 0) && (this->xmpTagPos >= sourcePos) ) { originalRef->Seek ( sourcePos, kXMP_SeekFromStart ); XIO::Copy ( originalRef, tempRef, (this->xmpTagPos - sourcePos), abortProc, abortArg ); sourcePos = this->xmpTagPos + this->xmpTagLen; } originalRef->Seek ( sourcePos, kXMP_SeekFromStart ); XIO::Copy ( originalRef, tempRef, (sourceLen - sourcePos), abortProc, abortArg ); this->needsUpdate = false; if ( progressTracker != 0 ) progressTracker->WorkComplete(); } // FLV_MetaHandler::WriteTempFile