コード例 #1
0
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
コード例 #2
0
ファイル: Matroska_Handler.cpp プロジェクト: SSE4/vmf-1
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();
}
コード例 #3
0
ファイル: FLV_Handler.cpp プロジェクト: vb0067/XMPToolkitSDK
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
コード例 #4
0
ファイル: Matroska_Handler.cpp プロジェクト: SSE4/vmf-1
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();
}
コード例 #5
0
ファイル: ASF_Handler.cpp プロジェクト: vb0067/XMPToolkitSDK
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
コード例 #6
0
ファイル: ASF_Handler.cpp プロジェクト: vb0067/XMPToolkitSDK
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
コード例 #7
0
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
コード例 #8
0
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
コード例 #9
0
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
コード例 #10
0
ファイル: FLV_Handler.cpp プロジェクト: vb0067/XMPToolkitSDK
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