Exemplo n.º 1
0
void PSIR_FileWriter::ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length )
{
	bool ok;

	this->DeleteExistingInfo();
	this->fileParsed = true;
	if ( length == 0 ) return;

	// Parse the image resource block.

	IOBuffer ioBuf;
	ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_CUR );

	XMP_Int64 psirOrigin = ioBuf.filePos;	// Need this to determine the resource data offsets.
	XMP_Int64 fileEnd = ioBuf.filePos + length;

	std::string rsrcPName;

	while ( (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)) < fileEnd ) {

		ok = CheckFileSpace ( fileRef, &ioBuf, 12 );	// The minimal image resource takes 12 bytes.
		if ( ! ok ) break;	// Bad image resource. Throw instead?

		XMP_Int64 thisRsrcPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);

		XMP_Uns32 type = GetUns32BE(ioBuf.ptr);
		XMP_Uns16 id   = GetUns16BE(ioBuf.ptr+4);
		ioBuf.ptr += 6;	// Advance to the resource name.

		XMP_Uns16 nameLen = ioBuf.ptr[0];	// ! The length for the Pascal string.
		XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE;	// ! Round up to an even total. Yes, +2!
		ok = CheckFileSpace ( fileRef, &ioBuf, paddedLen+4 );	// Get the name text and the data length.
		if ( ! ok ) break;	// Bad image resource. Throw instead?

		if ( nameLen > 0 ) rsrcPName.assign ( (char*)(ioBuf.ptr), paddedLen );	// ! Include the length byte and pad.

		ioBuf.ptr += paddedLen;	// Move to the data length.
		XMP_Uns32 dataLen   = GetUns32BE(ioBuf.ptr);
		XMP_Uns32 dataTotal = ((dataLen + 1) & 0xFFFFFFFEUL);	// Round up to an even total.
		ioBuf.ptr += 4;	// Advance to the resource data.

		XMP_Int64 thisDataPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);
		XMP_Int64 nextRsrcPos = thisDataPos + dataTotal;

		if ( type != k8BIM ) {
			XMP_Uns32 fullRsrcLen = (XMP_Uns32) (nextRsrcPos - thisRsrcPos);
			this->otherRsrcs.push_back ( OtherRsrcInfo ( (XMP_Uns32)thisRsrcPos, fullRsrcLen ) );
			MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
			continue;
		}

		InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, dataLen, kIsFileBased ) );
		InternalRsrcMap::iterator newRsrc = this->imgRsrcs.insert ( this->imgRsrcs.end(), mapValue );
		InternalRsrcInfo* rsrcPtr = &newRsrc->second;

		rsrcPtr->origOffset = (XMP_Uns32)thisDataPos;

		if ( nameLen > 0 ) {
			rsrcPtr->rsrcName = (XMP_Uns8*) malloc ( paddedLen );
			if ( rsrcPtr->rsrcName == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
			memcpy ( (void*)rsrcPtr->rsrcName, rsrcPName.c_str(), paddedLen );	// AUDIT: Safe, allocated enough bytes above.
		}

		if ( ! IsMetadataImgRsrc ( id ) ) {
			MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
			continue;
		}

		rsrcPtr->dataPtr = malloc ( dataLen );	// ! Allocate after the IsMetadataImgRsrc check.
		if ( rsrcPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );

		if ( dataTotal <= kIOBufferSize ) {
			// The image resource data fits within the I/O buffer.
			ok = CheckFileSpace ( fileRef, &ioBuf, dataTotal );
			if ( ! ok ) break;	// Bad image resource. Throw instead?
			memcpy ( (void*)rsrcPtr->dataPtr, ioBuf.ptr, dataLen );	// AUDIT: Safe, malloc'ed dataLen bytes above.
			ioBuf.ptr += dataTotal;	// ! Add the rounded length.
		} else {
			// The image resource data is bigger than the I/O buffer.
			LFA_Seek ( fileRef, (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)), SEEK_SET );
			LFA_Read ( fileRef, (void*)rsrcPtr->dataPtr, dataLen );
			FillBuffer ( fileRef, nextRsrcPos, &ioBuf );
		}

	}

	#if 0
	{
		printf ( "\nPSIR_FileWriter::ParseFileResources, count = %d\n", this->imgRsrcs.size() );
		InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
		InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
		for ( ; irPos != irEnd; ++irPos ) {
			InternalRsrcInfo& thisRsrc = irPos->second;
			printf ( "  #%d, dataLen %d, origOffset %d (0x%X)%s\n",
					 thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
					 (thisRsrc.changed ? ", changed" : "") );
		}
	}
	#endif

}	// PSIR_FileWriter::ParseFileResources
Exemplo n.º 2
0
void PSIR_FileWriter::ParseFileResources ( XMP_IO* fileRef, XMP_Uns32 length )
{
	// Parse the image resource block. We're using a map keyed by ID, so only one resource of each
	// ID is recognized. Redundant resources are not legit, but have been seen in the field. In
	// particular, one case has been seen of a duplicate IIM block with one empty. In general we
	// keep the first seen copy to be compatible with Photoshop. A later non-empty copy will be
	// taken though if the current one is empty.
	
	// ! Don't use map[id] to lookup, that creates a default entry if none exists!
	
	// PSIR layout:
	//	- Uns32 type, usually '8BIM'
	//	- Uns16 ID
	//	- PString name
	//	- Uns8 optional pad for even alignment
	//	- Uns32 data size
	//	- data
	//	- Uns8 optional pad for even alignment

	static const size_t kMinPSIRSize = 12;	// 4+2+1+1+4
	
	this->DeleteExistingInfo();
	this->fileParsed = true;
	if ( length == 0 ) return;

	XMP_Int64 psirOrigin = fileRef->Offset();	// Need this to determine the resource data offsets.
	XMP_Int64 fileEnd = psirOrigin + length;

	char nameBuffer [260];	// The name is a PString, at 1+255+1 including length and pad.

	while ( fileRef->Offset() < fileEnd ) {

		if ( ! XIO::CheckFileSpace ( fileRef, kMinPSIRSize ) ) break;	// Bad image resource.

		XMP_Int64 thisRsrcPos = fileRef->Offset();

		XMP_Uns32 type = XIO::ReadUns32_BE ( fileRef );
		XMP_Uns16 id   = XIO::ReadUns16_BE ( fileRef );

		XMP_Uns8 nameLen = XIO::ReadUns8 ( fileRef );	// ! The length for the Pascal string.
		XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE;	// ! Round up to an even total. Yes, +2!
		if ( ! XIO::CheckFileSpace ( fileRef, paddedLen+4 ) ) break;	// Bad image resource.

		nameBuffer[0] = nameLen;
		fileRef->ReadAll ( &nameBuffer[1], paddedLen-1 );	// Include the pad byte, present for zero nameLen.

		XMP_Uns32 dataLen   = XIO::ReadUns32_BE ( fileRef );
		XMP_Uns32 dataTotal = ((dataLen + 1) & 0xFFFFFFFEUL);	// Round up to an even total.
		if ( ! XIO::CheckFileSpace ( fileRef, dataTotal ) ) break;	// Bad image resource.

		XMP_Int64 thisDataPos = fileRef->Offset();
		XMP_Int64 nextRsrcPos = thisDataPos + dataTotal;

		if ( type != k8BIM ) {
			XMP_Uns32 fullRsrcLen = (XMP_Uns32) (nextRsrcPos - thisRsrcPos);
			this->otherRsrcs.push_back ( OtherRsrcInfo ( (XMP_Uns32)thisRsrcPos, fullRsrcLen ) );
			fileRef->Seek ( nextRsrcPos, kXMP_SeekFromStart );
			continue;
		}

		InternalRsrcInfo newInfo ( id, dataLen, kIsFileBased );
		InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
		if ( rsrcPos == this->imgRsrcs.end() ) {
			rsrcPos = this->imgRsrcs.insert ( rsrcPos, InternalRsrcMap::value_type ( id, newInfo ) );
		} else if ( (rsrcPos->second.dataLen == 0) && (newInfo.dataLen != 0) ) {
			rsrcPos->second = newInfo;
		} else {
			fileRef->Seek ( nextRsrcPos, kXMP_SeekFromStart );
			continue;
		}
		InternalRsrcInfo* rsrcPtr = &rsrcPos->second;

		rsrcPtr->origOffset = (XMP_Uns32)thisDataPos;

		if ( nameLen > 0 ) {
			rsrcPtr->rsrcName = (XMP_Uns8*) malloc ( paddedLen );
			if ( rsrcPtr->rsrcName == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
			memcpy ( (void*)rsrcPtr->rsrcName, nameBuffer, paddedLen );	// AUDIT: Safe, allocated enough bytes above.
		}

		if ( ! IsMetadataImgRsrc ( id ) ) {
			fileRef->Seek ( nextRsrcPos, kXMP_SeekFromStart );
			continue;
		}

		rsrcPtr->dataPtr = malloc ( dataTotal );	// ! Allocate after the IsMetadataImgRsrc check.
		if ( rsrcPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
		fileRef->ReadAll ( (void*)rsrcPtr->dataPtr, dataTotal );

	}

	#if 0
	{
		printf ( "\nPSIR_FileWriter::ParseFileResources, count = %d\n", this->imgRsrcs.size() );
		InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
		InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
		for ( ; irPos != irEnd; ++irPos ) {
			InternalRsrcInfo& thisRsrc = irPos->second;
			printf ( "  #%d, dataLen %d, origOffset %d (0x%X)%s\n",
					 thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
					 (thisRsrc.changed ? ", changed" : "") );
		}
	}
	#endif

}	// PSIR_FileWriter::ParseFileResources