Exemple #1
0
bool ID3v2Frame::advancePastCOMMDescriptor ( XMP_Int32& pos )
{

		if ( (this->contentSize - pos) <= 3 ) return false; // silent error, no room left behing language tag
		if ( ! CheckBytes ( &this->content[pos], "eng", 3 ) ) return false; // not an error, but leave all non-eng tags alone...

		pos += 3; // skip lang tag
		if ( pos >= this->contentSize ) return false; // silent error

		while ( pos < this->contentSize ) {
			if ( this->content[pos++] == 0x00 ) break;
		}
		if ( (pos < this->contentSize) && (this->content[pos] == 0x00) ) pos++;

		if ( (pos == 5) && (this->contentSize == 6) && (GetUns16BE(&this->content[4]) == 0x0031) ) {
			return false;
		}

		if ( pos > 4 ) {
			std::string descriptor = std::string ( &this->content[4], pos-1 );
			if ( 0 == descriptor.substr(0,4).compare( "iTun" ) ) {	// begins with engiTun ?
				return false; // leave alone, then
			}
		}

		return true; //o.k., descriptor skipped, time for the real thing.

}	// ID3v2Frame::advancePastCOMMDescriptor
Exemple #2
0
XMP_Int64 ID3v2Frame::read ( XMP_IO* file, XMP_Uns8 majorVersion )
{
	XMP_Assert ( (2 <= majorVersion) && (majorVersion <= 4) );

	this->release(); // ensures/allows reuse of 'curFrame'
	XMP_Int64 start = file->Offset();
	
	if ( majorVersion > 2 ) {
		file->ReadAll ( this->fields, kV23_FrameHeaderSize );
	} else {
		// Read the 6 byte v2.2 header into the 10 byte form.
		memset ( this->fields, 0, kV23_FrameHeaderSize );	// Clear all of the bytes.
		file->ReadAll ( &this->fields[o_id], 3 );		// Leave the low order byte as zero.
		file->ReadAll ( &this->fields[o_size+1], 3 );	// Read big endian UInt24.
	}

	this->id = GetUns32BE ( &this->fields[o_id] );

	if ( this->id == 0 ) {
		file->Seek ( start, kXMP_SeekFromStart );	// Zero ID must mean nothing but padding.
		return 0;
	}

	this->flags = GetUns16BE ( &this->fields[o_flags] );
	XMP_Validate ( (0 == (this->flags & 0xEE)), "invalid lower bits in frame flags", kXMPErr_BadFileFormat );

	//*** flag handling, spec :429ff aka line 431ff  (i.e. Frame should be discarded)
	//  compression and all of that..., unsynchronisation
	this->contentSize = GetUns32BE ( &this->fields[o_size] );
	if ( majorVersion == 4 ) this->contentSize = synchToInt32 ( this->contentSize );

	XMP_Validate ( (this->contentSize >= 0), "negative frame size", kXMPErr_BadFileFormat );
	XMP_Validate ( (this->contentSize < 20*1024*1024), "single frame exceeds 20MB", kXMPErr_BadFileFormat );

	this->content = new char [ this->contentSize ];

	file->ReadAll ( this->content, this->contentSize );
	return file->Offset() - start;

}	// ID3v2Frame::read
Exemple #3
0
bool ID3v2Frame::getFrameValue ( XMP_Uns8 majorVersion, XMP_Uns32 logicalID, std::string* utf8string )
{

	XMP_Assert ( (this->content != 0) && (this->contentSize >= 0) && (this->contentSize < 20*1024*1024) );

	if ( this->contentSize == 0 ) {
		utf8string->erase();
		return true; // ...it is "of interest", even if empty contents.
	}

	XMP_Int32 pos = 0;
	XMP_Uns8 encByte = 0;
	// WCOP does not have an encoding byte, for all others: use [0] as EncByte, advance pos
	if ( logicalID != 0x57434F50 ) {
		encByte = this->content[0];
		pos++;
	}

	// mode specific forks, COMM or USLT
	bool commMode = ( (logicalID == 0x434F4D4D) || (logicalID == 0x55534C54) );

	switch ( encByte ) {

		case 0: //ISO-8859-1, 0-terminated
		{
			if ( commMode && (! advancePastCOMMDescriptor ( pos )) ) return false; // not a frame of interest!

			char* localPtr  = &this->content[pos];
			size_t localLen = this->contentSize - pos;
			ReconcileUtils::Latin1ToUTF8 ( localPtr, localLen, utf8string );
			break;

		}

		case 1: // Unicode, v2.4: UTF-16 (undetermined Endianess), with BOM, terminated 0x00 00
		case 2: // UTF-16BE without BOM, terminated 0x00 00
		{

			if ( commMode && (! advancePastCOMMDescriptor ( pos )) ) return false; // not a frame of interest!

			std::string tmp ( this->content, this->contentSize );
			bool bigEndian = true;	// assume for now (if no BOM follows)

			if ( GetUns16BE ( &this->content[pos] ) == 0xFEFF ) {
				pos += 2;
				bigEndian = true;
			} else if ( GetUns16BE ( &this->content[pos] ) == 0xFFFE ) {
				pos += 2;
				bigEndian = false;
			}

			FromUTF16 ( (UTF16Unit*)&this->content[pos], ((this->contentSize - pos)) / 2, utf8string, bigEndian );
			break;

		}

		case 3: // UTF-8 unicode, terminated \0
		{
			if ( commMode && (! advancePastCOMMDescriptor ( pos )) ) return false; // not a frame of interest!
		
			if ( (GetUns32BE ( &this->content[pos]) & 0xFFFFFF00 ) == 0xEFBBBF00 ) {
				pos += 3;	// swallow any BOM, just in case
			}

			utf8string->assign ( &this->content[pos], (this->contentSize - pos) );
			break;
		}

		default:
			XMP_Throw ( "unknown text encoding", kXMPErr_BadFileFormat ); //COULDDO assume latin-1 or utf-8 as best-effort
			break;

	}

	return true;

}	// ID3v2Frame::getFrameValue
Exemple #4
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
Exemple #5
0
void PSIR_FileWriter::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
{
	this->DeleteExistingInfo();
	this->memParsed = true;
	if ( length == 0 ) return;

	// Allocate space for the full in-memory data and copy it.

	if ( ! copyData ) {
		this->memContent = (XMP_Uns8*) data;
		XMP_Assert ( ! this->ownedContent );
	} else {
		if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
		this->memContent = (XMP_Uns8*) malloc ( length );
		if ( this->memContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
		memcpy ( this->memContent, data, length );	// AUDIT: Safe, malloc'ed length bytes above.
		this->ownedContent = true;
	}
	this->memLength = length;

	// Capture the info for all of the resources.

	XMP_Uns8* psirPtr   = this->memContent;
	XMP_Uns8* psirEnd   = psirPtr + length;
	XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;

	while ( psirPtr <= psirLimit ) {

		XMP_Uns8* origin = psirPtr;	// The beginning of this resource.
		XMP_Uns32 type = GetUns32BE(psirPtr);
		XMP_Uns16 id = GetUns16BE(psirPtr+4);
		psirPtr += 6;	// Advance to the resource name.

		XMP_Uns8* namePtr = psirPtr;
		XMP_Uns16 nameLen = namePtr[0];			// ! The length for the Pascal string, w/ room for "+2".
		psirPtr += ((nameLen + 2) & 0xFFFE);	// ! Round up to an even offset. Yes, +2!

		if ( psirPtr > psirEnd-4 ) break;	// Bad image resource. Throw instead?

		XMP_Uns32 dataLen = GetUns32BE(psirPtr);
		psirPtr += 4;	// Advance to the resource data.

		XMP_Uns32 dataOffset = (XMP_Uns32) ( psirPtr - this->memContent );
		XMP_Uns8* nextRsrc   = psirPtr + ((dataLen + 1) & 0xFFFFFFFEUL);	// ! Round up to an even offset.

		if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break;	// Bad image resource. Throw instead?

		if ( type == k8BIM ) {
			InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, dataLen, kIsMemoryBased ) );
			InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.insert ( this->imgRsrcs.end(), mapValue );
			InternalRsrcInfo* rsrcPtr = &rsrcPos->second;
			rsrcPtr->dataPtr = psirPtr;
			rsrcPtr->origOffset = dataOffset;
			if ( nameLen != 0 ) rsrcPtr->rsrcName = namePtr;
		} else {
			XMP_Uns32 rsrcOffset = XMP_Uns32( origin - this->memContent );
			XMP_Uns32 rsrcLength = XMP_Uns32( nextRsrc - origin );	// Includes trailing pad.
			XMP_Assert ( (rsrcLength & 1) == 0 );
			this->otherRsrcs.push_back ( OtherRsrcInfo ( rsrcOffset, rsrcLength ) );
		}

		psirPtr = nextRsrc;

	}

}	// PSIR_FileWriter::ParseMemoryResources
void PSIR_FileWriter::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
{
	this->DeleteExistingInfo();
	this->memParsed = true;
	if ( length == 0 ) return;

	// Allocate space for the full in-memory data and copy it.

	if ( ! copyData ) {
		this->memContent = (XMP_Uns8*) data;
		XMP_Assert ( ! this->ownedContent );
	} else {
		if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
		this->memContent = (XMP_Uns8*) malloc ( length );
		if ( this->memContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
		memcpy ( this->memContent, data, length );	// AUDIT: Safe, malloc'ed length bytes above.
		this->ownedContent = true;
	}
	this->memLength = length;

	// Capture the info for all of the resources. 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!

	XMP_Uns8* psirPtr   = this->memContent;
	XMP_Uns8* psirEnd   = psirPtr + length;
	XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;

	while ( psirPtr <= psirLimit ) {

		XMP_Uns8* origin = psirPtr;	// The beginning of this resource.
		XMP_Uns32 type = GetUns32BE(psirPtr);
		XMP_Uns16 id = GetUns16BE(psirPtr+4);
		psirPtr += 6;	// Advance to the resource name.

		XMP_Uns8* namePtr = psirPtr;
		XMP_Uns16 nameLen = namePtr[0];			// ! The length for the Pascal string, w/ room for "+2".
		psirPtr += ((nameLen + 2) & 0xFFFE);	// ! Round up to an even offset. Yes, +2!

		if ( psirPtr > psirEnd-4 ) break;	// Bad image resource. Throw instead?

		XMP_Uns32 dataLen = GetUns32BE(psirPtr);
		psirPtr += 4;	// Advance to the resource data.

		XMP_Uns32 dataOffset = (XMP_Uns32) ( psirPtr - this->memContent );
		XMP_Uns8* nextRsrc   = psirPtr + ((dataLen + 1) & 0xFFFFFFFEUL);	// ! Round up to an even offset.

		if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break;	// Bad image resource. Throw instead?

		if ( type != k8BIM ) {

			XMP_Uns32 rsrcOffset = XMP_Uns32( origin - this->memContent );
			XMP_Uns32 rsrcLength = XMP_Uns32( nextRsrc - origin );	// Includes trailing pad.
			XMP_Assert ( (rsrcLength & 1) == 0 );
			this->otherRsrcs.push_back ( OtherRsrcInfo ( rsrcOffset, rsrcLength ) );

		} else {

			InternalRsrcInfo newInfo ( id, dataLen, kIsMemoryBased );
			newInfo.dataPtr = psirPtr;
			newInfo.origOffset = dataOffset;
			if ( nameLen != 0 ) newInfo.rsrcName = namePtr;

			InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
			if ( rsrcPos == this->imgRsrcs.end() ) {
				this->imgRsrcs.insert ( rsrcPos, InternalRsrcMap::value_type ( id, newInfo ) );
			} else if ( (rsrcPos->second.dataLen == 0) && (newInfo.dataLen != 0) ) {
				rsrcPos->second = newInfo;
			}

		}

		psirPtr = nextRsrc;

	}

}	// PSIR_FileWriter::ParseMemoryResources