Exemplo n.º 1
0
void GIF_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
{
	XMP_Assert( this->needsUpdate );

	XMP_IO* originalRef = this->parent->ioRef;
	originalRef->Rewind();

	tempRef->Truncate ( 0 );
	
	if ( XMPPacketOffset != 0 )
	{
		// Copying blocks before XMP Application Block
		XIO::Copy( originalRef, tempRef, XMPPacketOffset );

		// Writing XMP Packet
		tempRef->Write( this->xmpPacket.c_str(), (XMP_Uns32)this->xmpPacket.size() );

		// Copying Rest of the file
		originalRef->Seek( XMPPacketLength, kXMP_SeekFromCurrent );
		XIO::Copy( originalRef, tempRef, originalRef->Length() - originalRef->Offset() );

	}
	else
	{
		if ( trailerOffset == 0 )
			XMP_Throw( "Not able to write XMP packet in GIF file", kXMPErr_BadFileFormat );

		// Copying blocks before XMP Application Block
		XIO::Copy( originalRef, tempRef, trailerOffset );

		// Writing Extension Introducer 
		XIO::WriteUns8( tempRef, kXMP_block_Extension );

		// Writing Application Extension label
		XIO::WriteUns8( tempRef, 0xFF );

		// Writing Application Extension label
		XIO::WriteUns8( tempRef, APP_ID_LEN );

		// Writing Application Extension label
		tempRef->Write( XMP_APP_ID_DATA, APP_ID_LEN );

		// Writing XMP Packet
		tempRef->Write( this->xmpPacket.c_str(), (XMP_Uns32)this->xmpPacket.size() );

		// Writing Magic trailer
		XMP_Uns8 magicByte = 0x01;
		tempRef->Write( &magicByte, 1 );
		for ( magicByte = 0xFF; magicByte != 0x00; --magicByte )
			tempRef->Write( &magicByte, 1 );
		tempRef->Write( &magicByte, 1 );
		tempRef->Write( &magicByte, 1 );

		// Copying Rest of the file
		XIO::Copy( originalRef, tempRef, originalRef->Length() - originalRef->Offset() );

	}

}	// GIF_MetaHandler::WriteTempFile
Exemplo n.º 2
0
void Matroska_MetaHandler::UpdateXMP()
{
    XMP_IO* fileRef = parent->ioRef;

    fileRef->Seek(fileRef->Length(), kXMP_SeekFromStart);

    for (auto segment : _dom->_root->getElementsById(kSegment))
    {
        for (auto tags : segment->getElementsById(kTags))
        {
            for (auto tag : tags->getElementsById(kTag))
            {
                for (auto simple_tag : tag->getElementsById(kSimpleTag))
                {
                    auto tag_name = simple_tag->getElementById(kTagName);
                    if (tag_name->_value.StringValue == "XMP")
                    {
                        auto tag_string = simple_tag->getElementById(kTagString);

                        // we have found valid XMP, and if it's in the very end of file, we can truncate segment
                        if (tag_string->_offset + tag_string->size() == fileRef->Length())
                        {
                            segment->_size._value -= tags->size();

                            fileRef->Truncate(tags->_offset);
                            fileRef->Seek(tags->_offset, kXMP_SeekFromStart);
                        }
                        // otherwise, make old XMP tag Void and create new one from the scratch
                        else
                        {
                            tags->wipe(fileRef);
                        }
                    }
                }
            }
        }
    }
    auto segments = _dom->_root->getElementsById(kSegment);
    auto segment = segments.back();

    auto tag_name = std::make_shared<ebml_element_t>(kTagName, ebml_variant_t("XMP"));
    auto tag_string = std::make_shared<ebml_element_t>(kTagString, ebml_variant_t(xmpPacket));
    auto tag_language = std::make_shared<ebml_element_t>(kTagLanguage, ebml_variant_t("eng"));
    auto tag_default = std::make_shared<ebml_element_t>(kTagDefault, ebml_variant_t(1ULL));
    auto simple_tag = std::make_shared<ebml_element_t>(kSimpleTag, ebml_element_t::vec{ tag_language, tag_default, tag_name, tag_string });
    auto tag = std::make_shared<ebml_element_t>(kTag, simple_tag);
    auto tags = std::make_shared<ebml_element_t>(kTags, tag);

    tags->write(fileRef);

    segment->_size._value += tags->size();
    segment->update_header(fileRef);
}
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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();
}
Exemplo n.º 6
0
void WEBP_MetaHandler::CacheFileData()
{
    this->containsXMP = false; // assume for now

    XMP_IO* file = this->parent->ioRef;
    this->initialFileSize = file->Length();

    file->Rewind();

    XMP_Int64 filePos = 0;
    while (filePos < this->initialFileSize) {
        this->mainChunk = new WEBP::Container(this);
        filePos = file->Offset();
    }

    // covered before => internal error if it occurs
    XMP_Validate(file->Offset() == this->initialFileSize,
                 "WEBP_MetaHandler::CacheFileData: unknown data at end of file",
                 kXMPErr_InternalFailure);
}
Exemplo n.º 7
0
// =================================================================================================
// SVG_MetaHandler::WriteTempFile
// ==============================
//
void SVG_MetaHandler::WriteTempFile( XMP_IO* tempRef )
{
	XMP_Assert( this->needsUpdate );

	XMP_IO* sourceRef = this->parent->ioRef;
	if ( sourceRef == NULL || svgNode == NULL )
		return;

	tempRef->Rewind();
	sourceRef->Rewind();

	XMP_Int64 currentOffset = svgAdapter->firstSVGElementOffset;
	XIO::Copy( sourceRef, tempRef, currentOffset );

	OffsetStruct titleOffset = svgAdapter->GetElementOffsets( "title" );
	OffsetStruct descOffset = svgAdapter->GetElementOffsets( "desc" );
	OffsetStruct metadataOffset = svgAdapter->GetElementOffsets( "metadata" );

	std::string title;
	std::string description;

	XML_NodePtr titleNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "title" );
	( void ) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "title", "", "x-default", 0, &title, 0 );

	XML_NodePtr descNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "desc" );
	( void ) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "description", "", "x-default", 0, &description, 0 );

	// Need to cover the case of both workflows
	// This would have been called after inplace is not possible
	// This would have called for safe update
	if ( !isTitleUpdateReq )
	{
		if ( ( titleNode == NULL ) == ( title.empty() ) )
		{
			if ( titleNode != NULL && titleNode->content.size() == 1 && titleNode->content[ 0 ]->kind == kCDataNode && !XMP_LitMatch( titleNode->content[ 0 ]->value.c_str(), title.c_str() ) )
				isTitleUpdateReq = true;
		}
		else
			isTitleUpdateReq = true;
	}
	if ( !isDescUpdateReq )
	{
		if ( ( descNode == NULL ) == ( description.empty() ) )
		{
			if ( descNode != NULL && descNode->content.size() == 1 && descNode->content[ 0 ]->kind == kCDataNode &&  !XMP_LitMatch( descNode->content[ 0 ]->value.c_str(), description.c_str() ) )
				isDescUpdateReq = true;
		}
		else
			isDescUpdateReq = true;
	}

	// Initial Insertion/Updation

	// Insert/Update Title if requires
	// Don't insert/update it if Metadata or desc child comes before title child
	bool isTitleWritten = !isTitleUpdateReq;
	if ( isTitleUpdateReq )
	{
		// Insertion Case
		if ( titleNode == NULL )
		{
			InsertNewTitle( tempRef, title );
			isTitleWritten = true;
		}
		else if ( ( descOffset.startOffset == -1 || titleOffset.startOffset < descOffset.startOffset )	// Updation/Deletion Case
			&& ( metadataOffset.startOffset == -1 || titleOffset.startOffset < metadataOffset.startOffset ) )
		{
			ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
			isTitleWritten = true;
		}
	}

	// Insert/Update Description if requires
	// Don't insert/update it if Metadata child comes before desc child
	bool isDescWritten = !isDescUpdateReq;
	if ( isDescUpdateReq )
	{
		if ( descNode == NULL )
		{
			if ( titleOffset.nextOffset != -1 )
			{
				XIO::Copy( sourceRef, tempRef, titleOffset.nextOffset - currentOffset );
				currentOffset = titleOffset.nextOffset;
			}
			InsertNewDescription( tempRef, description );
			isDescWritten = true;
		}
		else if ( metadataOffset.startOffset == -1 || descOffset.startOffset < metadataOffset.startOffset )
		{
			ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
			isDescWritten = true;
		}
	}

	// Insert/Update Metadata if requires
	// Don't insert/update it if case is DTM
	bool isMetadataWritten = false;
	if ( metadataOffset.startOffset == -1 )
	{
		if ( descOffset.nextOffset != -1 )
		{
			XIO::Copy( sourceRef, tempRef, descOffset.nextOffset - currentOffset );
			currentOffset = descOffset.nextOffset;
		}
		else if ( titleOffset.nextOffset != -1 )
		{
			XIO::Copy( sourceRef, tempRef, titleOffset.nextOffset - currentOffset );
			currentOffset = titleOffset.nextOffset;
		}
		InsertNewMetadata( tempRef, this->xmpPacket );
		isMetadataWritten = true;
	}
	else if ( !( !isTitleWritten && isDescWritten && titleOffset.startOffset < metadataOffset.startOffset ) )		// Not DTM
	{
		// No XMP packet was present in the file
		if ( this->packetInfo.offset == kXMPFiles_UnknownOffset )
		{
			std::string metadataElement = "<metadata>";
			XIO::Copy( sourceRef, tempRef, metadataOffset.startOffset - currentOffset + metadataElement.length() );
			currentOffset = sourceRef->Offset();
			tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
		}
		else	// Replace XMP Packet
		{
			XIO::Copy( sourceRef, tempRef, this->packetInfo.offset - currentOffset );
			tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
			sourceRef->Seek( this->packetInfo.offset + this->packetInfo.length, kXMP_SeekFromStart );
			currentOffset = sourceRef->Offset();
		}
		isMetadataWritten = true;
	}

	// If simple cases was followed then copy rest file
	if ( isTitleWritten && isDescWritten && isMetadataWritten )
	{
		XIO::Copy( sourceRef, tempRef, ( sourceRef->Length() - currentOffset ) );
		return;
	}

	// If the case is not Simple (TDM) then perform these operations
	if ( isDescWritten )		// TDM, DTM, DMT
	{
		if ( !isTitleWritten )		// DTM, DMT
		{
			if ( titleOffset.startOffset < metadataOffset.startOffset )		// DTM
			{
				ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
				isTitleWritten = true;

				if ( this->packetInfo.offset == kXMPFiles_UnknownOffset )
				{
					std::string metadataElement = "<metadata>";
					XIO::Copy( sourceRef, tempRef, metadataOffset.startOffset - currentOffset + metadataElement.length() );
					currentOffset = sourceRef->Offset();
					tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
				}
				else
				{
					XIO::Copy( sourceRef, tempRef, this->packetInfo.offset - currentOffset );
					tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
					sourceRef->Seek( this->packetInfo.offset + this->packetInfo.length, kXMP_SeekFromStart );
					currentOffset = sourceRef->Offset();
				}
				isMetadataWritten = true;

			}
			else	// DMT
			{
				ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
				isTitleWritten = true;
			}
		}
		// Else
		// Would have already covered this case: TDM

	}
	else		//  TMD, MDT, MTD
	{
		if ( isTitleWritten )		// TMD
		{
			ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
			isDescWritten = true;
		}
		else		// MDT or MTD
		{
			if ( titleOffset.startOffset < descOffset.startOffset )	// MTD
			{
				ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
				isTitleWritten = true;

				ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
				isDescWritten = true;
			}
			else		// MDT
			{
				ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
				isDescWritten = true;

				ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
				isTitleWritten = true;
			}
		}
	}

	// Finally Everything would have been written
	XMP_Enforce( isTitleWritten && isDescWritten && isMetadataWritten );
	XIO::Copy( sourceRef, tempRef, ( sourceRef->Length() - currentOffset ) );
	this->needsUpdate = false;

}	// SVG_MetaHandler::WriteTempFile
Exemplo n.º 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
void Scanner_MetaHandler::CacheFileData()
{
	XMP_IO* fileRef   = this->parent->ioRef;
	bool        beLenient = XMP_OptionIsClear ( this->parent->openFlags, kXMPFiles_OpenStrictly );

	int			pkt;
	XMP_Int64	bufPos;
	size_t		bufLen;
	SXMPMeta *	newMeta;

	XMP_AbortProc abortProc  = this->parent->abortProc;
	void *            abortArg   = this->parent->abortArg;
	const bool        checkAbort = (abortProc != 0);

	std::vector<CandidateInfo> candidates;	// ! These have SXMPMeta* fields, don't leak on exceptions.

	this->containsXMP = false;

	try {

		// ------------------------------------------------------
		// Scan the entire file to find all of the valid packets.

		XMP_Int64  fileLen = fileRef->Length();
		XMPScanner scanner ( fileLen );

		enum { kBufferSize = 64*1024 };
		XMP_Uns8	buffer [kBufferSize];

		fileRef->Rewind();

		for ( bufPos = 0; bufPos < fileLen; bufPos += bufLen ) {
			if ( checkAbort && abortProc(abortArg) ) {
				XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
			}
			bufLen = fileRef->Read ( buffer, kBufferSize );
			if ( bufLen == 0 ) XMP_Throw ( "Scanner_MetaHandler::LocateXMP: Read failure", kXMPErr_ExternalFailure );
			scanner.Scan ( buffer, bufPos, bufLen );
		}

		// --------------------------------------------------------------
		// Parse the valid packet snips, building a vector of candidates.

		long snipCount = scanner.GetSnipCount();

		XMPScanner::SnipInfoVector snips ( snipCount );
		scanner.Report ( snips );

		for ( pkt = 0; pkt < snipCount; ++pkt ) {

			if ( checkAbort && abortProc(abortArg) ) {
				XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
			}

			// Seek to the packet then try to parse it.

			if ( snips[pkt].fState != XMPScanner::eValidPacketSnip ) continue;
			fileRef->Seek ( snips[pkt].fOffset, kXMP_SeekFromStart );
			newMeta = new SXMPMeta();
			std::string xmpPacket;
			xmpPacket.reserve ( (size_t)snips[pkt].fLength );

			try {
				for ( bufPos = 0; bufPos < snips[pkt].fLength; bufPos += bufLen ) {
					bufLen = kBufferSize;
					if ( (bufPos + bufLen) > (size_t)snips[pkt].fLength ) bufLen = size_t ( snips[pkt].fLength - bufPos );
					(void) fileRef->ReadAll ( buffer, (XMP_Int32)bufLen );
					xmpPacket.append ( (const char *)buffer, bufLen );
					newMeta->ParseFromBuffer ( (char *)buffer, (XMP_StringLen)bufLen, kXMP_ParseMoreBuffers );
				}
				newMeta->ParseFromBuffer ( 0, 0, kXMP_NoOptions );
			} catch ( ... ) {
				delete newMeta;
				if ( beLenient ) continue;	// Skip if we're being lenient, else rethrow.
				throw;
			}

			// It parsed OK, add it to the array of candidates.

			candidates.push_back ( CandidateInfo() );
			CandidateInfo & newInfo = candidates.back();
			newInfo.xmpObj = newMeta;
			newInfo.xmpPacket.swap ( xmpPacket );
			newInfo.packetInfo.offset = snips[pkt].fOffset;
			newInfo.packetInfo.length = (XMP_Int32)snips[pkt].fLength;
			newInfo.packetInfo.charForm  = snips[pkt].fCharForm;
			newInfo.packetInfo.writeable = (snips[pkt].fAccess == 'w');

		}

		// ----------------------------------------
		// Figure out which packet is the main one.

		int main = PickMainPacket ( candidates, beLenient );

		if ( main != -1 ) {
			this->packetInfo = candidates[main].packetInfo;
			this->xmpPacket.swap ( candidates[main].xmpPacket );
			this->xmpObj = *candidates[main].xmpObj;
			this->containsXMP = true;
			this->processedXMP = true;
		}

		for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
			if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
		}

	} catch ( ... ) {

		// Clean up the SXMPMeta* fields from the vector of candidates.
		for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
			if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
		}
		throw;

	}

}	// Scanner_MetaHandler::CacheFileData
Exemplo n.º 10
0
void JPEG_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_Uns16 marker, contentLen;

	static const size_t kBufferSize = 64*1024;	// Enough for a segment with maximum contents.
	XMP_Uns8 buffer [kBufferSize];
	
	XMP_Int64 origLength = origRef->Length();
	if ( origLength == 0 ) return;	// Tolerate empty files.
	if ( origLength < 4 ) {
		XMP_Throw ( "JPEG must have at least SOI and EOI markers", kXMPErr_BadJPEG );
	}

	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 );
	}

	origRef->Rewind();
	tempRef->Truncate ( 0 );

	marker = XIO::ReadUns16_BE ( origRef );	// Just read the SOI marker.
	if ( marker != 0xFFD8 ) XMP_Throw ( "Missing SOI marker", kXMPErr_BadJPEG );
	XIO::WriteUns16_BE ( tempRef, marker );

	// Copy any leading APP0 marker segments.

	while ( true ) {

		if ( checkAbort && abortProc(abortArg) ) {
			XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
		}
		
		if ( ! XIO::CheckFileSpace ( origRef, 2 ) ) break;	// Tolerate a file that ends abruptly.
		
		marker = XIO::ReadUns16_BE ( origRef );	// Read the next marker.
		if ( marker == 0xFFFF ) {
			// Have a pad byte, skip it. These are almost unheard of, so efficiency isn't critical.
			origRef->Seek ( -1, kXMP_SeekFromCurrent );	// Skip the first 0xFF, read the second again.
			continue;
		}

		if ( marker != 0xFFE0 ) break;	// Have a non-APP0 marker.
		XIO::WriteUns16_BE ( tempRef, marker );	// Write the APP0 marker.
		
		contentLen = XIO::ReadUns16_BE ( origRef );	// Copy the APP0 segment's length.
		XIO::WriteUns16_BE ( tempRef, contentLen );

		if ( contentLen < 2 ) XMP_Throw ( "Invalid JPEG segment length", kXMPErr_BadJPEG );
		contentLen -= 2;	// Reduce to just the content length.
		origRef->ReadAll ( buffer, contentLen );	// Copy the APP0 segment's content.
		tempRef->Write ( buffer, contentLen );

	}

	// Write the new Exif APP1 marker segment.

	XMP_Uns32 first4;

	if ( this->exifMgr != 0 ) {

		void* exifPtr;
		XMP_Uns32 exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr );
		if ( exifLen > kExifMaxDataLength ) exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr, true /* compact */ );

		while ( exifLen > 0 ) {
			XMP_Uns32 count = std::min ( exifLen, (XMP_Uns32) kExifMaxDataLength );
			first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + count );
			tempRef->Write ( &first4, 4 );
			tempRef->Write ( kExifSignatureString, kExifSignatureLength );
			tempRef->Write ( exifPtr, count );
			exifPtr = (XMP_Uns8 *) exifPtr + count;
			exifLen -= count;
		}
	}

	// Write the new XMP APP1 marker segment, with possible extension marker segments.

	std::string mainXMP, extXMP, extDigest;
	SXMPUtils::PackageForJPEG ( this->xmpObj, &mainXMP, &extXMP, &extDigest );
	XMP_Assert ( (extXMP.size() == 0) || (extDigest.size() == 32) );

	first4 = MakeUns32BE ( 0xFFE10000 + 2 + kMainXMPSignatureLength + (XMP_Uns32)mainXMP.size() );
	tempRef->Write ( &first4, 4 );
	tempRef->Write ( kMainXMPSignatureString, kMainXMPSignatureLength );
	tempRef->Write ( mainXMP.c_str(), (XMP_Int32)mainXMP.size() );

	size_t extPos = 0;
	size_t extLen = extXMP.size();

	while ( extLen > 0 ) {

		size_t partLen = extLen;
		if ( partLen > 65000 ) partLen = 65000;

		first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExtXMPPrefixLength + (XMP_Uns32)partLen );
		tempRef->Write ( &first4, 4 );

		tempRef->Write ( kExtXMPSignatureString, kExtXMPSignatureLength );
		tempRef->Write ( extDigest.c_str(), (XMP_Int32)extDigest.size() );

		first4 = MakeUns32BE ( (XMP_Int32)extXMP.size() );
		tempRef->Write ( &first4, 4 );
		first4 = MakeUns32BE ( (XMP_Int32)extPos );
		tempRef->Write ( &first4, 4 );

		tempRef->Write ( &extXMP[extPos], (XMP_Int32)partLen );

		extPos += partLen;
		extLen -= partLen;

	}

	// Write the new PSIR APP13 marker segments.
	if ( this->psirMgr != 0 ) {

		void* psirPtr;
		XMP_Uns32 psirLen = this->psirMgr->UpdateMemoryResources ( &psirPtr );
		while ( psirLen > 0 ) {
			XMP_Uns32 count = std::min ( psirLen, (XMP_Uns32) kPSIRMaxDataLength );
			first4 = MakeUns32BE ( 0xFFED0000 + 2 + kPSIRSignatureLength + count );
			tempRef->Write ( &first4, 4 );
			tempRef->Write ( kPSIRSignatureString, kPSIRSignatureLength );
			tempRef->Write ( psirPtr, count );
			psirPtr = (XMP_Uns8 *) psirPtr + count;
			psirLen -= count;
		}
	}

	// Copy remaining marker segments, skipping old metadata, to the first SOS marker or to EOI.
	origRef->Seek ( -2, kXMP_SeekFromCurrent );	// Back up to the marker from the end of the APP0 copy loop.
	
	while ( true ) {

		if ( checkAbort && abortProc(abortArg) ) {
			XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
		}

		if ( ! XIO::CheckFileSpace ( origRef, 2 ) ) break;	// Tolerate a file that ends abruptly.
		
		marker = XIO::ReadUns16_BE ( origRef );	// Read the next marker.
		if ( marker == 0xFFFF ) {
			// Have a pad byte, skip it. These are almost unheard of, so efficiency isn't critical.
			origRef->Seek ( -1, kXMP_SeekFromCurrent );	// Skip the first 0xFF, read the second again.
			continue;
		}

		if ( (marker == 0xFFDA) || (marker == 0xFFD9) ) {	// Quit at the first SOS marker or at EOI.
			origRef->Seek ( -2, kXMP_SeekFromCurrent );	// The tail copy must include this marker.
			break;
		}

		if ( (marker == 0xFF01) ||	// Ill-formed file if we encounter a TEM or RSTn marker.
			 ((0xFFD0 <= marker) && (marker <= 0xFFD7)) ) {
			XMP_Throw ( "Unexpected TEM or RSTn marker", kXMPErr_BadJPEG );
		}

		contentLen = XIO::ReadUns16_BE ( origRef );	// Read this segment's length.
		if ( contentLen < 2 ) XMP_Throw ( "Invalid JPEG segment length", kXMPErr_BadJPEG );
		contentLen -= 2;	// Reduce to just the content length.
		
		XMP_Int64 contentOrigin = origRef->Offset();
		bool copySegment = true;
		size_t signatureLen;

		if ( (marker == 0xFFED) && (contentLen >= kPSIRSignatureLength) ) {

			// This is an APP13 segment, skip if it is the old PSIR.
			signatureLen = origRef->Read ( buffer, kPSIRSignatureLength );
			if ( (signatureLen == kPSIRSignatureLength) &&
				 CheckBytes ( &buffer[0], kPSIRSignatureString, kPSIRSignatureLength ) ) {
				copySegment = false;
			}

		} else if ( (marker == 0xFFE1) && (contentLen >= kExifSignatureLength) ) {	// Check for the shortest signature.

			// This is an APP1 segment, skip if it is the old Exif or XMP.
			
			XMP_Assert ( (kExifSignatureLength < kMainXMPSignatureLength) &&
						 (kMainXMPSignatureLength < kExtXMPSignatureLength) );
			signatureLen = origRef->Read ( buffer, kExtXMPSignatureLength );	// Read for the longest signature.

			if ( (signatureLen >= kExifSignatureLength) &&
				 (CheckBytes ( &buffer[0], kExifSignatureString, kExifSignatureLength ) ||
				  CheckBytes ( &buffer[0], kExifSignatureAltStr, kExifSignatureLength )) ) {
				copySegment = false;
			}
			
			if ( copySegment && (signatureLen >= kMainXMPSignatureLength) &&
				 CheckBytes ( &buffer[0], kMainXMPSignatureString, kMainXMPSignatureLength ) ) {
				copySegment = false;
			}
			
			if ( copySegment && (signatureLen == kExtXMPSignatureLength) &&
				 CheckBytes ( &buffer[0], kExtXMPSignatureString, kExtXMPPrefixLength ) ) {
				copySegment = false;
			}
			
		}
		
		if ( ! copySegment ) {
			origRef->Seek ( (contentOrigin + contentLen), kXMP_SeekFromStart );
		} else {
			XIO::WriteUns16_BE ( tempRef, marker );
			XIO::WriteUns16_BE ( tempRef, (contentLen + 2) );
			origRef->Seek ( contentOrigin, kXMP_SeekFromStart );
			origRef->ReadAll ( buffer, contentLen );
			tempRef->Write ( buffer, contentLen );
		}

	}

	// Copy the remainder of the source file.

	XIO::Copy ( origRef, tempRef, (origLength - origRef->Offset()) );
	this->needsUpdate = false;

}	// JPEG_MetaHandler::WriteTempFile
Exemplo n.º 11
0
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
Exemplo n.º 12
0
void FLV_MetaHandler::CacheFileData()
{
	XMP_Assert ( ! this->containsXMP );

	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();

	XMP_Uns8  buffer [16];	// Enough for 1+2+"onMetaData"+nul.
	XMP_Uns32 ioCount;
	TagInfo   info;

	fileRef->Seek ( 5, kXMP_SeekFromStart );
	fileRef->ReadAll ( buffer, 4 );

	this->flvHeaderLen = GetUns32BE ( &buffer[0] );
	XMP_Uns32 firstTagPos = this->flvHeaderLen + 4;	// Include the initial zero back pointer.

	if ( firstTagPos >= fileSize ) return;	// Quit now if the file is just a header.

	for ( XMP_Uns64 tagPos = firstTagPos; tagPos < fileSize; tagPos += (11 + info.dataSize + 4) ) {

		if ( checkAbort && abortProc(abortArg) ) {
			XMP_Throw ( "FLV_MetaHandler::LookForMetadata - User abort", kXMPErr_UserAbort );
		}

		GetTagInfo ( fileRef, tagPos, &info );	// ! GetTagInfo seeks to the tag offset.
		if ( info.time != 0 ) break;
		if ( info.type != 18 ) continue;

		XMP_Assert ( sizeof(buffer) >= (1+2+10+1) );	// 02 000B onMetaData 00
		ioCount = fileRef->Read ( buffer, sizeof(buffer) );
		if ( (ioCount < 4) || (buffer[0] != 0x02) ) continue;

		XMP_Uns16     nameLen = GetUns16BE ( &buffer[1] );
		XMP_StringPtr namePtr = (XMP_StringPtr)(&buffer[3]);

		if ( this->onXMP.empty() && CheckName ( namePtr, nameLen, "onXMPData", 9 ) ) {

			// ! Put the raw data in onXMPData, analyze the value in ProcessXMP.

			this->xmpTagPos = tagPos;
			this->xmpTagLen = 11 + info.dataSize + 4;	// ! Includes the trailing back pointer.

			this->packetInfo.offset = tagPos + 11 + 1+2+nameLen;	// ! Not the real offset yet, the offset of the onXMPData value.

			ioCount = info.dataSize - (1+2+nameLen);	// Just the onXMPData value portion.
			this->onXMP.reserve ( ioCount );
			this->onXMP.assign ( ioCount, ' ' );
			fileRef->Seek ( this->packetInfo.offset, kXMP_SeekFromStart );
			fileRef->ReadAll ( (void*)this->onXMP.data(), ioCount );

			if ( ! this->onMetaData.empty() ) break;	// Done if we've found both.

		} else if ( this->onMetaData.empty() && CheckName ( namePtr, nameLen, "onMetaData", 10 ) ) {

			this->omdTagPos  = tagPos;
			this->omdTagLen  = 11 + info.dataSize + 4;	// ! Includes the trailing back pointer.

			ioCount = info.dataSize - (1+2+nameLen);	// Just the onMetaData value portion.
			this->onMetaData.reserve ( ioCount );
			this->onMetaData.assign ( ioCount, ' ' );
			fileRef->Seek ( (tagPos + 11 + 1+2+nameLen), kXMP_SeekFromStart );
			fileRef->ReadAll ( (void*)this->onMetaData.data(), ioCount );

			if ( ! this->onXMP.empty() ) break;	// Done if we've found both.

		}

	}

}	// FLV_MetaHandler::CacheFileData