Beispiel #1
0
XMPIterator::XMPIterator ( XMP_StringPtr  /*schemaNS*/,
                           XMP_StringPtr  /*propName*/,
                           XMP_OptionBits options ) : clientRefs(0), info(IterInfo(options,0))
{

	XMP_Throw ( "Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented );

}	// XMPIterator for global tables
Beispiel #2
0
void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last /* = true */ )
{
    enum XML_Status status;

    if ( length == 0 ) {	// Expat does not like empty buffers.
        if ( ! last ) return;
        buffer = kOneSpace;
        length = 1;
    }

    status = XML_Parse ( this->parser, (const char *)buffer, length, last );

    #if BanAllEntityUsage
        if ( this->isAborted ) XMP_Throw ( "DOCTYPE is not allowed", kXMPErr_BadXML );
    #endif

    if ( status != XML_STATUS_OK ) {

        XMP_StringPtr errMsg = "XML parsing failure";

        #if 0	// XMP_DebugBuild	// Disable for now to make test output uniform. Restore later with thread safety.

            // *** This is a good candidate for a callback error notification mechanism.
            // *** This code is not thread safe, the sExpatMessage isn't locked. But that's OK for debug usage.

            enum XML_Error expatErr = XML_GetErrorCode ( this->parser );
            const char *   expatMsg = XML_ErrorString ( expatErr );
            int errLine = XML_GetCurrentLineNumber ( this->parser );

            char msgBuffer[1000];
            // AUDIT: Use of sizeof(msgBuffer) for snprintf length is safe.
            snprintf ( msgBuffer, sizeof(msgBuffer), "# Expat error %d at line %d, \"%s\"", expatErr, errLine, expatMsg );
            sExpatMessage = msgBuffer;
            errMsg = sExpatMessage.c_str();

            #if  DumpXMLParseEvents
                if ( this->parseLog != 0 ) fprintf ( this->parseLog, "%s\n", errMsg, expatErr, errLine, expatMsg );
            #endif

        #endif

        XMP_Throw ( errMsg, kXMPErr_BadXML );

    }

}	// ExpatAdapter::ParseBuffer
Beispiel #3
0
XMPIterator::XMPIterator ( XMP_StringPtr  schemaNS,
						   XMP_StringPtr  propName,
						   XMP_OptionBits options ) : clientRefs(0), info(IterInfo(options,0))
{

	XMP_Throw ( "Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented );
		void * p; p = &schemaNS; p = &propName; p = &options;	// Avoid unused param warnings.

}	// XMPIterator for global tables
Beispiel #4
0
			void XMP_WinXP_HGQueue::Wait ( XMP_BasicMutex & queueMutex )
			{
				++this->waitCount;	// ! Does not need atomic increment, protected by queue mutex.
				ReleaseBasicMutex ( queueMutex );
				DWORD status = WaitForSingleObject ( this->queueEvent, INFINITE );
				if ( status != WAIT_OBJECT_0 ) XMP_Throw ( "Failure from WaitForSingleObject", kXMPErr_ExternalFailure );
				AcquireBasicMutex ( queueMutex );
				--this->waitCount;	// ! Does not need atomic decrement, protected by queue mutex.
		
				if ( this->releaseAll ) {
					if ( this->waitCount == 0 ) {
						this->releaseAll = false;
					} else {
						BOOL ok = SetEvent ( this->queueEvent );
						if ( ! ok ) XMP_Throw ( "Failure from SetEvent", kXMPErr_ExternalFailure );
					}
				}
			}
Beispiel #5
0
void PluginBase::FillAssociatedResources( std::vector<std::string> * resourceList ) 
{	
	XMP_OptionBits flags = this->mHandlerFlags;
	if ( (flags & kXMPFiles_HandlerOwnsFile) ||
		 (flags & kXMPFiles_UsesSidecarXMP) ||
		 (flags & kXMPFiles_FolderBasedFormat) ) {
			XMP_Throw ( "GetAssociatedResources is not implemented for this file format", kXMPErr_PluginFillAssociatedResources );
	}
	resourceList->push_back ( this->getPath() );
}
Beispiel #6
0
void GIF_MetaHandler::SeekFile( XMP_IO * fileRef, XMP_Int64 offset, SeekMode mode )
{
	if ( offset > fileRef->Length() || ( mode == kXMP_SeekFromCurrent && fileRef->Offset() + offset > fileRef->Length() ) )
	{
		XMP_Throw( "Out of range seek operation", kXMPErr_InternalFailure );
	}
	else
		fileRef->Seek( offset, mode );

}	// GIF_MetaHandler::SeekFile
Beispiel #7
0
void PluginBase::FillMetadataFiles( std::vector<std::string> * metadataFiles )
{
	XMP_OptionBits flags = this->mHandlerFlags;
	if ( (flags & kXMPFiles_UsesSidecarXMP) ||
		(flags & kXMPFiles_FolderBasedFormat) ) {
			XMP_Throw ( "Base implementation of FillMetadataFiles only for embedding handlers", kXMPErr_PluginFillMetadataFiles );
	}

	metadataFiles->push_back ( this->getPath() );
}
Beispiel #8
0
static XMP_Node *
AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr )
{
    if ( attr.ns.empty() ) {
        XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF );
    }

    return AddQualifierNode ( xmpParent, attr.name, attr.value );

}	// AddQualifierNode
Beispiel #9
0
void XMP_NamespaceTable::Dump ( XMP_TextOutputProc outProc, void * refCon ) const
{
	XMP_AutoLock tableLock ( &this->lock, kXMP_ReadLock );
	
	XMP_cStringMapPos p2uEnd = this->prefixToURIMap.end();	// ! Move up to avoid gcc complaints.
	XMP_cStringMapPos u2pEnd = this->uriToPrefixMap.end();
	
	DumpStringMap ( this->prefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon );
	
	if ( this->prefixToURIMap.size() != this->uriToPrefixMap.size() ) {
		OutProcLiteral ( "** bad namespace map sizes **" );
		XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
	}
	
	for ( XMP_cStringMapPos nsLeft = this->prefixToURIMap.begin(); nsLeft != p2uEnd; ++nsLeft ) {

		XMP_cStringMapPos nsOther = this->uriToPrefixMap.find ( nsLeft->second );
		if ( (nsOther == u2pEnd) || (nsLeft != this->prefixToURIMap.find ( nsOther->second )) ) {
			OutProcLiteral ( "  ** bad namespace URI **  " );
			DumpClearString ( nsLeft->second, outProc, refCon );
			break;
		}
		
		for ( XMP_cStringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) {
			if ( nsRight == nsLeft ) continue;	// ! Can't start at nsLeft+1, no operator+!
			if ( nsLeft->second == nsRight->second ) {
				OutProcLiteral ( "  ** duplicate namespace URI **  " );
				DumpClearString ( nsLeft->second, outProc, refCon );
				break;
			}
		}

	}
	
	for ( XMP_cStringMapPos nsLeft = this->uriToPrefixMap.begin(); nsLeft != u2pEnd; ++nsLeft ) {

		XMP_cStringMapPos nsOther = this->prefixToURIMap.find ( nsLeft->second );
		if ( (nsOther == p2uEnd) || (nsLeft != this->uriToPrefixMap.find ( nsOther->second )) ) {
			OutProcLiteral ( "  ** bad namespace prefix **  " );
			DumpClearString ( nsLeft->second, outProc, refCon );
			break;
		}

		for ( XMP_cStringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) {
			if ( nsRight == nsLeft ) continue;	// ! Can't start at nsLeft+1, no operator+!
			if ( nsLeft->second == nsRight->second ) {
				OutProcLiteral ( "  ** duplicate namespace prefix **  " );
				DumpClearString ( nsLeft->second, outProc, refCon );
				break;
			}
		}

	}

}	// XMP_NamespaceTable::Dump
Beispiel #10
0
void MetadataSet::removeAt( XMP_Uns32 pos )
{
	if( mMeta != NULL && pos < mMeta->size() )
	{
		mMeta->erase( mMeta->begin() + pos );
	}
	else
	{
		XMP_Throw( "Index out of range.", kXMPErr_BadIndex );
	}
}
Beispiel #11
0
bool ASF_MetaHandler::SafeWriteFile()
{
	XMP_IO* originalFile = this->parent->ioRef;
	XMP_IO* tempFile = originalFile->DeriveTemp();
	if ( tempFile == 0 ) XMP_Throw ( "Failure creating ASF temp file", kXMPErr_InternalFailure );

	this->WriteTempFile ( tempFile );
	originalFile->AbsorbTemp();

	return true;

} // ASF_MetaHandler::SafeWriteFile
Beispiel #12
0
static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs )
{
    XMP_Assert ( attrs != 0 );
    ExpatAdapter * thiz = (ExpatAdapter*)userData;

    size_t attrCount = 0;
    for ( XMP_StringPtr* a = attrs; *a != 0; ++a ) ++attrCount;
    if ( (attrCount & 1) != 0 )	XMP_Throw ( "Expat attribute info has odd length", kXMPErr_ExternalFailure );
    attrCount = attrCount/2;	// They are name/value pairs.

    #if XMP_DebugBuild & DumpXMLParseEvents
        if ( thiz->parseLog != 0 ) {
            PrintIndent ( thiz->parseLog, thiz->elemNesting );
            fprintf ( thiz->parseLog, "StartElement: %s, %d attrs", name, attrCount );
            for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
                XMP_StringPtr attrName = *attr;
                XMP_StringPtr attrValue = *(attr+1);
                fprintf ( thiz->parseLog, ", %s = \"%s\"", attrName, attrValue );
            }
            fprintf ( thiz->parseLog, "\n" );
        }
    #endif

    XML_Node * parentNode = thiz->parseStack.back();
    XML_Node * elemNode   = new XML_Node ( parentNode, "", kElemNode );

    SetQualName ( name, elemNode );

    for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {

        XMP_StringPtr attrName = *attr;
        XMP_StringPtr attrValue = *(attr+1);
        XML_Node * attrNode = new XML_Node ( elemNode, "", kAttrNode );

        SetQualName ( attrName, attrNode );
        attrNode->value = attrValue;
        if ( attrNode->name == "xml:lang" ) NormalizeLangValue ( &attrNode->value );
        elemNode->attrs.push_back ( attrNode );

    }

    parentNode->content.push_back ( elemNode );
    thiz->parseStack.push_back ( elemNode );

    if ( elemNode->name == "rdf:RDF" ) {
        thiz->rootNode = elemNode;
        ++thiz->rootCount;
    }
    #if XMP_DebugBuild
        ++thiz->elemNesting;
    #endif

}	// StartElementHandler
Beispiel #13
0
static void SetQualName ( XMP_StringPtr fullName, XML_Node * node )
{
    // Expat delivers the full name as a catenation of namespace URI, separator, and local name.

    // As a compatibility hack, an "about" or "ID" attribute of an rdf:Description element is
    // changed to "rdf:about" or rdf:ID. Easier done here than in the RDF recognizer.

    // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/.
    // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace.

    // ! This code presumes the RDF namespace prefix is "rdf".

    size_t sepPos = strlen(fullName);
    for ( --sepPos; sepPos > 0; --sepPos ) {
        if ( fullName[sepPos] == FullNameSeparator ) break;
    }

    if ( fullName[sepPos] == FullNameSeparator ) {

        XMP_StringPtr prefix;
        XMP_StringLen prefixLen;
        XMP_StringPtr localPart = fullName + sepPos + 1;

        node->ns.assign ( fullName, sepPos );
        if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/";

        bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &prefixLen );
        if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure );
        node->nsPrefixLen = prefixLen;	// ! Includes the ':'.

        node->name = prefix;
        node->name += localPart;

    } else {

        node->name = fullName;	// The name is not in a namespace.

        if ( node->parent->name == "rdf:Description" ) {
            if ( node->name == "about" ) {
                node->ns   = kXMP_NS_RDF;
                node->name = "rdf:about";
                node->nsPrefixLen = 4;	// ! Include the ':'.
            } else if ( node->name == "ID" ) {
                node->ns   = kXMP_NS_RDF;
                node->name = "rdf:ID";
                node->nsPrefixLen = 4;	// ! Include the ':'.
            }
        }

    }

}	// SetQualName
Beispiel #14
0
static void
RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
{
    XMP_Node * newChild = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );

    XML_cNodePos currAttr = xmlNode.attrs.begin();
    XML_cNodePos endAttr  = xmlNode.attrs.end();

    for ( ; currAttr != endAttr; ++currAttr ) {
        XMP_VarString & attrName = (*currAttr)->name;
        if ( attrName == "xml:lang" ) {
            AddQualifierNode ( newChild, **currAttr );
        } else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) {
            continue;	// Ignore all rdf:ID and rdf:datatype attributes.
        } else {
            XMP_Throw ( "Invalid attribute for literal property element", kXMPErr_BadRDF );
        }
    }

    XML_cNodePos currChild = xmlNode.content.begin();
    XML_cNodePos endChild  = xmlNode.content.end();
    size_t      textSize  = 0;

    for ( ; currChild != endChild; ++currChild ) {
        if ( (*currChild)->kind != kCDataNode ) XMP_Throw ( "Invalid child of literal property element", kXMPErr_BadRDF );
        textSize += (*currChild)->value.size();
    }

    newChild->value.reserve ( textSize );

    for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) {
        newChild->value += (*currChild)->value;
    }

    #if 0	// *** XMP_DebugBuild
        newChild->_valuePtr = newChild->value.c_str();
    #endif

}	// RDF_LiteralPropertyElement
Beispiel #15
0
PluginAPIRef Module::getPluginAPIs() 
{ 
	//
	// return ref. to Plugin API, load module if not yet loaded
	//
	if ( !mPluginAPIs || mLoaded != kModuleLoaded )
	{
		if ( !load() )
		{
			XMP_Throw ( "Plugin API not available.", kXMPErr_Unavailable );
		}
	}
	return mPluginAPIs;
}
Beispiel #16
0
static void ExportIPTC_Date ( XMP_Uns8 dateID, const SXMPMeta & xmp, IPTC_Manager * iptc )
{
	XMP_Uns8 timeID;
	XMP_StringPtr xmpNS, xmpProp;
	
	if ( dateID == kIPTC_DateCreated ) {
		timeID  = kIPTC_TimeCreated;
		xmpNS   = kXMP_NS_Photoshop;
		xmpProp = "DateCreated";
	} else if ( dateID == kIPTC_DigitalCreateDate ) {
		timeID  = kIPTC_DigitalCreateTime;
		xmpNS   = kXMP_NS_XMP;
		xmpProp = "CreateDate";
	} else {
		XMP_Throw ( "Unrecognized dateID", kXMPErr_BadParam );
	}

	iptc->DeleteDataSet ( dateID );	// ! Either the XMP does not exist and we want to 
	iptc->DeleteDataSet ( timeID );	// ! delete the IPTC, or we're replacing the IPTC.

	XMP_DateTime xmpValue;
	bool found = xmp.GetProperty_Date ( xmpNS, xmpProp, &xmpValue, 0 );
	if ( ! found ) return;

	char iimValue[16];	// AUDIT: Big enough for "YYYYMMDD" (8) and "HHMMSS+HHMM" (11).

	// Set the IIM date portion as YYYYMMDD with zeroes for unknown parts.
	
	snprintf ( iimValue, sizeof(iimValue), "%04d%02d%02d",	// AUDIT: Use of sizeof(iimValue) is safe.
			   xmpValue.year, xmpValue.month, xmpValue.day );

	iptc->SetDataSet_UTF8 ( dateID, iimValue, 8 );

	// Set the IIM time portion as HHMMSS+HHMM (or -HHMM). Allow a missing time zone.

	if ( xmpValue.hasTimeZone )  {
		snprintf ( iimValue, sizeof(iimValue), "%02d%02d%02d%c%02d%02d",	// AUDIT: Use of sizeof(iimValue) is safe.
				   xmpValue.hour, xmpValue.minute, xmpValue.second,
				   ((xmpValue.tzSign == kXMP_TimeWestOfUTC) ? '-' : '+'), xmpValue.tzHour, xmpValue.tzMinute );
		iptc->SetDataSet_UTF8 ( timeID, iimValue, 11 );
	} else if ( xmpValue.hasTime ) {
		snprintf ( iimValue, sizeof(iimValue), "%02d%02d%02d",	// AUDIT: Use of sizeof(iimValue) is safe.
				   xmpValue.hour, xmpValue.minute, xmpValue.second );
		iptc->SetDataSet_UTF8 ( timeID, iimValue, 6 );
	} else {
		iptc->DeleteDataSet ( timeID );
	}

}	// ExportIPTC_Date
Beispiel #17
0
static void
RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
{
    XML_cNodePos currChild = xmlParent.content.begin();
    XML_cNodePos endChild  = xmlParent.content.end();

    for ( ; currChild != endChild; ++currChild ) {
        if ( (*currChild)->IsWhitespaceNode() ) continue;
        if ( (*currChild)->kind != kElemNode ) {
            XMP_Throw ( "Expected property element node not found", kXMPErr_BadRDF );
        }
        RDF_PropertyElement ( xmpParent, **currChild, isTopLevel );
    }

}	// RDF_PropertyElementList
Beispiel #18
0
IMetadata* MetadataSet::getAt( XMP_Uns32 pos ) const
{
	IMetadata* ret = NULL;

	if( mMeta != NULL && pos < mMeta->size() )
	{
		ret = mMeta->at(pos);
	}
	else
	{
		XMP_Throw( "Index out of range.", kXMPErr_BadIndex );
	}

	return ret;
}
Beispiel #19
0
void PluginBase::FillAssociatedResources( StringVectorRef resourceList, SetStringVectorProc SetStringVector )
{
	if ( resourceList == 0 ) 
		XMP_Throw ( "A result file list vector must be provided", kXMPErr_BadParam );

	std::vector<std::string> resList;	// Pass a local vector, not the client's.
	(*SetStringVector)( resourceList, 0, 0 );	// Clear the client's result vector.
	FillAssociatedResources( &resList );

	if ( ! resList.empty() ) {
		const size_t fileCount = resList.size();
		std::vector<XMP_StringPtr> ptrArray;
		ptrArray.reserve ( fileCount );
		for ( size_t i = 0; i < fileCount; ++i ) {
			ptrArray.push_back ( resList[i].c_str() );
		}
		(*SetStringVector) ( resourceList, ptrArray.data(), (XMP_Uns32)fileCount );
	}
}
void XMP_ProgressTracker::NotifyClient ( bool isStartStop )
{
	XMP_Bool ok = !kXMP_Bool_False;
	float fractionDone = 0.0;
	
	if ( this->cbInfo.clientProc == 0 ) return;
	XMP_Assert ( this->cbInfo.wrapperProc != 0 );
	XMP_Assert ( (this->totalWork >= 0.0) && (this->workDone >= 0.0) && (this->cbInfo.interval >= 0.0) );
	// ! Note that totalWork might be unknown or understimated, and workDone greater than totalWork.
	
	if ( isStartStop ) {

		float totalTime = 0.0;
		if ( this->workDone > 0.0 ) {
			fractionDone = 1.0;	// This is the stop call.
			totalTime = PerfUtils::GetElapsedSeconds ( this->startTime, PerfUtils::NoteThisMoment() );
		}
		ok = (*this->cbInfo.wrapperProc ) ( this->cbInfo.clientProc, this->cbInfo.context,
											totalTime, fractionDone, 0.0 );

	} else {

		PerfUtils::MomentValue currentTime = PerfUtils::NoteThisMoment();
		float elapsedTime = PerfUtils::GetElapsedSeconds ( this->prevTime, currentTime );
		if ( elapsedTime < this->cbInfo.interval ) return;

		float remainingTime = 0.0;
		if ( (this->totalWork > 0.0) && (this->workDone > 0.0) ) {
			fractionDone = this->workDone / this->totalWork;
			if ( fractionDone > 1.0 ) fractionDone = 1.0;
			elapsedTime = PerfUtils::GetElapsedSeconds ( this->startTime, currentTime );
			remainingTime = (elapsedTime / fractionDone) * (1.0 - fractionDone);
		}

		this->prevTime = currentTime;
		ok = (*this->cbInfo.wrapperProc ) ( this->cbInfo.clientProc, this->cbInfo.context,
											elapsedTime, fractionDone, remainingTime );

	}

	if ( ok == kXMP_Bool_False ) XMP_Throw ( "Abort signaled by progress reporting callback", kXMPErr_ProgressAbort );
		
}	// XMP_ProgressTracker::NotifyClient
Beispiel #21
0
bool PluginBase::IsMetadataWritable ( )
{
	XMP_OptionBits flags = this->getHandlerFlags();
	const std::string & filePath = this->getPath();
	
	if ( (flags & kXMPFiles_HandlerOwnsFile)   ||
		 (flags & kXMPFiles_UsesSidecarXMP)    ||
		 (flags & kXMPFiles_FolderBasedFormat) ||
		 filePath.empty() )
	{
		XMP_Throw ( "IsMetadataWritable is not implemented for this file format", kXMPErr_PluginIsMetadataWritable );
	}

	try {
		return Host_IO::Writable( this->getPath().c_str() );
	} catch ( ... ) {

	}
	return false;
}
Beispiel #22
0
// parsing creation
Chunk::Chunk( ContainerChunk* parent_, RIFF_MetaHandler* handler, bool skip, ChunkType c )
{
	chunkType = c; // base class assumption
	this->parent = parent_;
	this->oldSize = 0;
	this->hasChange = false; // [2414649] valid assumption at creation time

	XMP_IO* file = handler->parent->ioRef;

	this->oldPos = file->Offset();
	this->id = XIO::ReadUns32_LE( file );
	this->oldSize = XIO::ReadUns32_LE( file );
	this->oldSize += 8;

	// Make sure the size is within expected bounds.
	XMP_Int64 chunkEnd = this->oldPos + this->oldSize;
	XMP_Int64 chunkLimit = handler->oldFileSize;
	if ( parent_ != 0 ) chunkLimit = parent_->oldPos + parent_->oldSize;
	if ( chunkEnd > chunkLimit ) {
		bool isUpdate = XMP_OptionIsSet ( handler->parent->openFlags, kXMPFiles_OpenForUpdate );
		bool repairFile = XMP_OptionIsSet ( handler->parent->openFlags, kXMPFiles_OpenRepairFile );
		if ( (! isUpdate) || (repairFile && (parent_ == 0)) ) {
			this->oldSize = chunkLimit - this->oldPos;
		} else {
			XMP_Throw ( "Bad RIFF chunk size", kXMPErr_BadFileFormat );
		}
	}

	this->newSize = this->oldSize;
	this->needSizeFix = false;

	if ( skip ) file->Seek ( (this->oldSize - 8), kXMP_SeekFromCurrent );

	// "good parenting", essential for latter destruction.
	if ( this->parent != NULL )
	{
		this->parent->children.push_back( this );
		if( this->chunkType == chunk_VALUE )
			this->parent->childmap.insert( std::make_pair( this->id, (ValueChunk*) this ) );
	}
}
const TIFF_MemoryReader::TweakedIFDEntry* TIFF_MemoryReader::FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const
{
	if ( ifd == kTIFF_KnownIFD ) {
		// ... lookup the tag in the known tag map
	}

	if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
	const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];

	if ( thisIFD->count == 0 ) return 0;

	XMP_Uns32 spanLength = thisIFD->count;
	const TweakedIFDEntry* spanBegin = &(thisIFD->entries[0]);

	while ( spanLength > 1 ) {

		XMP_Uns32 halfLength = spanLength >> 1;	// Since spanLength > 1, halfLength > 0.
		const TweakedIFDEntry* spanMiddle = spanBegin + halfLength;

		// There are halfLength entries below spanMiddle, then the spanMiddle entry, then
		// spanLength-halfLength-1 entries above spanMiddle (which can be none).

		XMP_Uns16 middleID = GetUns16AsIs ( &spanMiddle->id );
		if ( middleID == id ) {
			spanBegin = spanMiddle;
			break;
		} else if ( middleID > id ) {
			spanLength = halfLength;	// Discard the middle.
		} else {
			spanBegin = spanMiddle;	// Keep a valid spanBegin for the return check, don't use spanMiddle+1.
			spanLength -= halfLength;
		}

	}

	if ( GetUns16AsIs(&spanBegin->id) != id ) spanBegin = 0;
	return spanBegin;

}	// TIFF_MemoryReader::FindTagInIFD
XMP_Uns32 XMPFiles_IO::Read ( void * buffer, XMP_Uns32 count, bool readAll /* = false */ )
{
    XMP_FILESIO_START
    XMP_Assert ( this->fileRef != Host_IO::noFileRef );
    XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
    XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
    XMP_Assert ( this->currOffset <= this->currLength );

    if ( count > (this->currLength - this->currOffset) ) {
        if ( readAll ) XMP_Throw ( "XMPFiles_IO::Read, not enough data", kXMPErr_EnforceFailure );
        count = (XMP_Uns32) (this->currLength - this->currOffset);
    }

    XMP_Uns32 amountRead = Host_IO::Read ( this->fileRef, buffer, count );
    XMP_Enforce ( amountRead == count );

    this->currOffset += amountRead;
    return amountRead;
    XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
    return 0;

}	// XMPFiles_IO::Read
void XMPFiles_IO::Truncate ( XMP_Int64 length )
{
    XMP_FILESIO_START
    XMP_Assert ( this->fileRef != Host_IO::noFileRef );
    XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
    XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );

    if ( this->readOnly )
        XMP_Throw ( "New_XMPFiles_IO, truncate not permitted on read only file", kXMPErr_FilePermission );

    XMP_Enforce ( length <= this->currLength );
    Host_IO::SetEOF ( this->fileRef, length );

    this->currLength = length;
    if ( this->currOffset > this->currLength ) this->currOffset = this->currLength;

    // ! Seek to the expected offset, some versions of Host_IO::SetEOF implicitly seek to EOF.
    Host_IO::Seek ( this->fileRef, this->currOffset, kXMP_SeekFromStart );
    XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
    XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )

}	// XMPFiles_IO::Truncate
void XMPFiles_IO::AbsorbTemp()
{
    XMP_FILESIO_START
    XMP_Assert ( this->fileRef != Host_IO::noFileRef );

    XMPFiles_IO * temp = this->derivedTemp;
    if ( temp == 0 ) {
        XMP_Throw ( "XMPFiles_IO::AbsorbTemp, no temp to absorb", kXMPErr_InternalFailure );
    }
    XMP_Assert ( temp->isTemp );

    this->Close();
    temp->Close();

    Host_IO::SwapData ( this->filePath.c_str(), temp->filePath.c_str() );
    this->DeleteTemp();

    this->fileRef = Host_IO::Open ( this->filePath.c_str(), Host_IO::openReadWrite );
    this->currLength = Host_IO::Length ( this->fileRef );
    this->currOffset = 0;
    XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )

}	// XMPFiles_IO::AbsorbTemp
Beispiel #27
0
void MOOV_Manager::ParseMemoryTree ( XMP_Uns8 fileMode1 )
{
	this->fileMode = fileMode1;
	
	this->moovNode.offset = this->moovNode.boxType = 0;
	this->moovNode.headerSize = this->moovNode.contentSize = 0;
	this->moovNode.children.clear();
	this->moovNode.changedContent.clear();
	this->moovNode.changed = false;

	if ( this->fullSubtree.empty() ) return;
	
	ISOMedia::BoxInfo moovInfo;
	const XMP_Uns8 * moovOrigin = &this->fullSubtree[0];
	const XMP_Uns8 * moovLimit  = moovOrigin + this->fullSubtree.size();

	(void) ISOMedia::GetBoxInfo ( moovOrigin, moovLimit, &moovInfo );
	XMP_Enforce ( moovInfo.boxType == ISOMedia::k_moov );
	
	XMP_Uns64 fullMoovSize = moovInfo.headerSize + moovInfo.contentSize;
	if ( fullMoovSize > moovBoxSizeLimit ) {	// From here on we know 32-bit offsets are safe.
		XMP_Throw ( "Oversize 'moov' box", kXMPErr_EnforceFailure );
	}
	
	this->moovNode.boxType = ISOMedia::k_moov;
	this->moovNode.headerSize = moovInfo.headerSize;
	this->moovNode.contentSize = (XMP_Uns32)moovInfo.contentSize;

	bool ignoreMetaBoxes = (fileMode1 == kFileIsTraditionalQT);	// ! Don't want, these don't follow ISO spec.
	#if TraceParseMoovTree
		fprintf ( stderr, "Parsing 'moov' subtree, moovNode @ 0x%X, ignoreMetaBoxes = %d\n",
				  &this->moovNode, ignoreMetaBoxes );
	#endif
	this->ParseNestedBoxes ( &this->moovNode, "moov", ignoreMetaBoxes );
	
}	// MOOV_Manager::ParseMemoryTree
Beispiel #28
0
void PluginBase::FillMetadataFiles( StringVectorRef metadataFiles, SetStringVectorProc SetStringVector )
{
	if ( metadataFiles == 0 ) 
		XMP_Throw ( "A result file list vector must be provided", kXMPErr_BadParam );

	std::vector<std::string> fileList;	// Pass a local vector, not the client's.
	(*SetStringVector)( metadataFiles, 0, 0 );	// Clear the client's result vector.
	FillMetadataFiles( &fileList );

	// since we are dealing with STL ojbects across different DLL boundaries,
	// we are extracting const char* to actual path strings, constructing a vector
	// using these pointers and then passing the address of the underlying data
	// to the clients procedure which will repopulate its own vector of strings
	// using this information.
	if ( ! fileList.empty() ) {
		const size_t fileCount = fileList.size();
		std::vector<XMP_StringPtr> ptrArray;
		ptrArray.reserve ( fileCount );
		for ( size_t i = 0; i < fileCount; ++i ) {
			ptrArray.push_back ( fileList[i].c_str() );
		}
		(*SetStringVector) ( metadataFiles, ptrArray.data(), (XMP_Uns32)fileCount );
	}
}
Beispiel #29
0
XMPIterator::XMPIterator ( const XMPMeta & xmpObj,
						   XMP_StringPtr   schemaNS,
						   XMP_StringPtr   propName,
						   XMP_OptionBits  options ) : clientRefs(0), info(IterInfo(options,&xmpObj))
{
	if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
		XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
	}
	
	// *** Lock the XMPMeta object if we ever stop using a full DLL lock.

	if ( *propName != 0 ) {

		// An iterator rooted at a specific node.

		#if TraceIterators
			printf ( "\nNew XMP property iterator for \"%s\", options = %X\n    Schema = %s, root = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS, propName );
		#endif
		
		XMP_ExpandedXPath propPath;
		ExpandXPath ( schemaNS, propName, &propPath );
		XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath );	// If not found get empty iteration.
		
		if ( propNode != 0 ) {

			XMP_VarString rootName ( propPath[1].step );	// The schema is [0].
			for ( size_t i = 2; i < propPath.size(); ++i ) {
				XMP_OptionBits stepKind = GetStepKind ( propPath[i].options );
				if ( stepKind <= kXMP_QualifierStep ) rootName += '/';
				rootName += propPath[i].step;
			}

			propName = rootName.c_str();
			size_t leafOffset = rootName.size();
			while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset;
			if ( propName[leafOffset] == '/' ) ++leafOffset;

			info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) );
			SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() );
			if ( info.options & kXMP_IterJustChildren ) {
				AddNodeOffspring ( info, info.tree.children.back(), propNode );
			}

		}
	
	} else if ( *schemaNS != 0 ) {

		// An iterator for all properties in one schema.
		
		#if TraceIterators
			printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n    Schema = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS );
		#endif
		
		info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) );
		IterNode & iterSchema = info.tree.children.back();
		
		XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS );
		if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema );
		
		if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS );
		
		if ( iterSchema.children.empty() ) {
			info.tree.children.pop_back();	// No properties, remove the schema node.
		} else {
			SetCurrSchema ( info, schemaNS );
		}
	
	} else {

		// An iterator for all properties in all schema. First add schema that exist (have children),
		// adding aliases from them if appropriate. Then add schema that have no actual properties
		// but do have aliases to existing properties, if we're including aliases in the iteration.
		
		#if TraceIterators
			printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n",
			         xmpObj.tree.name.c_str(), options );
		#endif
		
		// First pick up the schema that exist.
		
		for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {

			const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum];
			info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) );
			IterNode & iterSchema = info.tree.children.back();

			if ( ! (info.options & kXMP_IterJustChildren) ) {
				AddSchemaProps ( info, iterSchema, xmpSchema );
				if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() );
				if ( iterSchema.children.empty() ) info.tree.children.pop_back();	// No properties, remove the schema node.
			}

		}
		
		if ( info.options & kXMP_IterIncludeAliases ) {

			// Add the schema that only have aliases. The most convenient, and safest way, is to go
			// through the registered namespaces, see if it exists, and let AddSchemaAliases do its
			// thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff
			// be in storage order (not subject to the namespace map order).
			
			// ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The
			// ! existing schema (presumably) have actual children. We need to call AddSchemaAliases
			// ! here to determine if the namespace has any aliases to existing properties. We then
			// ! strip the children if necessary.

			XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin();
			XMP_cStringMapPos endNS  = sNamespaceURIToPrefixMap->end();
			for ( ; currNS != endNS; ++currNS ) {
				XMP_StringPtr schemaName = currNS->first.c_str();
				if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue;
				info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) );
				IterNode & iterSchema = info.tree.children.back();
				AddSchemaAliases ( info, iterSchema, schemaName );
				if ( iterSchema.children.empty() ) {
					info.tree.children.pop_back();	// No aliases, remove the schema node.
				} else if ( info.options & kXMP_IterJustChildren ) {
					iterSchema.children.clear();	// Get rid of the children.
				}
			}

		}

	}
	
	// Set the current iteration position to the first node to be visited.
	
	info.currPos = info.tree.children.begin();
	info.endPos  = info.tree.children.end();
	
	if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) {
		info.currPos->visitStage = kIter_VisitSelf;
	}

	#if TraceIterators
		if ( info.currPos == info.endPos ) {
			printf ( "    ** Empty iteration **\n" );
		} else {
			printf ( "    Initial node %s, stage = %s, iterator @ %.8X\n",
			         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
		}
	#endif
	
}	// XMPIterator for XMPMeta objects
Beispiel #30
0
			void XMP_WinXP_HGQueue::ReleaseAll()
			{
				this->releaseAll = true;
				BOOL ok = SetEvent ( this->queueEvent );
				if ( ! ok ) XMP_Throw ( "Failure from SetEvent", kXMPErr_ExternalFailure );
			}