Exemple #1
0
	void FileInfo::CheckFormat ( LFA_FileRef fileRef )
	{
		IOBuffer ioBuf;
	
		LFA_Seek ( fileRef, 0, SEEK_SET );

		if ( CheckFileSpace ( fileRef, &ioBuf, SWF_SIGNATURE_LEN ) ) {

			if ( CheckBytes ( ioBuf.ptr, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) {
				this->compressedFile = false;
			} else if ( CheckBytes ( ioBuf.ptr, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) {
				this->compressedFile = true;
			}

			LFA_Seek ( fileRef, 4, SEEK_SET );
			XMP_Uns8 buffer[4];
			LFA_Read ( fileRef, buffer, 4 );
			iSize = GetUns32LE ( buffer );

		}

		LFA_Seek ( fileRef, 0, SEEK_SET );

	}	// FileInfo::CheckFormat
Exemple #2
0
	bool RewriteChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long tagID, long parentID, const char * inData )
	{
		UInt32 len;
		UInt64 pos;
	
		try {
			if ( FindChunk ( inOutRiffState, tagID, parentID, 0, NULL, &len, &pos ) ) {
				LFA_Seek ( inFileRef, pos, SEEK_SET );
				LFA_Write ( inFileRef, inData, len );
			}
		} catch ( ... ) {
			return false;
		}
	
		return true;
	
	}
Exemple #3
0
	long OpenRIFF ( LFA_FileRef inFileRef, RiffState & inOutRiffState )
	{
		UInt64 pos = 0;
		long tag, subtype;
		UInt32 len;

		const XMP_Int64 fileLen = LFA_Measure ( inFileRef );
		if ( fileLen < 8 ) return 0;
		
		LFA_Seek ( inFileRef, 0, SEEK_SET );
	
		while ( ReadTag ( inFileRef, &tag, &len, &subtype, pos, fileLen ) ) {
			if ( tag != FOURCC_RIFF ) break;
			AddTag ( inOutRiffState, tag, len, pos, 0, 0, subtype );
			if ( subtype != 0 ) SubRead ( inFileRef, inOutRiffState, subtype, len, pos );
		}
	
		return (long) inOutRiffState.tags.size();

	}
Exemple #4
0
	bool UpdateHeader ( LFA_FileRef fileRef )
	{

		try {

			XMP_Int64 length64 = LFA_Measure ( fileRef );
			if ( (length64 < 8) || (length64 > (XMP_Int64)0xFFFFFFFFULL) ) return false;

			XMP_Uns32 length32 = MakeUns32LE ( (XMP_Uns32)length64 );

			LFA_Seek ( fileRef, 4, SEEK_SET );
			LFA_Write ( fileRef, &length32, 4 );
			
			return true;

		} catch ( ... ) {}
	
		return false;

	}	// UpdateHeader
Exemple #5
0
XMP_Uns32 PSIR_FileWriter::UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
												 IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg )
{
	IgnoreParam(ioBuf);
	const XMP_Uns32 zero32 = 0;

	const bool checkAbort = (abortProc != 0);

	struct RsrcHeader {
		XMP_Uns32 type;
		XMP_Uns16 id;
	};
	XMP_Assert ( (offsetof(RsrcHeader,type) == 0) && (offsetof(RsrcHeader,id) == 4) );

	if ( this->memParsed ) XMP_Throw ( "Not file based", kXMPErr_EnforceFailure );

	XMP_Int64 destLenOffset = LFA_Seek ( destRef, 0, SEEK_CUR );
	XMP_Uns32 destLength = 0;

	LFA_Write ( destRef, &destLength, 4 );	// Write a placeholder for the new PSIR section length.

	#if 0
	{
		printf ( "\nPSIR_FileWriter::UpdateFileResources, 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

	// First write all of the '8BIM' resources from the map. Use the internal data if present, else
	// copy the data from the file.

	RsrcHeader outHeader;
	outHeader.type  = MakeUns32BE ( k8BIM );

	InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.begin();
	InternalRsrcMap::iterator rsrcEnd = this->imgRsrcs.end();

	// printf ( "\nPSIR_FileWriter::UpdateFileResources - 8BIM resources\n" );
	for ( ; rsrcPos != rsrcEnd; ++rsrcPos ) {

		InternalRsrcInfo& currRsrc = rsrcPos->second;

		outHeader.id = MakeUns16BE ( currRsrc.id );
		LFA_Write ( destRef, &outHeader, 6 );
		destLength += 6;

		if ( currRsrc.rsrcName == 0 ) {
			LFA_Write ( destRef, &zero32, 2 );
			destLength += 2;
		} else {
			XMP_Assert ( currRsrc.rsrcName[0] != 0 );
			XMP_Uns16 nameLen = currRsrc.rsrcName[0];	// ! Include room for +1.
			XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE;	// ! Round up to an even total. Yes, +2!
			LFA_Write ( destRef, currRsrc.rsrcName, paddedLen );
			destLength += paddedLen;
		}

		XMP_Uns32 dataLen = MakeUns32BE ( currRsrc.dataLen );
		LFA_Write ( destRef, &dataLen, 4 );
		// printf ( "  #%d, offset %d (0x%X), dataLen %d\n", currRsrc.id, destLength, destLength, currRsrc.dataLen );

		if ( currRsrc.dataPtr != 0 ) {
			LFA_Write ( destRef, currRsrc.dataPtr, currRsrc.dataLen );
		} else {
			LFA_Seek ( sourceRef, currRsrc.origOffset, SEEK_SET );
			LFA_Copy ( sourceRef, destRef, currRsrc.dataLen );
		}

		destLength += 4 + currRsrc.dataLen;

		if ( (currRsrc.dataLen & 1) != 0 ) {
			LFA_Write ( destRef, &zero32, 1 );	// ! Pad the data to an even length.
			++destLength;
		}

	}

	// Now write all of the non-8BIM resources. Copy the entire resource chunk from the source file.

	// printf ( "\nPSIR_FileWriter::UpdateFileResources - other resources\n" );
	for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) {
		// printf ( "  offset %d (0x%X), length %d",
		//		 this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcLength );
		LFA_Seek ( sourceRef, this->otherRsrcs[i].rsrcOffset, SEEK_SET );
		LFA_Copy ( sourceRef, destRef, this->otherRsrcs[i].rsrcLength );
		destLength += this->otherRsrcs[i].rsrcLength;	// Alignment padding is already included.
	}

	// Write the final PSIR section length, seek back to the end of the file, return the length.

	// printf ( "\nPSIR_FileWriter::UpdateFileResources - final length %d (0x%X)\n", destLength, destLength );
	LFA_Seek ( destRef, destLenOffset, SEEK_SET );
	XMP_Uns32 outLen = MakeUns32BE ( destLength );
	LFA_Write ( destRef, &outLen, 4 );
	LFA_Seek ( destRef, 0, SEEK_END );

	// *** Not rebuilding the internal map - turns out we never want it, why pay for the I/O.
	// *** Should probably add an option for all of these cases, memory and file based.

	return destLength;

}	// PSIR_FileWriter::UpdateFileResources
Exemple #6
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 #7
0
// =================================================================================================
// MP3_MetaHandler::UpdateFile
// ===========================
void MP3_MetaHandler::UpdateFile ( bool doSafeUpdate )
{
	if ( doSafeUpdate )
		XMP_Throw ( "UCF_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );

	LFA_FileRef file ( this->parent->fileRef );

	// leave 2.3 resp. 2.4 header, since we want to let alone 
	// and don't know enough about the encoding of unrelated frames...
	XMP_Assert( this->containsXMP );

	tagIsDirty = false;
	mustShift = false;

	// write out native properties:
	// * update existing ones
	// * create new frames as needed
	// * delete frames if property is gone!
	// see what there is to do for us:

	// RECON LOOP START
	for (int r=0; reconProps[r].frameID != 0; r++)
	{
		std::string value;
		bool needDescriptor = false;
		bool need16LE = true;
		bool needEncodingByte = true;

		XMP_Uns32 frameID = GetUns32BE( reconProps[r].frameID ); // the would-be frame
		ID3v2Frame* frame = framesMap[ frameID ];	// the actual frame (if already existing)

		// get XMP property
		//	* honour specific exceptions
		//  * leave value empty() if it doesn't exist ==> frame must be delete/not created
		switch( frameID )
		{
		case 0x54434D50: // TCMP if exists: part of compilation
			need16LE = false;
			if ( xmpObj.GetProperty( kXMP_NS_DM, "partOfCompilation", &value, 0 )
				&& ( 0 == stricmp( value.c_str(), "true" ) ))
				value = "1"; // set a TCMP frame of value 1
			else
				value.erase(); // delete/prevent creation of frame
			break;

		case 0x54495432: // TIT2 -> title["x-default"]
		case 0x54434F50: // TCOP -> rights["x-default"]
			if (! xmpObj.GetLocalizedText( reconProps[r].ns, reconProps[r].prop, "", "x-default", 0, &value, 0 )) //jaja, side effect.
				value.erase(); // if not, erase string.
			break;
		case 0x54434F4E: // TCON -> genre
			{
				if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
				{	// nothing found? -> Erase string. (Leads to Unset below)
					value.erase();
					break;
				}
				// genre: we need to get the number back, if possible
				XMP_Int16 iFound = -1; // flag as "not found"
				for ( int i=0; i < 127; ++i ) {
					if ( (value.size() == strlen(Genres[i])) 
					  && (stricmp( value.c_str(), Genres[i] ) == 0) ) //fixing stricmp buggy on PPC
						{
							iFound = i; // Found
							break;
						}
				}
				if ( iFound == -1 ) // not found known numeric genre?
					break; // stick with the literal value (also for v2.3, since this is common practice!)

				need16LE = false; // no unicode need for (##)
				char strGenre[64];
				snprintf ( strGenre, sizeof(strGenre), "(%d)", iFound );	// AUDIT: Using sizeof(strGenre) is safe.
				value.assign(strGenre);
			}
			break;
		case 0x434F4D4D: // COMM
		case 0x55534C54: // USLT, both need descriptor.
			needDescriptor = true;
			if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
				value.erase();
			break;
		case 0x54594552: //TYER
		case 0x54444154: //TDAT	
		case 0x54494D45: //TIME			
			{
				if ( majorVersion <= 3 ) // TYER, TIME and TDAT depricated since v. 2.4 -> else use TDRC
				{
					XMP_DateTime dateTime;	
					if (! xmpObj.GetProperty_Date( reconProps[r].ns, reconProps[r].prop, &dateTime, 0 ))
					{	// nothing found? -> Erase string. (Leads to Unset below)
						value.erase();
						break;
					}

					// TYER
					if ( frameID == 0x54594552 )
					{
						XMP_Validate( dateTime.year <= 9999 && dateTime.year > 0 , "Year is out of range", kXMPErr_BadParam);
						// get only Year!
						SXMPUtils::ConvertFromInt( dateTime.year, "", &value );
						break;
					} 
					// TDAT
					else if ( frameID == 0x54444154 && dateTime.hasDate ) // date validation made by "GetProperty_Date"
					{						
						std::string day, month;
						SXMPUtils::ConvertFromInt( dateTime.day, "", &day );
						SXMPUtils::ConvertFromInt( dateTime.month, "", &month );
						if ( dateTime.day < 10 )
							value = "0";
						value += day;
						if ( dateTime.month < 10 )
							value += "0";
						value += month;
						break;
					} 
					// TIME
					else if ( frameID == 0x54494D45 && dateTime.hasTime ) // time validation made by "GetProperty_Date" )
					{
						std::string hour, minute;
						SXMPUtils::ConvertFromInt( dateTime.hour, "", &hour );
						SXMPUtils::ConvertFromInt( dateTime.minute, "", &minute );
						if ( dateTime.hour < 10 )
							value = "0";
						value += hour;
						if ( dateTime.minute < 10 )
							value += "0";
						value += minute;
						break;
					} 
					else
					{
						value.erase();
						break;
					}
				}
				else // v.2.4 --> delete TYER,TIME or TDAT & write into TDRC
				{
					value.erase();
					break;
				}
			}
		case 0x54445243: //TDRC (only v2.4)
			{
				// only export for id3 > v2.4
				if ( majorVersion > 3 ) // (only v2.4)
				{
					if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
						value.erase();				
				}
				break;
			}
		break;
		case 0x57434F50: //WCOP
			needEncodingByte = false;
			need16LE = false;
			if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
				value.erase(); // if not, erase string
		break;
		case 0x5452434B: // TRCK
		case 0x54504F53: // TPOS
			need16LE = false;
			// no break, go on:
		default:
			if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
				value.erase(); // if not, erase string
			break;
		}

		// [XMP exist] x [frame exist] => four cases:
		// 1/4) nothing before, nothing now
		if ( value.empty() && (frame==0))  
			continue; // nothing to do

		// all else means there will be rewrite work to do:
		tagIsDirty = true;

		// 2/4) value before, now gone:
		if ( value.empty() && (frame!=0))
		{
			frame->active = false; //mark for non-use
			continue;
		}
		// 3/4) no old value, create new value
		if ( frame==0)
		{	
			ID3v2Frame* newFrame=new ID3v2Frame( frameID );
			newFrame->setFrameValue( value, needDescriptor,  need16LE, false, needEncodingByte ); //always write as utf16-le incl. BOM
			framesVector.push_back( newFrame );
			framesMap[ frameID ] = newFrame;
			continue;
		}
		// 4/4) change existing value
		else // resp. change frame
		{
			frame->setFrameValue( value, needDescriptor, need16LE, false, needEncodingByte );
		}
	} 	// RECON LOOP END

	/////////////////////////////////////////////////////////////////////////////////
	// (Re)Build XMP frame:
	ID3v2Frame* frame = framesMap[ XMP_FRAME_ID ];
	if ( frame == 0)
	{	
		ID3v2Frame* newFrame=new ID3v2Frame( XMP_FRAME_ID );
		newFrame->setFrameValue( this->xmpPacket, false, false, true );
		framesVector.push_back( newFrame );
		framesMap[ XMP_FRAME_ID ] = newFrame;
	} else
		frame->setFrameValue( this->xmpPacket, false, false, true );

	////////////////////////////////////////////////////////////////////////////////
	// Decision making
	newFramesSize = 0;
	for ( XMP_Uns32 i=0; i < framesVector.size(); i++)
	{
		if (framesVector[i]->active)
			newFramesSize += (10 + framesVector[i]->contentSize );
	}

	mustShift = ( newFramesSize > (oldTagSize - 10)) ||
	//optimization: If more than 8K can be saved by rewriting the MP3, go do it:
				((newFramesSize + 8*1024) < oldTagSize );

	if (!mustShift)	// fill what we got
		newTagSize = oldTagSize;
	else // if need to shift anyway, get some nice 2K padding
		newTagSize = newFramesSize + 2048 + 10;
	newPadding = newTagSize -10 - newFramesSize;

	// shifting needed? -> shift
	if ( mustShift )
	{
		XMP_Int64 filesize = LFA_Measure( file );
		if ( this->hasID3Tag )
			LFA_Move( file, oldTagSize, file, newTagSize , filesize - oldTagSize ); //fix [2338569]
		else
			LFA_Move( file, 0, file, newTagSize, filesize ); // move entire file up.
	}

	// correct size stuff, write out header
	LFA_Rewind( file );
	id3Header.write( file, newTagSize);	

	// write out tags
	for ( XMP_Uns32 i=0; i < framesVector.size(); i++)
	{
		if ( framesVector[i]->active)
			framesVector[i]->write(file, majorVersion);
	}

	// write out padding:
	for ( XMP_Int64 i = newPadding; i > 0;)
	{
		const XMP_Uns64 zero = 0;
		if ( i >= 8 ) // worthwhile optimization
		{
			LFA_Write( file, &zero, 8 );
			i -= 8;
			continue;
		}
		LFA_Write( file, &zero, 1 );
		i--;
	}

	// check end of file for ID3v1 tag
	XMP_Int64 possibleTruncationPoint = LFA_Seek( file, -128, SEEK_END);
	bool alreadyHasID3v1 = (LFA_ReadInt32_BE( file ) & 0xFFFFFF00) == 0x54414700; // "TAG"
	if ( ! alreadyHasID3v1 ) // extend file
		LFA_Extend( file, LFA_Measure( file ) + 128 );
	id3v1Tag.write( file, &this->xmpObj );

	this->needsUpdate = false; //do last for safety reasons
}	// MP3_MetaHandler::UpdateFile
Exemple #8
0
// =================================================================================================
// MP3_MetaHandler::CacheFileData
// ==============================
void MP3_MetaHandler::CacheFileData()
{
	//*** abort procedures
	this->containsXMP = false;		//assume no XMP for now

	LFA_FileRef file = this->parent->fileRef;
	XMP_PacketInfo &packetInfo = this->packetInfo;

	LFA_Rewind(file);

	hasID3Tag = id3Header.read( file );
	majorVersion = id3Header.fields[ID3Header::o_version_major];
	minorVersion = id3Header.fields[ID3Header::o_version_minor];
	hasExtHeader = (0 != ( 0x40 & id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag
	hasFooter = ( 0 != ( 0x10 & 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.)
	oldTagSize = 10 + synchToInt32(GetUns32BE( &id3Header.fields[ID3Header::o_size] ));

	if (hasExtHeader)
	{
		extHeaderSize = synchToInt32( LFA_ReadInt32_BE( file));
		XMP_Uns8 extHeaderNumFlagBytes = LFA_ReadUns8( file );

		// v2.3 doesn't include the size, while v2.4 does
		if ( majorVersion < 4 ) extHeaderSize += 4; 
		XMP_Validate( extHeaderSize >= 6, "extHeader size too small", kXMPErr_BadFileFormat );

		bool ok;
		LFA_Seek(file, extHeaderSize - 6, SEEK_CUR , &ok);
		XMP_Assert(ok);
	}
	else
	{
		extHeaderSize = 0; // := there is no such header.
	}

	this->framesVector.clear(); //mac precaution
	ID3v2Frame* curFrame = 0; // reusable

	////////////////////////////////////////////////////
	// read frames
	while ( LFA_Tell(file) < oldTagSize )
	{
		curFrame = new ID3v2Frame();

		try {
			XMP_Int64 frameSize = curFrame->read( file, majorVersion );
			if (frameSize == 0) // no more frames coming => proceed to padding
			{
				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( XMP_Error e)
		{
			delete curFrame;
			XMP_Throw( e.GetErrMsg(), e.GetID()); // rethrow
		}

		// 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 ( CheckBytes( &curFrame->fields[ID3v2Frame::o_id], "PRIV", 4 ))
			if( curFrame->contentSize > 8 ) // to avoid adress violation on very small non-XMP PRIV frames
				if( CheckBytes( &curFrame->content[0], "XMP\0", 4 ))
				{
					// be sure that this is the first packet (all else would be illegal format)
					XMP_Validate( framesMap[ XMP_FRAME_ID] == 0, "two XMP packets in one file", kXMPErr_BadFileFormat );
					//add this to map, needed on reconciliation
					framesMap[ XMP_FRAME_ID ] = curFrame;

					this->packetInfo.length = curFrame->contentSize - 4; // content minus "XMP\0"
					this->packetInfo.offset = ( LFA_Tell(file) - 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.
				if ( LFA_Tell(file) + 10 >= oldTagSize )
					break;
	}

	////////////////////////////////////////////////////
	// padding
	oldPadding = oldTagSize - LFA_Tell( file );
	oldFramesSize = oldTagSize - 10 - oldPadding;

	XMP_Validate( oldPadding >= 0, "illegal oldTagSize or padding value", kXMPErr_BadFileFormat );

	for ( XMP_Int64 i = oldPadding; i > 0;)
	{
		if ( i >= 8 ) // worthwhile optimization
		{
			if ( LFA_ReadInt64_BE(file) != 0 )
				XMP_Throw ( "padding not nulled out.", kXMPErr_BadFileFormat );
			i -= 8;
			continue;
		}
		if ( LFA_ReadUns8(file) != 0)
			XMP_Throw ( "padding(2) not nulled out.", kXMPErr_BadFileFormat );
		i--;
	}

	//// read ID3v1 tag
	if ( ! this->containsXMP ) // all else has priority
	{
		this->containsXMP = id3v1Tag.read( file, &this->xmpObj );
	}

}	// MP3_MetaHandler::CacheFileData
Exemple #9
0
	static bool  ReadTag ( LFA_FileRef inFileRef, long * outTag, UInt32 * outLength, long * subtype, UInt64 & inOutPosition, UInt64 maxOffset )
	{
		UInt32	realLength;
	
		long bytesRead;
		bytesRead = LFA_Read ( inFileRef, outTag, 4 );
		if ( bytesRead != 4 ) return false;
		*outTag = GetUns32LE ( outTag );
		
		bytesRead = LFA_Read ( inFileRef, outLength, 4 );
		if ( bytesRead != 4 ) return false;
		*outLength = GetUns32LE ( outLength );

		realLength = *outLength;
		realLength += (realLength & 1);		// Round up to an even value.

		inOutPosition = GetFilePosition ( inFileRef );	// The file offset of the data portion.
		UInt64 maxLength = maxOffset - inOutPosition;

		if ( (inOutPosition > maxOffset) || ((UInt64)(*outLength) > maxLength) ) {

			bool ignoreLastPad = true;	// Ignore cases where a final pad byte is missing.
			UInt64 fileLen = LFA_Measure ( inFileRef );
			if ( inOutPosition > (maxOffset + 1) ) ignoreLastPad = false;
			if ( (UInt64)(*outLength) > (maxLength + 1) ) ignoreLastPad = false;

			if ( ! ignoreLastPad ) {

				// Workaround for bad files in the field that have a bad size in the outermost RIFF
				// chunk. Do a "runtime repair" of cases where the length is too long (beyond EOF).
				// This handles read-only usage, update usage is repaired (or not) in the handler.

				bool oversizeRIFF = (inOutPosition == 8) &&	// Is this the initial 'RIFF' chunk?
									(fileLen >= 8);			// Is the file at least of the minimal size?
								 
				if ( ! oversizeRIFF ) {
					XMP_Throw ( "RIFF tag exceeds maximum length", kXMPErr_BadValue );
				} else {
					*outLength = (UInt32)(fileLen) - 8;
					realLength = *outLength;
					realLength += (realLength & 1);		// Round up to an even value.
				}

			}

		}
		
		*subtype = 0;

		if ( (*outTag != FOURCC_LIST) && (*outTag != FOURCC_RIFF) ) {

			UInt64 tempPos = inOutPosition + realLength;
			if ( tempPos <= maxOffset ) {
				LFA_Seek ( inFileRef, tempPos, SEEK_SET );
			} else if ( (tempPos == (maxOffset + 1)) && (maxOffset == (UInt64)LFA_Measure(inFileRef)) ) {
				LFA_Seek ( inFileRef, 0, SEEK_END );	// Hack to tolerate a missing final pad byte.
			} else {
				XMP_Throw ( "Bad RIFF offset", kXMPErr_BadValue );
			}

		} else  {

			bytesRead = LFA_Read ( inFileRef, subtype, 4 );
			if ( bytesRead != 4 ) return false;
			*subtype = GetUns32LE ( subtype );

			*outLength -= 4;
			realLength -= 4;

			// Special case:
			// Since the 'movi' chunk can contain billions of subchunks, skip over the 'movi' subchunk.
			//
			// The 'movi' subtype is added to the list as the TAG.
			// The subtype is returned empty so nobody will try to parse the subchunks.

			if ( *subtype == listtypeAVIMOVIE ) {
				inOutPosition = GetFilePosition ( inFileRef );
				UInt64 tempPos = inOutPosition + realLength;
				if ( tempPos <= maxOffset ) {
					LFA_Seek ( inFileRef, tempPos, SEEK_SET );
				} else if ( (tempPos == (maxOffset + 1)) && (maxOffset == (UInt64)LFA_Measure(inFileRef)) ) {
					LFA_Seek ( inFileRef, 0, SEEK_END );	// Hack to tolerate a missing final pad byte.
				} else {
					XMP_Throw ( "Bad RIFF offset", kXMPErr_BadValue );
				}
				*outLength += 4;
				*outTag = *subtype;
				*subtype = 0;
			}

			inOutPosition = GetFilePosition ( inFileRef );

		}
	
		return true;

	}
Exemple #10
0
	bool MakeChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, UInt32 len )
	{
		long starttag;
		UInt32 taglen;
		UInt32 rifflen, avail;
		UInt64 pos;
	
		/* look for top level Premiere padding chunk */
		starttag = 0;
		while ( FindChunk ( inOutRiffState, ckidPremierePadding, riffType, 0, &starttag, &taglen, &pos ) ) {
	
			pos -= 8;
			taglen += 8;
			long extra = taglen - len;
			if ( extra < 0 ) continue;
	
			RiffIterator iter = inOutRiffState.tags.begin();
			iter += (starttag - 1);
	
			if ( extra == 0 ) {

				iter->len = 0;

			} else {

				atag pad;
				UInt64 padpos;
	
				/*  need 8 bytes extra to be able to split it */
				extra -= 8;
				if ( extra < 0 ) continue;
	
				try{
					padpos = pos + len;
					LFA_Seek ( inFileRef, padpos, SEEK_SET );
					pad.id = MakeUns32LE ( ckidPremierePadding );
					pad.len = MakeUns32LE ( extra );
					LFA_Write ( inFileRef, &pad, sizeof(pad) );
				} catch ( ... ) {
					return false;
				}

				iter->pos = padpos + 8;
				iter->len = extra;

			}
	
			/* seek back to start of original padding chunk */
			LFA_Seek ( inFileRef, pos, SEEK_SET );
	
			return true;

		}
	
		/* can't take padding chunk, so append new chunk to end of file */
	
		rifflen = inOutRiffState.rifflen + 8;
		avail = AVIMAXCHUNKSIZE - rifflen;
	
		LFA_Seek ( inFileRef, 0, SEEK_END );
		pos = GetFilePosition ( inFileRef );

		if ( (pos & 1) == 1 ) {
			// The file length is odd, need a pad byte.
			XMP_Uns8 pad = 0;
			LFA_Write ( inFileRef, &pad, 1 );
			++pos;
		}
	
		if ( avail < len ) {

			/* if needed, create new AVIX chunk */
			ltag avix;
	
			avix.id = MakeUns32LE ( FOURCC_RIFF );
			avix.len = MakeUns32LE ( 4 + len );
			avix.subid = MakeUns32LE ( formtypeAVIX );
			LFA_Write(inFileRef, &avix, sizeof(avix));
	
			pos += 12;
			AddTag ( inOutRiffState, avix.id, len, pos, 0, 0, 0 );

		} else {

			/* otherwise, rewrite length of last RIFF chunk in file */
			pos = inOutRiffState.riffpos + 4;
			rifflen = inOutRiffState.rifflen + len;
			XMP_Uns32 fileLen = MakeUns32LE ( rifflen );
			LFA_Seek ( inFileRef, pos, SEEK_SET );
			LFA_Write ( inFileRef, &fileLen, 4 );
			inOutRiffState.rifflen = rifflen;
	
			/* prepare to write data */
			LFA_Seek ( inFileRef, 0, SEEK_END );

		}
	
		return true;

	}
Exemple #11
0
// plain convenience
XMP_Int64 LFA_Rewind( LFA_FileRef file)
{
	return LFA_Seek( file, 0 , SEEK_SET ); // _SET !
}
Exemple #12
0
XMP_Int64 LFA_Tell ( LFA_FileRef file )
{
	return LFA_Seek( file, 0 , SEEK_CUR ); // _CUR !
}
Exemple #13
0
	int FileInfo::Def ( LFA_FileRef source, LFA_FileRef dest )
	{
		int ret, flush;
		unsigned have;
		z_stream strm;
		unsigned char in[CHUNK];
		unsigned char out[CHUNK];

		// allocate deflate state
		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		ret = deflateInit ( &strm, SWF_DEFAULT_COMPRESSION_LEVEL );
		if ( ret != Z_OK ) return ret;

		// compress until end of file

		LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET );
		XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN;

		try {

			do {

				strm.avail_in = LFA_Read ( source, in, CHUNK );

				flush = ( (strm.avail_in < CHUNK) ? Z_FINISH : Z_NO_FLUSH );
				
				strm.next_in = in;

				// run deflate() on input until output buffer not full, finish
				// compression if all of source has been read in
				do {

					strm.avail_out = CHUNK;
					strm.next_out = out;
					ret = deflate ( &strm, flush );    // no bad return value
					XMP_Assert ( ret != Z_STREAM_ERROR );  // state not clobbered
					have = CHUNK - strm.avail_out;
					
					LFA_Seek ( dest, outPos, SEEK_SET );
					LFA_Write ( dest, out, have );
					outPos += have;

				} while ( strm.avail_out == 0 );
				XMP_Assert ( strm.avail_in == 0 );	// all input will be used

				// done when last data in file processed

			} while ( flush != Z_FINISH );
			XMP_Assert ( ret == Z_STREAM_END );	// stream will be complete

		} catch ( ... ) {

			deflateEnd ( &strm );
			return Z_ERRNO;

		}
		
		/* clean up and return */
		deflateEnd ( &strm );
		return Z_OK;

	}	// FileInfo::Def
Exemple #14
0
	int FileInfo::Inf ( LFA_FileRef source, LFA_FileRef dest )
	{
		int ret;
		unsigned have;
		z_stream strm;
		unsigned char in[CHUNK];
		unsigned char out[CHUNK];

		XMP_Uns64 allBytes = 0;

		// allocate inflate state 
		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		strm.avail_in = 0;
		strm.next_in = Z_NULL;

		ret = inflateInit ( &strm );

		if ( ret != Z_OK ) return ret;

		// decompress until deflate stream ends or end of file 

		LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET );
		XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN;

		try {

			do { 

				strm.avail_in = LFA_Read ( source, in, CHUNK );
				if ( strm.avail_in == 0 ) {
					ret = Z_STREAM_END;
					break;
				}

				strm.next_in = in;

				// run inflate() on input until output buffer not full 
				do {

					strm.avail_out = CHUNK; 
					strm.next_out = out;
					ret = inflate ( &strm, Z_NO_FLUSH );
					XMP_Assert ( ret != Z_STREAM_ERROR );  // state not clobbered 

					switch ( ret ) {
						case Z_NEED_DICT:	ret = Z_DATA_ERROR;	// and fall through 
						case Z_DATA_ERROR:
						case Z_MEM_ERROR:	inflateEnd ( &strm );
											return ret;
					}

					have = CHUNK - strm.avail_out;
					LFA_Seek ( dest, outPos, SEEK_SET );
					LFA_Write ( dest, out, have );
					
					outPos += have;
					
				} while ( strm.avail_out == 0 );

				// done when inflate() says it's done 

			} while ( ret != Z_STREAM_END );

		} catch ( ... ) {

			inflateEnd ( &strm );
			return Z_ERRNO;

		}

		// clean up and return 
		inflateEnd ( &strm );
		return ( (ret == Z_STREAM_END) ? Z_OK : Z_DATA_ERROR );

	}	// FileInfo::Inf