Exemplo n.º 1
0
void PSD_MetaHandler::CacheFileData()
{
	XMP_IO*      fileRef    = this->parent->ioRef;
	XMP_PacketInfo & packetInfo = this->packetInfo;

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

	XMP_Assert ( ! this->containsXMP );
	// Set containsXMP to true here only if the XMP image resource is found.

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

	XMP_Uns8  psdHeader[30];
	XMP_Uns32 ioLen, cmLen;

	XMP_Int64 filePos = 0;
	fileRef->Rewind ( );

	ioLen = fileRef->Read ( psdHeader, 30 );
	if ( ioLen != 30 ) return;	// Throw?

	this->imageHeight = GetUns32BE ( &psdHeader[14] );
	this->imageWidth  = GetUns32BE ( &psdHeader[18] );

	cmLen = GetUns32BE ( &psdHeader[26] );

	XMP_Int64 psirOrigin = 26 + 4 + cmLen;

	filePos = fileRef->Seek ( psirOrigin, kXMP_SeekFromStart  );
	if ( filePos !=  psirOrigin ) return;	// Throw?

	if ( ! XIO::CheckFileSpace ( fileRef, 4 ) ) return;	// Throw?
	XMP_Uns32 psirLen = XIO::ReadUns32_BE ( fileRef );

	this->psirMgr.ParseFileResources ( fileRef, psirLen );

	PSIR_Manager::ImgRsrcInfo xmpInfo;
	bool found = this->psirMgr.GetImgRsrc ( kPSIR_XMP, &xmpInfo );

	if ( found ) {

		// printf ( "PSD_MetaHandler::CacheFileData - XMP packet offset %d (0x%X), size %d\n",
		//		  xmpInfo.origOffset, xmpInfo.origOffset, xmpInfo.dataLen );
		this->packetInfo.offset = xmpInfo.origOffset;
		this->packetInfo.length = xmpInfo.dataLen;
		this->packetInfo.padSize   = 0;				// Assume for now, set these properly in ProcessXMP.
		this->packetInfo.charForm  = kXMP_CharUnknown;
		this->packetInfo.writeable = true;

		this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );

		this->containsXMP = true;

	}

}	// PSD_MetaHandler::CacheFileData
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.º 3
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.º 4
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.º 5
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.º 6
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.º 7
0
void SVG_MetaHandler::CacheFileData() 
{
	XMP_Assert( !this->containsXMP );

	XMP_IO * fileRef = this->parent->ioRef;
	
	XMP_Uns8 marker[ 4 ];
	fileRef->Rewind();
	fileRef->Read( marker, 4 );

	// Checking for UTF-16 BOM and UTF-32 BOM
	if ( ( marker[ 0 ] == 0xFF && marker[ 1 ] == 0xFE ) || ( marker[ 0 ] == 0xFE && marker[ 1 ] == 0xFF ) || ( marker[ 0 ] == marker[ 1 ] == 0x00 && marker[ 2 ] == 0xFE && marker[ 3 ] == 0xFF ) )
	{
		XMP_Error error( kXMPErr_BadXML, "Invalid SVG file" );
		this->NotifyClient( &this->parent->errorCallback, kXMPErrSev_OperationFatal, error );
	}
		
	// Creating a new SVG Parser
	svgAdapter = new SVG_Adapter();
	if ( svgAdapter == 0 )
		XMP_Throw( "SVG_MetaHandler: Can't create SVG adapter", kXMPErr_NoMemory );
	svgAdapter->SetErrorCallback( &this->parent->errorCallback );

	// Registering all the required tags to SVG Parser
	svgAdapter->RegisterPI( "xpacket" );
	svgAdapter->RegisterElement( "metadata", "svg" );
	svgAdapter->RegisterElement( "xmpmeta", "metadata" );
	svgAdapter->RegisterElement( "RDF", "metadata" );
	svgAdapter->RegisterElement( "title", "svg" );
	svgAdapter->RegisterElement( "desc", "svg" );

	// Parsing the whole buffer
	fileRef->Rewind();
	XMP_Uns8 buffer[ 64 * 1024 ];
	while ( true ) {
		XMP_Int32 ioCount = fileRef->Read( buffer, sizeof( buffer ) );
		if ( ioCount == 0 || !svgAdapter->IsParsingRequire() ) break;
		svgAdapter->ParseBuffer( buffer, ioCount, false /* not the end */ );
	}
	svgAdapter->ParseBuffer( 0, 0, true );	// End the parse.

	XML_Node & xmlTree = this->svgAdapter->tree;
	XML_NodePtr rootElem = 0;

	for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i )
	{
		if ( xmlTree.content[ i ]->kind == kElemNode ) {
			rootElem = xmlTree.content[ i ];
		}
	}
	if ( rootElem == 0 )
		XMP_Throw( "Not a valid SVG File", kXMPErr_BadFileFormat );

	XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;

	if ( ! XMP_LitMatch( rootLocalName, "svg" ) )
		XMP_Throw( "Not able to parse such SVG File", kXMPErr_BadFileFormat );
	
	// Making SVG node as Root Node
	svgNode = rootElem;

	bool FoundPI = false;
	bool FoundWrapper = false;
	XML_NodePtr metadataNode = svgNode->GetNamedElement( rootElem->ns.c_str(), "metadata" );

	// We are intersted only in the Metadata tag of outer SVG element
	// XMP should be present only in metadata Node of SVG
	if ( metadataNode != NULL )
	{
		XMP_Int64 packetLength = -1;
		XMP_Int64 packetOffset = -1;
		XMP_Int64 PIOffset = svgAdapter->GetPIOffset( "xpacket", 1 );
		OffsetStruct wrapperOffset = svgAdapter->GetElementOffsets( "xmpmeta" );
		OffsetStruct rdfOffset = svgAdapter->GetElementOffsets( "RDF" );
		
		// Checking XMP PI's position
		if ( PIOffset != -1 )
		{
			if ( wrapperOffset.startOffset != -1 && wrapperOffset.startOffset < PIOffset )
				packetOffset = wrapperOffset.startOffset;
			else
			{
				XMP_Int64 trailerOffset = svgAdapter->GetPIOffset( "xpacket", 2 );
				XML_NodePtr trailerNode = metadataNode->GetNamedElement( "", "xpacket", 1 );
				if ( trailerOffset != -1 || trailerNode != 0 )
				{
					packetLength = 2;								// "<?" = 2
					packetLength += trailerNode->name.length();		// Node's name
					packetLength += 1;								// Empty Space after Node's name
					packetLength += trailerNode->value.length();	// Value
					packetLength += 2;								// "?>" = 2
					packetLength += ( trailerOffset - PIOffset );
					packetOffset = PIOffset;
				}
			}
		}
		else if ( wrapperOffset.startOffset != -1 )		// XMP Wrapper is present without PI
		{
			XML_NodePtr wrapperNode = metadataNode->GetNamedElement( "adobe:ns:meta/", "xmpmeta" );
			if ( wrapperNode != 0 )
			{
				std::string trailerWrapper = "</x:xmpmeta>";
				packetLength = trailerWrapper.length();
				packetLength += ( wrapperOffset.endOffset - wrapperOffset.startOffset );
				packetOffset = wrapperOffset.startOffset;
			}
		}
		else		// RDF packet is present without PI and wrapper
		{
			XML_NodePtr rdfNode = metadataNode->GetNamedElement( "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF" );
			if ( rdfNode != 0 )
			{
				std::string rdfTrailer = "</rdf:RDF>";
				packetLength = rdfTrailer.length();
				packetLength += ( rdfOffset.endOffset - rdfOffset.startOffset );
				packetOffset = rdfOffset.startOffset;
			}
		}

		// Fill the necesarry information and packet with XMP data
		if ( packetOffset != -1 )
		{
			this->packetInfo.offset = packetOffset;
			this->packetInfo.length = ( XMP_Int32 ) packetLength;
			this->xmpPacket.assign( this->packetInfo.length, ' ' );
			fileRef->Seek( packetOffset, kXMP_SeekFromStart );
			fileRef->ReadAll( ( void* )this->xmpPacket.data(), this->packetInfo.length );
			FillPacketInfo( this->xmpPacket, &this->packetInfo );
			this->containsXMP = true;
			return;
		}
	}
	this->containsXMP = false;	

}	// SVG_MetaHandler::CacheFileData
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
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
Exemplo n.º 12
0
void InDesign_MetaHandler::CacheFileData()
{
	XMP_IO* fileRef = this->parent->ioRef;
	XMP_PacketInfo & packetInfo = this->packetInfo;

	XMP_Assert ( kINDD_PageSize == sizeof(InDesignMasterPage) );
	static const size_t kBufferSize = (2 * kINDD_PageSize);
	XMP_Uns8 buffer [kBufferSize];

	size_t	 dbPages;
	XMP_Uns8 cobjEndian;

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

	this->containsXMP = false;

	// ---------------------------------------------------------------------------------
	// Figure out which master page is active and seek to the contiguous object portion.

	{
		fileRef->Rewind();
		fileRef->ReadAll ( buffer, (2 * kINDD_PageSize) );

		InDesignMasterPage * masters = (InDesignMasterPage *) &buffer[0];
		XMP_Uns64 seq0 = GetUns64LE ( (XMP_Uns8 *) &masters[0].fSequenceNumber );
		XMP_Uns64 seq1 = GetUns64LE ( (XMP_Uns8 *) &masters[1].fSequenceNumber );

		dbPages = GetUns32LE ( (XMP_Uns8 *) &masters[0].fFilePages );
		cobjEndian = masters[0].fObjectStreamEndian;
		if ( seq1 > seq0 ) {
			dbPages = GetUns32LE ( (XMP_Uns8 *)  &masters[1].fFilePages );
			cobjEndian = masters[1].fObjectStreamEndian;
		}
	}

	XMP_Assert ( ! this->streamBigEndian );
	if ( cobjEndian == kINDD_BigEndian ) this->streamBigEndian = true;

	// ---------------------------------------------------------------------------------------------
	// Look for the XMP contiguous object. Each contiguous object has a header and trailer, both of
	// the InDesignContigObjMarker structure. The stream size in the header/trailer is the number of
	// data bytes between the header and trailer. The XMP stream begins with a 4 byte size of the
	// XMP packet. Yes, this is the contiguous object data size minus 4 - silly but true. The XMP
	// must have a packet wrapper, the leading xpacket PI is used as the marker of XMP.

	XMP_Int64 cobjPos = (XMP_Int64)dbPages * kINDD_PageSize;	// ! Use a 64 bit multiply!
	cobjPos -= (2 * sizeof(InDesignContigObjMarker));			// ! For the first pass in the loop.
	XMP_Uns32 streamLength = 0;									// ! For the first pass in the loop.

	while ( true ) {

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

		// Fetch the start of the next stream and check the contiguous object header.
		// ! The writeable bit of fObjectClassID is ignored, we use the packet trailer flag.

		cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
		fileRef->Seek ( cobjPos, kXMP_SeekFromStart );
		fileRef->ReadAll ( buffer, sizeof(InDesignContigObjMarker) );

		const InDesignContigObjMarker * cobjHeader = (const InDesignContigObjMarker *) &buffer[0];
		if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break;	// Not a contiguous object header.
		this->xmpObjID = cobjHeader->fObjectUID;	// Save these now while the buffer is good.
		this->xmpClassID = cobjHeader->fObjectClassID;
		streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );

		// See if this is the XMP stream.

		if ( streamLength < (4 + kUTF8_PacketHeaderLen + kUTF8_PacketTrailerLen) ) continue;	// Too small, can't possibly be XMP.

		fileRef->ReadAll ( buffer, (4 + kUTF8_PacketHeaderLen) );
		XMP_Uns32 innerLength = GetUns32LE ( &buffer[0] );
		if ( this->streamBigEndian ) innerLength = GetUns32BE ( &buffer[0] );
		if ( innerLength != (streamLength - 4) ) {
			// Be tolerant of a mistake with the endian flag.
			innerLength = Flip4 ( innerLength );
			if ( innerLength != (streamLength - 4) ) continue;	// Not legit XMP.
		}

		XMP_Uns8 * chPtr = &buffer[4];
		size_t startLen = strlen((char*)kUTF8_PacketStart);
		size_t idLen = strlen((char*)kUTF8_PacketID);
		
		if ( ! CheckBytes ( chPtr, kUTF8_PacketStart, startLen ) ) continue;
		chPtr += startLen;

		XMP_Uns8 quote = *chPtr;
		if ( (quote != '\'') && (quote != '"') ) continue;
		chPtr += 1;
		if ( *chPtr != quote ) {
			if ( ! CheckBytes ( chPtr, Uns8Ptr("\xEF\xBB\xBF"), 3 ) ) continue;
			chPtr += 3;
		}
		if ( *chPtr != quote ) continue;
		chPtr += 1;

		if ( ! CheckBytes ( chPtr, Uns8Ptr(" id="), 4 ) ) continue;
		chPtr += 4;
		quote = *chPtr;
		if ( (quote != '\'') && (quote != '"') ) continue;
		chPtr += 1;
		if ( ! CheckBytes ( chPtr, kUTF8_PacketID, idLen ) ) continue;
		chPtr += idLen;
		if ( *chPtr != quote ) continue;
		chPtr += 1;

		// We've seen enough, it is the XMP. To fit the Basic_Handler model we need to compute the
		// total size of remaining contiguous objects, the trailingContentSize. We don't use the
		// size to EOF, that would wrongly include the final zero padding for 4KB alignment.

		this->xmpPrefixSize = sizeof(InDesignContigObjMarker) + 4;
		this->xmpSuffixSize = sizeof(InDesignContigObjMarker);
		packetInfo.offset = cobjPos + this->xmpPrefixSize;
		packetInfo.length = innerLength;

		XMP_Int64 tcStart = cobjPos + streamLength + (2 * sizeof(InDesignContigObjMarker));
		while ( true ) {
			if ( checkAbort && abortProc(abortArg) ) {
				XMP_Throw ( "InDesign_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
			}
			cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
			XMP_Uns32 len = fileRef->Read ( buffer, sizeof(InDesignContigObjMarker) );
			if ( len < sizeof(InDesignContigObjMarker) ) break;	// Too small, must be end of file.
			cobjHeader = (const InDesignContigObjMarker *) &buffer[0];
			if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break;	// Not a contiguous object header.
			streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );
		}
		this->trailingContentSize = cobjPos - tcStart;

		#if TraceInDesignHandler
			XMP_Uns32 pktOffset = (XMP_Uns32)this->packetInfo.offset;
			printf ( "Found XMP in InDesign file, offsets:\n" );
			printf ( "  CObj head %X, XMP %X, CObj tail %X, file tail %X, padding %X\n",
					 (pktOffset - this->xmpPrefixSize), pktOffset, (pktOffset + this->packetInfo.length),
					 (pktOffset + this->packetInfo.length + this->xmpSuffixSize),
					 (pktOffset + this->packetInfo.length + this->xmpSuffixSize + (XMP_Uns32)this->trailingContentSize) );
		#endif

		this->containsXMP = true;
		break;

	}

	if ( this->containsXMP ) {
		this->xmpFileOffset = packetInfo.offset;
		this->xmpFileSize = packetInfo.length;
		ReadXMPPacket ( this );
	}

}	// InDesign_MetaHandler::CacheFileData
Exemplo n.º 13
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