Exemple #1
0
ChunkPath::ChunkPath( const ChunkPath& path )
{
	for( XMP_Int32 i=0; i<path.length(); i++ )
	{
		this->append( path.identifier(i) );
	}
}
void ChunkController::findChunks( const ChunkPath& path, ChunkPath& currentPath, const Chunk& chunk )
{
	if( path.length() > currentPath.length() )
	{
		for( XMP_Uns32 i=0; i<chunk.numChildren(); i++ )
		{
			Chunk* child = NULL;

			try
			{
				child = chunk.getChildAt(i);
			}
			catch(...)
			{
				child = NULL;
			}

			if( child != NULL )
			{
				currentPath.append( child->getIdentifier() );

				switch( path.match( currentPath ) )
				{
					case ChunkPath::kFullMatch:
					{
						mSearchResults.push_back( child );
					}
					break;

					case ChunkPath::kPartMatch:
					{
						this->findChunks( path, currentPath, *child );
					}
					break;

					case ChunkPath::kNoMatch:
					{
						// Nothing to do
					}
					break; 
				}

				currentPath.remove();
			}
		}
	}
}//findChunks
Exemple #3
0
ChunkPath::MatchResult ChunkPath::match( const ChunkPath& path ) const
{
	MatchResult ret			= kNoMatch;

	if( path.length() > 0 )
	{
		XMP_Int32 depth			= ( this->length() > path.length() ? path.length() : this->length() );
		XMP_Int32 matchCount	= 0;

		for( XMP_Int32 i=0; i<depth; i++ )
		{
			const ChunkIdentifier& id1 = this->identifier(i);
			const ChunkIdentifier& id2 = path.identifier(i);

			if( id1.id == id2.id )
			{
				if( i == this->length() - 1 && id1.type == kType_NONE )
				{
					matchCount++;
				}
				else if( id1.type == id2.type )
				{
					matchCount++;
				}
			}
			else
				break;
		}

		if( matchCount == depth )
		{
			ret = ( path.length() >= this->length() ? kFullMatch : kPartMatch );
		}
	}

	return ret;
}
void ChunkController::parseChunks( XMP_IO* stream, ChunkPath& currentPath, XMP_OptionBits* options /* = NULL */, Chunk* parent /* = NULL */)
{
	XMP_Uns64 filePos 		= stream->Offset();
	XMP_Bool isRoot			= (parent == mRoot);
	XMP_Uns64 parseLimit	= mFileSize;
	XMP_Uns32 chunkCnt		= 0; 

	XMP_Validate( mRoot != NULL, "ERROR inserting Chunk. mRoot is NULL.", kXMPErr_InternalFailure );
	XMP_Assert(dynamic_cast<Chunk*>(mRoot) == static_cast<Chunk*>(mRoot));
	parent = ( parent == NULL ? dynamic_cast<Chunk*>(mRoot) : parent );

	//
	// calculate the parse limit
	//
	if ( !isRoot )
	{
		parseLimit = parent->getOriginalOffset() + parent->getSize( true );

		if( parseLimit > mFileSize )
		{
			parseLimit = mFileSize;
		}
	}

	while ( filePos < parseLimit )
	{
		XMP_Uns64 fileTail = mFileSize - filePos;

		//
		// check if there is enough space (at least for id and size)
		//
		if ( fileTail < Chunk::HEADER_SIZE )
		{
			//preserve rest of bytes (fileTail)
			mTrailingGarbageOffset = filePos;
			mTrailingGarbageSize = fileTail;
			break; // stop parsing
		}
		else
		{
			bool chunkJump = false;

			//
			// create a new Chunk
			//
			Chunk* chunk = Chunk::createChunk(* mEndian );
			
			bool readFailure = false;
			//
			// read the Chunk (id, size, [type]) without caching the data
			//
			try
			{
				chunk->readChunk( stream );
			}
			catch( ... )
			{
				// remember exception during reading the chunk
				readFailure = true;
			}

			//
			// validate chunk ID for top-level chunks
			//
			if( isRoot && ! mChunkBehavior->isValidTopLevelChunk( chunk->getIdentifier(), chunkCnt ) )
			{
				// notValid: preserve rest of bytes (fileTail)
				mTrailingGarbageOffset = filePos;
				mTrailingGarbageSize = fileTail;
				//delete unused chunk (because these are undefined trailing bytes)
				delete chunk; 
				break; // stop parsing
			}
			else if ( readFailure )
			{
				delete chunk;
				XMP_Throw ( "Bad RIFF chunk", kXMPErr_BadFileFormat );
			}

			//
			// parenting 
			// (as early as possible in order to be able to clean up 
			// the tree correctly in the case of an exception)
			//
			parent->appendChild(chunk, false);

			// count top-level chunks
			if( isRoot )
			{
				chunkCnt++;
			}

			//
			// check size if value exceeds 4GB border
			//
			if( chunk->getSize() >= 0x00000000FFFFFFFFLL )
			{
				// remember file position
				XMP_Int64 currentFilePos = stream->Offset();

				// ask for the "real" size value
				XMP_Uns64 realSize = mChunkBehavior->getRealSize( chunk->getSize(), 
																  chunk->getIdentifier(),
																  *mRoot,
																  stream );

				// set new size at chunk
				chunk->setSize( realSize, true );

				// set flag if the file position changed
				chunkJump = currentFilePos < stream->Offset();
			}

			//
			// Repair if needed
			//
			if ( filePos + chunk->getSize(true) > mFileSize )
			{
				bool isUpdate =		( options != NULL ? XMP_OptionIsSet ( *options, kXMPFiles_OpenForUpdate ) : false );
				bool repairFile =	( options != NULL ? XMP_OptionIsSet ( *options, kXMPFiles_OpenRepairFile ) : false );

				if ( ( ! isUpdate ) || ( repairFile && isRoot ) ) 
				{
					chunk->setSize( mFileSize-filePos-Chunk::HEADER_SIZE, true );
				} 
				else 
				{
					XMP_Throw ( "Bad RIFF chunk size", kXMPErr_BadFileFormat );
				}
			}

			// extend search path
			currentPath.append( chunk->getIdentifier() );

			// first 4 bytes might be already read by the chunk->readChunk function
			XMP_Uns64 offsetOfChunkRead = stream->Offset() -  filePos - Chunk::HEADER_SIZE;

			switch ( compareChunkPaths(currentPath) )
			{
				case ChunkPath::kFullMatch :
				{
					chunk->cacheChunkData( stream );
				}
				break;

				case ChunkPath::kPartMatch :
				{
					parseChunks( stream, currentPath, options, chunk);
					// recalculate the size based on the sizes of its children
					chunk->calculateSize( true );
				}
				break;

				case ChunkPath::kNoMatch :
				{
					// Not a chunk we are interested in, so mark it as not changed
					// It will then be ignored by any further logic
					chunk->resetChanges();

					if ( !chunkJump && chunk->getSize() > 0) // if chunk not empty
					{
						XMP_Validate( stream->Offset() + chunk->getSize() - offsetOfChunkRead <= mFileSize , "ERROR: want's to skip beyond EOF", kXMPErr_InternalFailure);
						stream->Seek ( chunk->getSize() - offsetOfChunkRead , kXMP_SeekFromCurrent );
					}
				}
				break;
			}

			// remove last identifier from current path
			currentPath.remove();

			// update current file position
			filePos = stream->Offset();

			// skip pad byte if there is one (if size odd)
			if( filePos < mFileSize &&
				( ( chunkJump && ( stream->Offset() & 1 ) > 0 ) ||
				( !chunkJump && ( chunk->getSize() & 1 ) > 0 ) ) )
			{
				stream->Seek ( 1 , kXMP_SeekFromCurrent );
				filePos++;
			}
		}
	}
}