--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imageeditorengine/src/CExifParser.cpp Fri Jan 29 13:53:17 2010 +0200
@@ -0,0 +1,1122 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - Initial contribution
+*
+* Contributors:
+* Ixonos Plc
+*
+* Description:
+*
+*/
+
+
+#include "CExifParser.h"
+#include <e32svr.h> // for debug
+
+
+
+enum TExifType
+ {
+ EByte = 1,
+ EAscii,
+ EShort,
+ ELong,
+ ERational,
+ EUndefined = 7,
+ ESLong = 9,
+ ESRational
+ };
+
+
+
+const char* KTypeName[] =
+ {
+ "Byte",
+ "Ascii",
+ "Short",
+ "Long",
+ "Rational",
+ "Undefined",
+ "SLong",
+ "SRational"
+ };
+
+
+
+const char KTypeLength[] =
+ {
+ 0,
+ 1,
+ 1,
+ 2,
+ 4,
+ 8,
+ 0,
+ 1,
+ 0,
+ 4,
+ 8
+ };
+
+
+
+
+
+
+
+CExifParser* CExifParser::NewL()
+ {
+ CExifParser* self = NewLC();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+
+CExifParser* CExifParser::NewLC()
+ {
+ CExifParser* self = new( ELeave )CExifParser();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+
+CExifParser::~CExifParser()
+ {
+ iEntry.ResetAndDestroy();
+ iParseStack.Reset();
+
+ delete[] iSaveBuf;
+ delete[] iSaveDataBuf;
+
+ iThumbData = NULL;
+ }
+
+
+
+CExifParser::CExifParser()
+ {
+
+ }
+
+
+
+void CExifParser::ConstructL()
+ {
+ iIntelByteOrder = true;
+ }
+
+
+
+void CExifParser::ParseL( const TPtrC8& aData )
+ {
+ if( aData.Length() < (8+2+12) ) return; // header + 1 tag length
+
+ iData.Set( aData );
+ iThumbData = 0;
+ iThumbLen = 0;
+
+ if( iData[ 0 ] == 0x49 && iData[ 1 ] == 0x49 )
+ {
+ // intel byte order
+ iIntelByteOrder = ETrue;
+ //RDebug::Print( _L("Intel byte order selected") );
+ }
+ else
+ {
+ //RDebug::Print( _L("Motorola byte order selected") );
+ }
+
+ iPosition = 2;
+ TUint16 v = Get16();
+ if( v != 0x002a )
+ {
+ // must be 2a 00 in EXIF
+ User::Leave( KErrNotSupported );
+ }
+
+ iPosition = 4;
+ iParseStack.Append( TParseStack( Get32(), EIfd0 ) );
+
+ while( iParseStack.Count() )
+ {
+ iPosition = iParseStack[ 0 ].iPosition;
+ TUint8 currentIfd = iParseStack[ 0 ].iIfd;
+ iParseStack.Remove( 0 );
+ TInt i;
+ TInt c = Get16();
+ for( i=0; i<c; i++ )
+ {
+ ParseIfdL( currentIfd );
+ }
+ TUint32 link = NULL;
+ if (iPosition + 3 < iData.Length())
+ {
+ link = Get32();
+ }
+
+ if( link )
+ {
+ //RDebug::Print( _L(" --Link (IFD1?) %d,%d"), link, iPosition );
+ iParseStack.Append( TParseStack( link, EIfd1 ) );
+ }
+ else
+ {
+ //RDebug::Print( _L(" -- NULL Link after IFD") );
+ }
+ }
+ iParseStack.Reset();
+
+ //RDebug::Print( _L(" -- Parse Complete") );
+ iIntelByteOrder = true;
+ }
+
+
+
+TBool CExifParser::TagExist( TInt aIfd, TUint16 aTag )
+ {
+ if( FindTag( aIfd, aTag ) >= 0 ) return ETrue;
+ return EFalse;
+ }
+
+
+
+void CExifParser::DeleteTag( TInt aIfd, TUint16 aTag )
+ {
+ TInt i = FindTag( aIfd, aTag );
+ if( i >= 0 )
+ {
+ delete iEntry[ i ];
+ iEntry.Remove( i );
+ }
+ }
+
+
+
+TUint32 CExifParser::TagValue( TInt aIfd, TUint16 aTag )
+ {
+ TInt value = 0;
+ TInt n = FindTag( aIfd, aTag );
+ if( n<0 ) return 0;
+ TExifEntry* e = iEntry[ n ];
+ TUint8* valData = e->iData;
+ switch( e->iType )
+ {
+ case EByte:
+ {
+ value = Get8( valData );
+ break;
+ }
+ case EAscii:
+ {
+ /*
+ TBuf< 256 >str;
+ str.Copy( _L("value:") );
+ const TUint8* p = valData;
+ while( *p != 0 )
+ {
+ str.Append( *p );
+ p++;
+ }
+ */
+ // not supported
+ value = 0;
+ break;
+ }
+ case EShort:
+ {
+ value = Get16( valData );
+ ////RDebug::Print( _L("value:%d"), value );
+ break;
+ }
+ case ELong:
+ {
+ value = Get32( valData );
+ ////RDebug::Print( _L("value:%d"), value );
+ break;
+ }
+ case ERational:
+ {
+ TInt nominator = Get32( valData );
+ TInt denominator = Get32( valData+4 );
+ ////RDebug::Print( _L("value:%d/%d"), nominator, denominator );
+ if( denominator != 0 )
+ {
+ value = nominator / denominator;
+ }
+ else
+ {
+ value = 0;
+ }
+ break;
+ }
+ case EUndefined:
+ {
+
+ break;
+ }
+ case ESLong:
+ {
+ TUint32 val = Get32( valData );
+ value = *(TInt*)(&val);
+ ////RDebug::Print( _L("value:%d"), svalue );
+
+ break;
+ }
+ case ESRational:
+ {
+ TUint32 uval = Get32( valData );
+ TInt nominator = *(TInt*)(&uval);
+ uval = Get32( valData+4 );
+ TInt denominator = *(TInt*)(&uval);
+
+ if( denominator != 0 )
+ {
+ value = nominator / denominator;
+ }
+ else
+ {
+ value = 0;
+ }
+ ////RDebug::Print( _L("value:%d/%d"), nominator, denominator );
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return value;
+ }
+
+TPtrC8 CExifParser::ThumbData()
+ {
+ return TPtrC8( iThumbData, iThumbLen );
+ }
+
+
+TPtr8 CExifParser::SaveL( const TPtrC8& aThumbData )
+ {
+ iIntelByteOrder = true;
+ //
+ // Exif data cannot take more than 64KBytes
+ //
+ if (iSaveBuf)
+ {
+ delete[] iSaveBuf;
+ iSaveBuf = NULL;
+ }
+
+ iSaveBuf = new( ELeave )TUint8[ 0x10000 ];
+ iSaveBufPos = 0;
+
+ if (iSaveDataBuf)
+ {
+ delete[] iSaveDataBuf;
+ iSaveDataBuf = NULL;
+ }
+
+ iSaveDataBuf = new( ELeave )TUint8[ 0x10000 ];
+ iSaveDataBufPos = 0;
+
+ //
+ // header
+ //
+ Put8( 0x49 );
+ Put8( 0x49 );
+ Put8( 0x2a );
+ Put8( 0x00 );
+ Put32( 8 );
+
+ //
+ // Remove IFD0 SubIfd tag, will be regenerated
+ //
+ DeleteTag( EIfd0, 0x8769 );
+
+ //
+ // Save IFD0
+ //
+ Put16( IfdCount( EIfd0 ) + 1 );
+ TInt c = iEntry.Count();
+ TInt i;
+ for( i=0; i<c; i++ )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == EIfd0 )
+ {
+ StoreEntry( i );
+ }
+ }
+
+ //
+ // Save link to SubIfd ( this is a tag )
+ //
+ TExifEntry* tagsub = new( ELeave )TExifEntry;
+ CleanupStack::PushL(tagsub);
+ tagsub->iTag = 0x8769;
+ tagsub->iIfd = EIfd0;
+ tagsub->iType = ELong;
+ tagsub->iCount = 1;
+ tagsub->iData = new( ELeave )TUint8[ 4 ];
+ TUint8* dat = tagsub->iData;
+ TUint32 offset = iSaveBufPos + 12 + 4; // just after IFD1 link
+ if( iIntelByteOrder )
+ {
+ dat[ 0 ] = offset & 255; offset >>= 8;
+ dat[ 1 ] = offset & 255; offset >>= 8;
+ dat[ 2 ] = offset & 255; offset >>= 8;
+ dat[ 3 ] = offset & 255;
+ }
+ else
+ {
+ dat[ 3 ] = offset & 255; offset >>= 8;
+ dat[ 2 ] = offset & 255; offset >>= 8;
+ dat[ 1 ] = offset & 255; offset >>= 8;
+ dat[ 0 ] = offset & 255;
+ }
+ iEntry.Append( tagsub );
+ CleanupStack::Pop();
+ StoreEntry( iEntry.Count()-1 );
+
+ //
+ // Save link to IFD1 ( not a tag, just pointer )
+ //
+ TInt IFD1LinkPos = iSaveBufPos;
+ Put32( 0 );
+
+ //
+ // Remove Interoperability tag, will be regenerated
+ //
+ DeleteTag( ESubIfd, 0xa005 );
+ c = iEntry.Count();
+
+ //
+ // Save SubIfd
+ //
+ Put16( IfdCount( ESubIfd ) );
+ //RDebug::Print( _L(" SUBIFD count %x"), IfdCount( ESubIfd ) );
+ for( i=0; i<c; i++ )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == ESubIfd )
+ {
+ //RDebug::Print( _L(" SUBIFD %x"), e->iTag );
+ StoreEntry( i );
+ }
+ }
+/*
+ TExifEntry* tagint = new( ELeave )TExifEntry;
+ tagint->iTag = 0xa005;
+ tagint->iIfd = ESubIfd;
+ tagint->iType = ELong;
+ tagint->iCount = 1;
+ tagint->iData = new( ELeave )TUint8[ 4 ];
+ TUint8* dat2 = tagint->iData;
+ TUint32 offset2 = iSaveBufPos + 12 + 4; // just after IFD link
+ if( iIntelByteOrder )
+ {
+ dat2[ 0 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 1 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 2 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 3 ] = offset2 & 255;
+ }
+ else
+ {
+ dat2[ 3 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 2 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 1 ] = offset2 & 255; offset2 >>= 8;
+ dat2[ 0 ] = offset2 & 255;
+ }
+ iEntry.Append( tagint );
+ StoreEntry( iEntry.Count()-1 );
+*/
+ Put32( 0 ); // IFD link
+
+/*
+ //
+ // Save Interoperability
+ //
+ Put16( IfdCount( EInteroperability ) );
+ c = iEntry.Count();
+ for( i=0; i<c; i++ )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == EInteroperability )
+ {
+ StoreEntry( i );
+ }
+ }
+ Put32( 0 ); // IFD link
+*/
+ //
+ // Save IFD1 ( thumbnail ) if new thumbnail given
+ //
+ if( aThumbData.Ptr() )
+ {
+ TUint32 temp = iSaveBufPos;
+ iSaveBufPos = IFD1LinkPos;
+ Put32( temp );
+ iSaveBufPos = temp;
+ }
+
+ //
+ // Remove old thumbnail tags
+ //
+ c = iEntry.Count();
+ i = 0;
+ while( i < iEntry.Count() )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == EIfd1 )
+ {
+ delete e;
+ iEntry.Remove( i );
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ //
+ // Add newe thumbnail tags ( if thumbnail given )
+ //
+ TInt thumbData = 0;
+ if( aThumbData.Ptr() )
+ {
+ AddTagL( EIfd1, 0x0103, (TUint16)6 ); // thumbnail = jpeg
+
+ // thumbnail X-resolution 180/1
+ AddTagL( EIfd1, 0x011a, (TUint32)180, (TUint32)1 );
+
+ // thumbnail Y-resolution 180/1
+ AddTagL( EIfd1, 0x011b, (TUint32)180, (TUint32)1 );
+
+ // thumbnail resolution unit = inch
+ AddTagL( EIfd1, 0x0128, (TUint16)2 );
+
+ AddTagL( EIfd1, 0x0201, (TUint32)0 ); // thumb offset
+ AddTagL( EIfd1, 0x0202, (TUint32)aThumbData.Length() ); // thumb length
+
+
+ Put16( IfdCount( EIfd1 ) );
+ c = iEntry.Count();
+ for( i=0; i<c; i++ )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == EIfd1 )
+ {
+ StoreEntry( i );
+ }
+ }
+
+
+ thumbData = iSaveBufPos - 12 - 4; // tag 0x0201 data position
+
+ Put32( 0 ); // IFD link
+ }
+
+ //
+ // Copy tag data to same buffer with tags
+ //
+ Mem::Copy( iSaveBuf + iSaveBufPos, iSaveDataBuf, iSaveDataBufPos );
+ TInt totalLength = iSaveBufPos + iSaveDataBufPos;
+
+ //
+ // Copy thumbnail data to same buffer
+ //
+ if( thumbData )
+ {
+ TInt temp = iSaveBufPos;
+ iSaveBufPos = thumbData;
+ Put32( totalLength );
+ iSaveBufPos = temp;
+
+ Mem::Copy( iSaveBuf + totalLength, aThumbData.Ptr(), aThumbData.Length() );
+ totalLength += aThumbData.Length();
+ }
+ //
+ // update data pointers
+ //
+ if( iSaveBufPos & 1 ) iSaveBufPos++; // data must be in even address
+ TInt doffset = iSaveBufPos;
+ c = iDataEntry.Count();
+ for( i=0; i<c; i++ )
+ {
+ iSaveBufPos = iDataEntry[ i ];
+ TUint32 ptr = Get32( iSaveBuf + iSaveBufPos );
+ ptr += doffset;
+ Put32( ptr );
+ }
+
+ delete[] iSaveDataBuf;
+ iSaveDataBuf = NULL;
+ iDataEntry.Reset();
+
+ TPtr8 buffer( iSaveBuf, totalLength );
+ buffer.SetLength( totalLength );
+ return buffer;
+ }
+
+
+
+TUint32 CExifParser::Get8()
+ {
+ return iData[ iPosition++ ];
+
+ }
+
+
+
+TUint32 CExifParser::Get16()
+ {
+ TUint32 value;
+ if( iIntelByteOrder )
+ {
+ value = 256 * iData[ iPosition + 1 ] + iData[ iPosition ];
+ }
+ else
+ {
+ value = 256 * iData[ iPosition ] + iData[ iPosition + 1 ];
+ }
+ iPosition += 2;
+ return value;
+ }
+
+
+
+TUint32 CExifParser::Get32()
+ {
+ TUint32 value;
+ if( iIntelByteOrder )
+ {
+ value = iData[ iPosition + 3 ];
+ value <<= 8;
+ value |= iData[ iPosition + 2 ];
+ value <<= 8;
+ value |= iData[ iPosition + 1 ];
+ value <<= 8;
+ value |= iData[ iPosition + 0 ];
+ }
+ else
+ {
+ value = iData[ iPosition + 0 ];
+ value <<= 8;
+ value |= iData[ iPosition + 1 ];
+ value <<= 8;
+ value |= iData[ iPosition + 2 ];
+ value <<= 8;
+ value |= iData[ iPosition + 3 ];
+ }
+ iPosition += 4;
+ return value;
+ }
+
+
+
+TUint32 CExifParser::Get8( const TUint8* aData )
+ {
+ return *aData;
+ }
+
+
+
+TUint32 CExifParser::Get16( const TUint8* aData )
+ {
+ TUint32 value;
+ if( iIntelByteOrder )
+ {
+ value = 256 * aData[ 1 ] + aData[ 0 ];
+ }
+ else
+ {
+ value = 256 * aData[ 0 ] + aData[ 1 ];
+ }
+ return value;
+ }
+
+
+
+TUint32 CExifParser::Get32( const TUint8* aData )
+ {
+ TUint32 value;
+ if( iIntelByteOrder )
+ {
+ value = aData[ 3 ];
+ value <<= 8;
+ value |= aData[ 2 ];
+ value <<= 8;
+ value |= aData[ 1 ];
+ value <<= 8;
+ value |= aData[ 0 ];
+ }
+ else
+ {
+ value = aData[ 0 ];
+ value <<= 8;
+ value |= aData[ 1 ];
+ value <<= 8;
+ value |= aData[ 2 ];
+ value <<= 8;
+ value |= aData[ 3 ];
+ }
+ return value;
+ }
+
+
+
+void CExifParser::ParseIfdL( TUint8 aIfd )
+ {
+ TUint32 tag = Get16();
+ TUint32 type = Get16();
+ TUint32 count = Get32();
+ TUint32 offset = Get32();
+ TUint32 revOffset = ( ( offset & 0xff ) << 24 ) + ( ( offset & 0xff00 ) << 8 ) + ( ( offset & 0xff0000 ) >> 8 ) + ( ( offset & 0xff000000 ) >> 24 );
+
+ RDebug::Print( _L("Pos %d, Tag %x, type %d, count %d, offset %d, ifd %d"), iPosition-14, tag, type, count, offset, aIfd );
+
+ const TUint8* valData = NULL;
+
+ TInt bytes = KTypeLength[ type ] * count;
+
+ if( bytes > 4 )
+ {
+ valData = &iData[ offset ];
+ }
+ else
+ {
+ if( iIntelByteOrder )
+ {
+ valData = (const TUint8*)(&offset);
+ }
+ else
+ {
+ // offset already reversed
+ // must use reversed offset
+ valData = (const TUint8*)(&revOffset);
+ }
+ }
+
+
+ TExifEntry* entry = new( ELeave )TExifEntry;
+ CleanupStack::PushL(entry);
+ entry->iIfd = aIfd;
+ entry->iTag = tag;
+ entry->iType = type;
+ entry->iCount = count;
+
+ TUint32 value = 0;
+
+ entry->iData = new( ELeave )TUint8[ bytes ];
+ if( iIntelByteOrder )
+ {
+ Mem::Copy( entry->iData, valData, bytes );
+ switch( type )
+ {
+ case EByte:
+ {
+ value = Get8( valData );
+ break;
+ }
+ case EShort:
+ {
+ value = Get16( valData );
+ break;
+ }
+ case ELong:
+ case ESLong:
+ {
+ value = Get32( valData );
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else
+ {
+
+ switch( type )
+ {
+ case EByte:
+ {
+ value = Get8( valData );
+ entry->iData[ 0 ] = value;
+ break;
+ }
+ case EAscii:
+ {
+ Mem::Copy( entry->iData, valData, bytes );
+ //RDebug::Print( str );
+ break;
+ }
+ case EShort:
+ {
+ entry->iData[ 1 ] = Get8( valData );
+ entry->iData[ 0 ] = Get8( valData+1 );
+ value = Get16( valData );
+ break;
+ }
+ case ELong:
+ case ESLong:
+ {
+ entry->iData[ 3 ] = Get8( valData );
+ entry->iData[ 2 ] = Get8( valData+1 );
+ entry->iData[ 1 ] = Get8( valData+2 );
+ entry->iData[ 0 ] = Get8( valData+3 );
+ value = Get32( valData );
+ break;
+ }
+ case ERational:
+ case ESRational:
+ {
+ entry->iData[ 3 ] = Get8( valData );
+ entry->iData[ 2 ] = Get8( valData+1 );
+ entry->iData[ 1 ] = Get8( valData+2 );
+ entry->iData[ 0 ] = Get8( valData+3 );
+
+ entry->iData[ 7 ] = Get8( valData+4 );
+ entry->iData[ 6 ] = Get8( valData+5 );
+ entry->iData[ 5 ] = Get8( valData+6 );
+ entry->iData[ 4 ] = Get8( valData+7 );
+ break;
+ }
+ case EUndefined:
+ default:
+ {
+ Mem::Copy( entry->iData, valData, bytes );
+ break;
+ }
+ }
+ }
+ //RDebug::Print( _L("value=%d"), value );
+
+ iEntry.Append( entry );
+ CleanupStack::Pop();
+
+
+ if( tag == 0x927c )
+ {
+ //RDebug::Print( _L(" --MakerNote") );
+ }
+
+ if( tag == 0x8769 )
+ {
+ iParseStack.Append( TParseStack( value, ESubIfd ) );
+ //RDebug::Print( _L(" --SubIfd %d, %d"), value, iPosition );
+ }
+
+ if( tag == 0xa005 )
+ {
+ iParseStack.Append( TParseStack( value, EInteroperability ) );
+ //RDebug::Print( _L(" --Interoperability, %d, %d"), value, iPosition );
+ }
+
+ if( aIfd == EIfd1 )
+ {
+ if( tag == 0x0201 )
+ {
+ iThumbData = ((TUint8*)iData.Ptr()) + value;
+ }
+ if( tag == 0x0202 )
+ {
+ iThumbLen = value;
+ }
+ }
+ }
+
+
+
+TInt CExifParser::FindTag( TInt aIfd, TUint16 aTag )
+ {
+ TInt i;
+ TInt c = iEntry.Count();
+ for( i=0; i<c; i++ )
+ {
+ if( iEntry[ i ]->iIfd == aIfd )
+ {
+ if( iEntry[ i ]->iTag == aTag ) return i;
+ }
+ }
+ return -1;
+ }
+
+
+
+void CExifParser::StoreEntry( TInt aIndex )
+ {
+ TExifEntry* e = iEntry[ aIndex ];
+
+ TUint32 count = e->iCount;
+ TUint32 data = 0;
+ TInt bytes = KTypeLength[ e->iType ] * count;
+ TUint8* d = e->iData;
+
+ bool realData = false;
+
+ if( bytes <= 4 )
+ {
+ // store data to offset
+ TInt i;
+ TInt shift = 0;
+ for( i=0; i<bytes; i++ )
+ {
+ data |= ( d[ i ] << shift );
+ shift += 8;
+ }
+ }
+ else
+ {
+ // more than 4 bytes, store in data section
+ data = StoreData( d, bytes );
+ realData = true;
+ }
+
+ Put16( e->iTag );
+ Put16( e->iType );
+ Put32( count );
+ if( realData )
+ {
+ iDataEntry.Append( iSaveBufPos );
+ }
+ Put32( data );
+ }
+
+
+
+void CExifParser::Put8( TUint8 aData )
+ {
+ iSaveBuf[ iSaveBufPos++ ] = aData;
+ }
+
+
+
+void CExifParser::Put16( TUint16 aData )
+ {
+ Put8( aData & 255 );
+ Put8( aData / 256 );
+ /*
+ if( iIntelByteOrder )
+ {
+ Put8( aData & 255 );
+ Put8( aData / 256 );
+ }
+ else
+ {
+ Put8( aData / 256 );
+ Put8( aData & 255 );
+ }
+ */
+ }
+
+
+
+void CExifParser::Put32( TUint32 aData )
+ {
+ Put16( aData & 65535 );
+ Put16( aData / 65536 );
+ /*
+ if( iIntelByteOrder )
+ {
+ Put16( aData & 65535 );
+ Put16( aData / 65536 );
+ }
+ else
+ {
+ Put16( aData / 65536 );
+ Put16( aData & 65535 );
+ }
+ */
+ }
+
+
+TUint32 CExifParser::StoreData( TUint8* aData, TInt aCount )
+ {
+ if( iSaveDataBufPos & 1 ) iSaveDataBufPos++; // must be even offset
+ TUint32 pos = iSaveDataBufPos;
+ TInt i;
+ for( i=0; i<aCount; i++ )
+ {
+ iSaveDataBuf[ iSaveDataBufPos++ ] = aData[ i ];
+ }
+ return pos;
+ }
+
+
+TInt CExifParser::IfdCount( TInt aIfd )
+ {
+ TInt count = 0;
+ TInt c = iEntry.Count();
+ TInt i;
+ for( i=0; i<c; i++ )
+ {
+ TExifEntry* e = iEntry[ i ];
+ if( e->iIfd == aIfd )
+ {
+ count++;
+ }
+ }
+ return count;
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TInt32 aValue )
+ {
+ TUint32 uvalue = *( TUint32* )( &aValue );
+
+ TUint8* data = new( ELeave )TUint8[ 4 ];
+ CleanupStack::PushL(data);
+ if( iIntelByteOrder )
+ {
+ data[ 0 ] = uvalue & 255;
+ data[ 1 ] = ( uvalue >> 8 ) & 255;
+ data[ 2 ] = ( uvalue >> 16 ) & 255;
+ data[ 3 ] = ( uvalue >> 24 ) & 255;
+ }
+ else
+ {
+ data[ 3 ] = uvalue & 255;
+ data[ 2 ] = ( uvalue >> 8 ) & 255;
+ data[ 1 ] = ( uvalue >> 16 ) & 255;
+ data[ 0 ] = ( uvalue >> 24 ) & 255;
+ }
+ AddTagL( aIfd, aTag, ESLong, data, 4 );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint32 aValue )
+ {
+ TUint8* data = new( ELeave )TUint8[ 4 ];
+ CleanupStack::PushL(data);
+ if( iIntelByteOrder )
+ {
+ data[ 0 ] = aValue & 255;
+ data[ 1 ] = ( aValue >> 8 ) & 255;
+ data[ 2 ] = ( aValue >> 16 ) & 255;
+ data[ 3 ] = ( aValue >> 24 ) & 255;
+ }
+ else
+ {
+ data[ 3 ] = aValue & 255;
+ data[ 2 ] = ( aValue >> 8 ) & 255;
+ data[ 1 ] = ( aValue >> 16 ) & 255;
+ data[ 0 ] = ( aValue >> 24 ) & 255;
+ }
+ AddTagL( aIfd, aTag, ELong, data, 4 );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint16 aValue )
+ {
+ TUint8* data = new( ELeave )TUint8[ 2 ];
+ CleanupStack::PushL(data);
+ if( iIntelByteOrder )
+ {
+ data[ 0 ] = aValue & 255;
+ data[ 1 ] = aValue / 256;
+ }
+ else
+ {
+ data[ 1 ] = aValue & 255;
+ data[ 0 ] = aValue / 256;
+ }
+ AddTagL( aIfd, aTag, EShort, data, 2 );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint8 aValue )
+ {
+ TUint8* data = new( ELeave )TUint8[ 1 ];
+ CleanupStack::PushL(data);
+ *data = aValue;
+ AddTagL( aIfd, aTag, EByte, data, 1 );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TPtrC8 aData )
+ {
+ TUint8* data = new( ELeave )TUint8[ aData.Length() ];
+ CleanupStack::PushL(data);
+ Mem::Copy( data, aData.Ptr(), aData.Length() );
+ AddTagL( aIfd, aTag, EUndefined, data, aData.Length() );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, const TUint8* aValue )
+ {
+ TInt l = User::StringLength( aValue ) + 1;
+ TUint8* data = new( ELeave )TUint8[ l ];
+ CleanupStack::PushL(data);
+ Mem::Copy( data, aValue, l );
+ AddTagL( aIfd, aTag, EAscii, data, l );
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint32 aNominator, TUint32 aDenominator )
+ {
+ TUint8* data = new( ELeave )TUint8[ 8 ];
+ CleanupStack::PushL(data);
+ if( iIntelByteOrder )
+ {
+ data[ 0 ] = aNominator & 255;
+ data[ 1 ] = ( aNominator >> 8 ) & 255;
+ data[ 2 ] = ( aNominator >> 16 ) & 255;
+ data[ 3 ] = ( aNominator >> 24 ) & 255;
+ data[ 4 ] = aDenominator & 255;
+ data[ 5 ] = ( aDenominator >> 8 ) & 255;
+ data[ 6 ] = ( aDenominator >> 16 ) & 255;
+ data[ 7 ] = ( aDenominator >> 24 ) & 255;
+ }
+ else
+ {
+ data[ 3 ] = aNominator & 255;
+ data[ 2 ] = ( aNominator >> 8 ) & 255;
+ data[ 1 ] = ( aNominator >> 16 ) & 255;
+ data[ 0 ] = ( aNominator >> 24 ) & 255;
+ data[ 7 ] = aDenominator & 255;
+ data[ 6 ] = ( aDenominator >> 8 ) & 255;
+ data[ 5 ] = ( aDenominator >> 16 ) & 255;
+ data[ 4 ] = ( aDenominator >> 24 ) & 255;
+ }
+ AddTagL( aIfd, aTag, ERational, data, 8 );
+
+ CleanupStack::Pop();
+ }
+
+
+
+void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TInt aType, TUint8* aData, TInt aDataLen )
+ {
+ TExifEntry* e = new( ELeave )TExifEntry;
+ e->iIfd = aIfd;
+ e->iTag = aTag;
+ e->iType = aType;
+ e->iData = aData;
+ e->iCount = aDataLen / KTypeLength[ aType ];
+ iEntry.Append( e );
+ }
+
+