imageeditorengine/src/CExifParser.cpp
changeset 1 edfc90759b9f
equal deleted inserted replaced
0:57d4cdd99204 1:edfc90759b9f
       
     1 /*
       
     2 * Copyright (c) 2010 Ixonos Plc.
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - Initial contribution
       
    11 *
       
    12 * Contributors:
       
    13 * Ixonos Plc
       
    14 *
       
    15 * Description:  
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "CExifParser.h"
       
    21 #include <e32svr.h>		// for debug
       
    22 
       
    23 
       
    24 
       
    25 enum TExifType
       
    26 	{
       
    27 	EByte = 1,
       
    28 	EAscii,
       
    29 	EShort,
       
    30 	ELong,
       
    31 	ERational,
       
    32 	EUndefined = 7,
       
    33 	ESLong = 9,
       
    34 	ESRational
       
    35 	};
       
    36 
       
    37 
       
    38 
       
    39 const char* KTypeName[] = 
       
    40 	{
       
    41 	"Byte",
       
    42 	"Ascii",
       
    43 	"Short",
       
    44 	"Long",
       
    45 	"Rational",
       
    46 	"Undefined",
       
    47 	"SLong",
       
    48 	"SRational"
       
    49 	};
       
    50 
       
    51 
       
    52 
       
    53 const char KTypeLength[] = 
       
    54 	{
       
    55 	0,
       
    56 	1,
       
    57 	1,
       
    58 	2,
       
    59 	4,
       
    60 	8,
       
    61 	0,
       
    62 	1,
       
    63 	0,
       
    64 	4,
       
    65 	8
       
    66 	};
       
    67 
       
    68 
       
    69 
       
    70 
       
    71 
       
    72 
       
    73 
       
    74 CExifParser* CExifParser::NewL()
       
    75 	{
       
    76 	CExifParser* self = NewLC();
       
    77 	CleanupStack::Pop( self );
       
    78 	return self;
       
    79 	}
       
    80 
       
    81 
       
    82 
       
    83 CExifParser* CExifParser::NewLC()
       
    84 	{
       
    85 	CExifParser* self = new( ELeave )CExifParser();
       
    86 	CleanupStack::PushL( self );
       
    87 	self->ConstructL();
       
    88 	return self;
       
    89 	}
       
    90 
       
    91 
       
    92 
       
    93 CExifParser::~CExifParser()
       
    94 	{
       
    95 	iEntry.ResetAndDestroy();
       
    96 	iParseStack.Reset();
       
    97 
       
    98     delete[] iSaveBuf;
       
    99 	delete[] iSaveDataBuf;
       
   100 	
       
   101 	iThumbData = NULL;    
       
   102 	}
       
   103 
       
   104 
       
   105 
       
   106 CExifParser::CExifParser()
       
   107 	{
       
   108 	
       
   109 	}
       
   110 
       
   111 
       
   112 
       
   113 void CExifParser::ConstructL()
       
   114 	{
       
   115 	iIntelByteOrder = true;
       
   116 	}
       
   117 
       
   118 
       
   119 
       
   120 void CExifParser::ParseL( const TPtrC8& aData )
       
   121 	{
       
   122 	if( aData.Length() < (8+2+12) ) return; // header + 1 tag length
       
   123 
       
   124 	iData.Set( aData );
       
   125 	iThumbData = 0;
       
   126 	iThumbLen = 0;
       
   127 
       
   128 	if( iData[ 0 ] == 0x49 && iData[ 1 ] == 0x49 )
       
   129 		{
       
   130 		// intel byte order
       
   131 		iIntelByteOrder = ETrue;
       
   132 		//RDebug::Print( _L("Intel byte order selected") );
       
   133 		}
       
   134 	else
       
   135 		{
       
   136 		//RDebug::Print( _L("Motorola byte order selected") );
       
   137 		}
       
   138 	
       
   139 	iPosition = 2;
       
   140 	TUint16 v = Get16();
       
   141 	if( v != 0x002a )
       
   142 		{
       
   143 		// must be 2a 00 in EXIF
       
   144 		User::Leave( KErrNotSupported );
       
   145 		}
       
   146 	
       
   147 	iPosition = 4;
       
   148 	iParseStack.Append( TParseStack( Get32(), EIfd0 ) );
       
   149 	
       
   150 	while( iParseStack.Count() )
       
   151 		{
       
   152 		iPosition = iParseStack[ 0 ].iPosition;
       
   153 		TUint8 currentIfd = iParseStack[ 0 ].iIfd;
       
   154 		iParseStack.Remove( 0 );
       
   155 		TInt i;
       
   156 		TInt c = Get16();
       
   157 		for( i=0; i<c; i++ )
       
   158 			{
       
   159 			ParseIfdL( currentIfd );
       
   160 			}
       
   161 		TUint32 link = NULL;	
       
   162 		if (iPosition + 3 < iData.Length())
       
   163 			{
       
   164 			link = Get32();
       
   165 			}
       
   166 			
       
   167 		if( link )
       
   168 			{
       
   169 			//RDebug::Print( _L(" --Link (IFD1?) %d,%d"), link, iPosition );
       
   170 			iParseStack.Append( TParseStack( link, EIfd1 ) );
       
   171 			}
       
   172 		else
       
   173 			{
       
   174 			//RDebug::Print( _L(" -- NULL Link after IFD") );
       
   175 			}
       
   176 		}
       
   177 	iParseStack.Reset();
       
   178 
       
   179 	//RDebug::Print( _L(" -- Parse Complete") );
       
   180 	iIntelByteOrder = true;
       
   181 	}
       
   182 
       
   183 
       
   184 
       
   185 TBool CExifParser::TagExist( TInt aIfd, TUint16 aTag )
       
   186 	{
       
   187 	if( FindTag( aIfd, aTag ) >= 0 ) return ETrue;
       
   188 	return EFalse;
       
   189 	}
       
   190 
       
   191 
       
   192 
       
   193 void CExifParser::DeleteTag( TInt aIfd, TUint16 aTag )
       
   194 	{
       
   195 	TInt i = FindTag( aIfd, aTag );
       
   196 	if( i >= 0 )
       
   197 		{
       
   198 		delete iEntry[ i ];
       
   199 		iEntry.Remove( i );
       
   200 		}
       
   201 	}
       
   202 
       
   203 
       
   204 
       
   205 TUint32 CExifParser::TagValue( TInt aIfd, TUint16 aTag )
       
   206 	{
       
   207 	TInt value = 0;
       
   208 	TInt n = FindTag( aIfd, aTag );
       
   209 	if( n<0 ) return 0;
       
   210 	TExifEntry* e = iEntry[ n ];
       
   211 	TUint8* valData = e->iData;
       
   212 	switch( e->iType )
       
   213 		{
       
   214 		case EByte:
       
   215 			{
       
   216 			value = Get8( valData );
       
   217 			break;
       
   218 			}
       
   219 		case EAscii:
       
   220 			{
       
   221 			/*
       
   222 			TBuf< 256 >str;
       
   223 			str.Copy( _L("value:") );
       
   224 			const TUint8* p = valData;
       
   225 			while( *p != 0 )
       
   226 				{
       
   227 				str.Append( *p );
       
   228 				p++;
       
   229 				}
       
   230 			*/
       
   231 			// not supported
       
   232 			value = 0;
       
   233 			break;
       
   234 			}
       
   235 		case EShort:
       
   236 			{
       
   237 			value = Get16( valData );
       
   238 			////RDebug::Print( _L("value:%d"), value );
       
   239 			break;
       
   240 			}
       
   241 		case ELong:
       
   242 			{
       
   243 			value = Get32( valData );
       
   244 			////RDebug::Print( _L("value:%d"), value );
       
   245 			break;
       
   246 			}
       
   247 		case ERational:
       
   248 			{
       
   249 			TInt nominator = Get32( valData );
       
   250 			TInt denominator = Get32( valData+4 );
       
   251 			////RDebug::Print( _L("value:%d/%d"), nominator, denominator );
       
   252 			if( denominator != 0 )
       
   253 				{
       
   254 				value = nominator / denominator;
       
   255 				}
       
   256 			else
       
   257 				{
       
   258 				value = 0;
       
   259 				}
       
   260 			break;
       
   261 			}
       
   262 		case EUndefined:
       
   263 			{
       
   264 			
       
   265 			break;
       
   266 			}
       
   267 		case ESLong:
       
   268 			{
       
   269 			TUint32 val = Get32( valData );
       
   270 			value = *(TInt*)(&val);
       
   271 			////RDebug::Print( _L("value:%d"), svalue );
       
   272 
       
   273 			break;
       
   274 			}
       
   275 		case ESRational:
       
   276 			{
       
   277 			TUint32 uval = Get32( valData );
       
   278 			TInt nominator = *(TInt*)(&uval);
       
   279 			uval = Get32( valData+4 );
       
   280 			TInt denominator = *(TInt*)(&uval);
       
   281 
       
   282 			if( denominator != 0 )
       
   283 				{
       
   284 				value = nominator / denominator;
       
   285 				}
       
   286 			else
       
   287 				{
       
   288 				value = 0;
       
   289 				}
       
   290 			////RDebug::Print( _L("value:%d/%d"), nominator, denominator );
       
   291 			break;
       
   292 			}
       
   293 		default:
       
   294 		 	{
       
   295 		 	break;
       
   296 		 	}
       
   297 		}	
       
   298 
       
   299 	return value;
       
   300 	}
       
   301 
       
   302 TPtrC8 CExifParser::ThumbData()
       
   303 	{
       
   304 	return TPtrC8( iThumbData, iThumbLen );
       
   305 	}
       
   306 
       
   307 
       
   308 TPtr8 CExifParser::SaveL( const TPtrC8& aThumbData )
       
   309 	{
       
   310 	iIntelByteOrder = true;
       
   311 	//
       
   312 	// Exif data cannot take more than 64KBytes
       
   313 	//
       
   314 	if (iSaveBuf)
       
   315 	{
       
   316 	    delete[] iSaveBuf;
       
   317 	    iSaveBuf = NULL;
       
   318 	}
       
   319 	
       
   320 	iSaveBuf = new( ELeave )TUint8[ 0x10000 ];
       
   321 	iSaveBufPos = 0;
       
   322 
       
   323 	if (iSaveDataBuf)
       
   324 	{
       
   325     	delete[] iSaveDataBuf;
       
   326     	iSaveDataBuf = NULL;	    
       
   327 	}
       
   328 
       
   329 	iSaveDataBuf = new( ELeave )TUint8[ 0x10000 ];
       
   330 	iSaveDataBufPos = 0;
       
   331 
       
   332 	//
       
   333 	// header
       
   334 	//
       
   335 	Put8( 0x49 );
       
   336 	Put8( 0x49 );
       
   337 	Put8( 0x2a );
       
   338 	Put8( 0x00 );
       
   339 	Put32( 8 );
       
   340 
       
   341 	//
       
   342 	// Remove IFD0 SubIfd tag, will be regenerated
       
   343 	//
       
   344 	DeleteTag( EIfd0, 0x8769 );
       
   345 
       
   346 	//
       
   347 	// Save IFD0
       
   348 	//
       
   349 	Put16( IfdCount( EIfd0 ) + 1 );
       
   350 	TInt c = iEntry.Count();
       
   351 	TInt i;
       
   352 	for( i=0; i<c; i++ )
       
   353 		{
       
   354 		TExifEntry* e = iEntry[ i ];
       
   355 		if( e->iIfd == EIfd0 )
       
   356 			{
       
   357 			StoreEntry( i );
       
   358 			}
       
   359 		}
       
   360 
       
   361 	//
       
   362 	// Save link to SubIfd ( this is a tag )
       
   363 	//
       
   364 	TExifEntry* tagsub = new( ELeave )TExifEntry;
       
   365 	CleanupStack::PushL(tagsub);
       
   366 	tagsub->iTag = 0x8769;
       
   367 	tagsub->iIfd = EIfd0;
       
   368 	tagsub->iType = ELong;
       
   369 	tagsub->iCount = 1;
       
   370 	tagsub->iData = new( ELeave )TUint8[ 4 ];
       
   371 	TUint8* dat = tagsub->iData;
       
   372 	TUint32 offset = iSaveBufPos + 12 + 4; // just after IFD1 link
       
   373 	if( iIntelByteOrder )
       
   374 		{
       
   375 		dat[ 0 ] = offset & 255; offset >>= 8;
       
   376 		dat[ 1 ] = offset & 255; offset >>= 8;
       
   377 		dat[ 2 ] = offset & 255; offset >>= 8;
       
   378 		dat[ 3 ] = offset & 255;
       
   379 		}
       
   380 	else
       
   381 		{
       
   382 		dat[ 3 ] = offset & 255; offset >>= 8;
       
   383 		dat[ 2 ] = offset & 255; offset >>= 8;
       
   384 		dat[ 1 ] = offset & 255; offset >>= 8;
       
   385 		dat[ 0 ] = offset & 255;
       
   386 		}
       
   387 	iEntry.Append( tagsub );
       
   388 	CleanupStack::Pop();
       
   389 	StoreEntry( iEntry.Count()-1 );
       
   390 	
       
   391 	//
       
   392 	// Save link to IFD1 ( not a tag, just pointer )
       
   393 	//
       
   394 	TInt IFD1LinkPos = iSaveBufPos;
       
   395 	Put32( 0 );
       
   396 
       
   397 	//
       
   398 	// Remove Interoperability tag, will be regenerated
       
   399 	//
       
   400 	DeleteTag( ESubIfd, 0xa005 );
       
   401 	c = iEntry.Count();
       
   402 
       
   403 	//
       
   404 	// Save SubIfd
       
   405 	//
       
   406 	Put16( IfdCount( ESubIfd ) );
       
   407 	//RDebug::Print( _L(" SUBIFD count %x"), IfdCount( ESubIfd ) );
       
   408 	for( i=0; i<c; i++ )
       
   409 		{
       
   410 		TExifEntry* e = iEntry[ i ];
       
   411 		if( e->iIfd == ESubIfd )
       
   412 			{
       
   413 			//RDebug::Print( _L("  SUBIFD %x"), e->iTag );
       
   414 			StoreEntry( i );
       
   415 			}
       
   416 		}
       
   417 /*	
       
   418 	TExifEntry* tagint = new( ELeave )TExifEntry;
       
   419 	tagint->iTag = 0xa005;
       
   420 	tagint->iIfd = ESubIfd;
       
   421 	tagint->iType = ELong;
       
   422 	tagint->iCount = 1;
       
   423 	tagint->iData = new( ELeave )TUint8[ 4 ];
       
   424 	TUint8* dat2 = tagint->iData;
       
   425 	TUint32 offset2 = iSaveBufPos + 12 + 4; // just after IFD link
       
   426 	if( iIntelByteOrder )
       
   427 		{
       
   428 		dat2[ 0 ] = offset2 & 255; offset2 >>= 8;
       
   429 		dat2[ 1 ] = offset2 & 255; offset2 >>= 8;
       
   430 		dat2[ 2 ] = offset2 & 255; offset2 >>= 8;
       
   431 		dat2[ 3 ] = offset2 & 255;
       
   432 		}
       
   433 	else
       
   434 		{
       
   435 		dat2[ 3 ] = offset2 & 255; offset2 >>= 8;
       
   436 		dat2[ 2 ] = offset2 & 255; offset2 >>= 8;
       
   437 		dat2[ 1 ] = offset2 & 255; offset2 >>= 8;
       
   438 		dat2[ 0 ] = offset2 & 255;
       
   439 		}
       
   440 	iEntry.Append( tagint );
       
   441 	StoreEntry( iEntry.Count()-1 );
       
   442 */
       
   443 	Put32( 0 ); // IFD link
       
   444 
       
   445 /*	
       
   446 	//
       
   447 	// Save Interoperability
       
   448 	//
       
   449 	Put16( IfdCount( EInteroperability ) );
       
   450 	c = iEntry.Count();
       
   451 	for( i=0; i<c; i++ )
       
   452 		{
       
   453 		TExifEntry* e = iEntry[ i ];
       
   454 		if( e->iIfd == EInteroperability )
       
   455 			{
       
   456 			StoreEntry( i );
       
   457 			}
       
   458 		}
       
   459 	Put32( 0 ); // IFD link
       
   460 */
       
   461 	//
       
   462 	// Save IFD1 ( thumbnail ) if new thumbnail given
       
   463 	//
       
   464 	if( aThumbData.Ptr() )
       
   465 		{
       
   466 		TUint32 temp = iSaveBufPos;
       
   467 		iSaveBufPos = IFD1LinkPos;
       
   468 		Put32( temp );
       
   469 		iSaveBufPos = temp;
       
   470 		}
       
   471 
       
   472 	//
       
   473 	// Remove old thumbnail tags
       
   474 	//
       
   475 	c = iEntry.Count();
       
   476 	i = 0;
       
   477 	while( i < iEntry.Count() )
       
   478 		{
       
   479 		TExifEntry* e = iEntry[ i ];
       
   480 		if( e->iIfd == EIfd1 )
       
   481 			{
       
   482 			delete e;
       
   483 			iEntry.Remove( i );
       
   484 			}
       
   485 		else
       
   486 			{
       
   487 			i++;
       
   488 			}
       
   489 		}
       
   490 
       
   491 	//
       
   492 	// Add newe thumbnail tags ( if thumbnail given )
       
   493 	//
       
   494 	TInt thumbData = 0;
       
   495 	if( aThumbData.Ptr() )
       
   496 		{
       
   497 		AddTagL( EIfd1, 0x0103, (TUint16)6 );			// thumbnail = jpeg
       
   498 		
       
   499 		// thumbnail X-resolution 180/1
       
   500 		AddTagL( EIfd1, 0x011a, (TUint32)180, (TUint32)1 );			 
       
   501 		
       
   502 		// thumbnail Y-resolution 180/1
       
   503 		AddTagL( EIfd1, 0x011b, (TUint32)180, (TUint32)1 );
       
   504 		
       
   505 		// thumbnail resolution unit = inch
       
   506 		AddTagL( EIfd1, 0x0128, (TUint16)2 );
       
   507 
       
   508 		AddTagL( EIfd1, 0x0201, (TUint32)0 );			// thumb offset
       
   509 		AddTagL( EIfd1, 0x0202, (TUint32)aThumbData.Length() );	// thumb length
       
   510 		
       
   511 	
       
   512 		Put16( IfdCount( EIfd1 ) );
       
   513 		c = iEntry.Count();
       
   514 		for( i=0; i<c; i++ )
       
   515 			{
       
   516 			TExifEntry* e = iEntry[ i ];
       
   517 			if( e->iIfd == EIfd1 )
       
   518 				{
       
   519 				StoreEntry( i );
       
   520 				}
       
   521 			}
       
   522 		
       
   523 
       
   524 		thumbData = iSaveBufPos - 12 - 4; // tag 0x0201 data position
       
   525 
       
   526 		Put32( 0 ); // IFD link
       
   527 		}
       
   528 
       
   529 	//
       
   530 	// Copy tag data to same buffer with tags
       
   531 	//
       
   532 	Mem::Copy( iSaveBuf + iSaveBufPos, iSaveDataBuf, iSaveDataBufPos );
       
   533 	TInt totalLength = iSaveBufPos + iSaveDataBufPos;
       
   534 
       
   535 	//
       
   536 	// Copy thumbnail data to same buffer
       
   537 	//
       
   538 	if( thumbData )
       
   539 		{
       
   540 		TInt temp = iSaveBufPos;
       
   541 		iSaveBufPos = thumbData;
       
   542 		Put32( totalLength );
       
   543 		iSaveBufPos = temp;
       
   544 		
       
   545 		Mem::Copy( iSaveBuf + totalLength, aThumbData.Ptr(), aThumbData.Length() );
       
   546 		totalLength += aThumbData.Length();
       
   547 		}	
       
   548 	//
       
   549 	// update data pointers
       
   550 	//
       
   551 	if( iSaveBufPos & 1 ) iSaveBufPos++;		// data must be in even address
       
   552 	TInt doffset = iSaveBufPos;
       
   553 	c = iDataEntry.Count();
       
   554 	for( i=0; i<c; i++ )
       
   555 		{
       
   556 		iSaveBufPos = iDataEntry[ i ];
       
   557 		TUint32 ptr = Get32( iSaveBuf + iSaveBufPos );
       
   558 		ptr += doffset;
       
   559 		Put32( ptr );
       
   560 		}
       
   561 
       
   562 	delete[] iSaveDataBuf;
       
   563 	iSaveDataBuf = NULL;
       
   564 	iDataEntry.Reset();
       
   565 	
       
   566 	TPtr8 buffer( iSaveBuf, totalLength );
       
   567 	buffer.SetLength( totalLength );
       
   568 	return buffer;
       
   569 	}
       
   570 
       
   571 
       
   572 
       
   573 TUint32 CExifParser::Get8()
       
   574 	{
       
   575 	return iData[ iPosition++ ];
       
   576 
       
   577 	}
       
   578 
       
   579 
       
   580 
       
   581 TUint32 CExifParser::Get16()
       
   582 	{
       
   583 	TUint32 value;
       
   584 	if( iIntelByteOrder )
       
   585 		{
       
   586 		value = 256 * iData[ iPosition + 1 ] + iData[ iPosition ];
       
   587 		}
       
   588 	else
       
   589 		{
       
   590 		value = 256 * iData[ iPosition ] + iData[ iPosition + 1 ];
       
   591 		}
       
   592 	iPosition += 2;
       
   593 	return value;	
       
   594 	}
       
   595 
       
   596 
       
   597 
       
   598 TUint32 CExifParser::Get32()
       
   599 	{
       
   600 	TUint32 value;
       
   601 	if( iIntelByteOrder )
       
   602 		{
       
   603 		value = iData[ iPosition + 3 ];
       
   604 		value <<= 8;
       
   605 		value |= iData[ iPosition + 2 ];
       
   606 		value <<= 8;
       
   607 		value |= iData[ iPosition + 1 ];
       
   608 		value <<= 8;
       
   609 		value |= iData[ iPosition + 0 ];
       
   610 		}
       
   611 	else
       
   612 		{
       
   613 		value = iData[ iPosition + 0 ];
       
   614 		value <<= 8;
       
   615 		value |= iData[ iPosition + 1 ];
       
   616 		value <<= 8;
       
   617 		value |= iData[ iPosition + 2 ];
       
   618 		value <<= 8;
       
   619 		value |= iData[ iPosition + 3 ];
       
   620 		}
       
   621 	iPosition += 4;
       
   622 	return value;	
       
   623 	}
       
   624 
       
   625 
       
   626 
       
   627 TUint32 CExifParser::Get8( const TUint8* aData )
       
   628 	{
       
   629 	return *aData;
       
   630 	}
       
   631 
       
   632 
       
   633 
       
   634 TUint32 CExifParser::Get16( const TUint8* aData )
       
   635 	{
       
   636 	TUint32 value;
       
   637 	if( iIntelByteOrder )
       
   638 		{
       
   639 		value = 256 * aData[ 1 ] + aData[ 0 ];
       
   640 		}
       
   641 	else
       
   642 		{
       
   643 		value = 256 * aData[ 0 ] + aData[ 1 ];
       
   644 		}
       
   645 	return value;	
       
   646 	}
       
   647 
       
   648 
       
   649 
       
   650 TUint32 CExifParser::Get32( const TUint8* aData )
       
   651 	{
       
   652 	TUint32 value;
       
   653 	if( iIntelByteOrder )
       
   654 		{
       
   655 		value = aData[ 3 ];
       
   656 		value <<= 8;
       
   657 		value |= aData[ 2 ];
       
   658 		value <<= 8;
       
   659 		value |= aData[ 1 ];
       
   660 		value <<= 8;
       
   661 		value |= aData[ 0 ];
       
   662 		}
       
   663 	else
       
   664 		{
       
   665 		value = aData[ 0 ];
       
   666 		value <<= 8;
       
   667 		value |= aData[ 1 ];
       
   668 		value <<= 8;
       
   669 		value |= aData[ 2 ];
       
   670 		value <<= 8;
       
   671 		value |= aData[ 3 ];
       
   672 		}
       
   673 	return value;	
       
   674 	}
       
   675 
       
   676 
       
   677 
       
   678 void CExifParser::ParseIfdL( TUint8 aIfd )
       
   679 	{
       
   680 	TUint32 tag = Get16();
       
   681 	TUint32 type = Get16();
       
   682 	TUint32 count = Get32();
       
   683 	TUint32 offset = Get32();
       
   684 	TUint32 revOffset = ( ( offset & 0xff ) << 24 ) + ( ( offset & 0xff00 ) << 8 ) + ( ( offset & 0xff0000 ) >> 8 ) + ( ( offset & 0xff000000 ) >> 24 );
       
   685 
       
   686 	RDebug::Print( _L("Pos %d, Tag %x, type %d, count %d, offset %d, ifd %d"), iPosition-14, tag, type, count, offset, aIfd );
       
   687 	
       
   688 	const TUint8* valData = NULL;
       
   689 
       
   690 	TInt bytes = KTypeLength[ type ] * count;
       
   691 
       
   692 	if( bytes > 4 )
       
   693 		{
       
   694 		valData = &iData[ offset ];
       
   695 		}
       
   696 	else
       
   697 		{
       
   698 		if( iIntelByteOrder )
       
   699 			{
       
   700 			valData = (const TUint8*)(&offset);
       
   701 			}
       
   702 		else
       
   703 			{
       
   704 			// offset already reversed
       
   705 			// must use reversed offset
       
   706 			valData = (const TUint8*)(&revOffset);
       
   707 			}
       
   708 		}
       
   709 
       
   710 
       
   711 	TExifEntry* entry = new( ELeave )TExifEntry;
       
   712 	CleanupStack::PushL(entry);
       
   713 	entry->iIfd = aIfd;
       
   714 	entry->iTag = tag;
       
   715 	entry->iType = type;
       
   716 	entry->iCount = count;
       
   717 	
       
   718 	TUint32 value = 0;
       
   719 		
       
   720 	entry->iData = new( ELeave )TUint8[ bytes ];
       
   721 	if( iIntelByteOrder )
       
   722 		{
       
   723 		Mem::Copy( entry->iData, valData, bytes );
       
   724 		switch( type )
       
   725 			{
       
   726 			case EByte:
       
   727 				{
       
   728 				value = Get8( valData );
       
   729 				break;
       
   730 				}
       
   731 			case EShort:
       
   732 				{
       
   733 				value = Get16( valData );
       
   734 				break;
       
   735 				}
       
   736 			case ELong:
       
   737 			case ESLong:
       
   738 				{
       
   739 				value = Get32( valData );
       
   740 				break;
       
   741 				}
       
   742 			default:
       
   743 				break;
       
   744 			}
       
   745 		}
       
   746 	else
       
   747 		{
       
   748 		
       
   749 		switch( type )
       
   750 			{
       
   751 			case EByte:
       
   752 				{
       
   753 				value = Get8( valData );
       
   754 				entry->iData[ 0 ] = value;
       
   755 				break;
       
   756 				}
       
   757 			case EAscii:
       
   758 				{
       
   759 				Mem::Copy( entry->iData, valData, bytes );
       
   760 				//RDebug::Print( str );
       
   761 				break;
       
   762 				}
       
   763 			case EShort:
       
   764 				{
       
   765 				entry->iData[ 1 ] = Get8( valData );
       
   766 				entry->iData[ 0 ] = Get8( valData+1 );
       
   767 				value = Get16( valData );
       
   768 				break;
       
   769 				}
       
   770 			case ELong:
       
   771 			case ESLong:
       
   772 				{
       
   773 				entry->iData[ 3 ] = Get8( valData );
       
   774 				entry->iData[ 2 ] = Get8( valData+1 );
       
   775 				entry->iData[ 1 ] = Get8( valData+2 );
       
   776 				entry->iData[ 0 ] = Get8( valData+3 );
       
   777 				value = Get32( valData );
       
   778 				break;
       
   779 				}
       
   780 			case ERational:
       
   781 			case ESRational:
       
   782 				{
       
   783 				entry->iData[ 3 ] = Get8( valData );
       
   784 				entry->iData[ 2 ] = Get8( valData+1 );
       
   785 				entry->iData[ 1 ] = Get8( valData+2 );
       
   786 				entry->iData[ 0 ] = Get8( valData+3 );
       
   787 
       
   788 				entry->iData[ 7 ] = Get8( valData+4 );
       
   789 				entry->iData[ 6 ] = Get8( valData+5 );
       
   790 				entry->iData[ 5 ] = Get8( valData+6 );
       
   791 				entry->iData[ 4 ] = Get8( valData+7 );
       
   792 				break;
       
   793 				}
       
   794 			case EUndefined:
       
   795 			default:
       
   796 				{
       
   797 				Mem::Copy( entry->iData, valData, bytes );
       
   798 				break;
       
   799 				}
       
   800 			}
       
   801 		}
       
   802 	//RDebug::Print( _L("value=%d"), value );
       
   803 	
       
   804 	iEntry.Append( entry );
       
   805 	CleanupStack::Pop();
       
   806 	
       
   807 
       
   808 	if( tag == 0x927c )
       
   809 		{
       
   810 		//RDebug::Print( _L(" --MakerNote") );
       
   811 		}
       
   812 
       
   813 	if( tag == 0x8769 )
       
   814 		{
       
   815 		iParseStack.Append( TParseStack( value, ESubIfd ) );
       
   816 		//RDebug::Print( _L(" --SubIfd %d, %d"), value, iPosition );
       
   817 		}
       
   818 
       
   819 	if( tag == 0xa005 )
       
   820 		{
       
   821 		iParseStack.Append( TParseStack( value, EInteroperability ) );
       
   822 		//RDebug::Print( _L(" --Interoperability, %d, %d"), value, iPosition );
       
   823 		}
       
   824 
       
   825 	if( aIfd == EIfd1 )
       
   826 		{
       
   827 		if( tag == 0x0201 )
       
   828 			{
       
   829 			iThumbData = ((TUint8*)iData.Ptr()) + value;
       
   830 			}
       
   831 		if( tag == 0x0202 )
       
   832 			{
       
   833 			iThumbLen = value;
       
   834 			}
       
   835 		}
       
   836 	}
       
   837 
       
   838 
       
   839 
       
   840 TInt CExifParser::FindTag( TInt aIfd, TUint16 aTag )
       
   841 	{
       
   842 	TInt i;
       
   843 	TInt c = iEntry.Count();
       
   844 	for( i=0; i<c; i++ )
       
   845 		{
       
   846 		if( iEntry[ i ]->iIfd == aIfd )
       
   847 			{
       
   848 			if( iEntry[ i ]->iTag == aTag ) return i;
       
   849 			}
       
   850 		}
       
   851 	return -1;
       
   852 	}
       
   853 
       
   854 
       
   855 
       
   856 void CExifParser::StoreEntry( TInt aIndex )
       
   857 	{
       
   858 	TExifEntry* e = iEntry[ aIndex ];
       
   859 
       
   860 	TUint32 count = e->iCount;
       
   861 	TUint32 data = 0;
       
   862 	TInt bytes = KTypeLength[ e->iType ] * count;
       
   863 	TUint8* d = e->iData;
       
   864 
       
   865 	bool realData = false;
       
   866 
       
   867 	if( bytes <= 4 )
       
   868 		{
       
   869 		// store data to offset
       
   870 		TInt i;
       
   871 		TInt shift = 0;
       
   872 		for( i=0; i<bytes; i++ )
       
   873 			{
       
   874 			data |= ( d[ i ] << shift );
       
   875 			shift += 8;
       
   876 			}
       
   877 		}
       
   878 	else
       
   879 		{
       
   880 		// more than 4 bytes, store in data section
       
   881 		data = StoreData( d, bytes );
       
   882 		realData = true;
       
   883 		}
       
   884 
       
   885 	Put16( e->iTag );
       
   886 	Put16( e->iType );
       
   887 	Put32( count );
       
   888 	if( realData )
       
   889 		{
       
   890 		iDataEntry.Append( iSaveBufPos );
       
   891 		}
       
   892 	Put32( data );
       
   893 	}
       
   894 
       
   895 
       
   896 
       
   897 void CExifParser::Put8( TUint8 aData )
       
   898 	{
       
   899 	iSaveBuf[ iSaveBufPos++ ] = aData;
       
   900 	}
       
   901 	
       
   902 
       
   903 
       
   904 void CExifParser::Put16( TUint16 aData )
       
   905 	{
       
   906 	Put8( aData & 255 );
       
   907 	Put8( aData / 256 );
       
   908 	/*
       
   909 	if( iIntelByteOrder )
       
   910 		{
       
   911 		Put8( aData & 255 );
       
   912 		Put8( aData / 256 );
       
   913 		}
       
   914 	else
       
   915 		{
       
   916 		Put8( aData / 256 );
       
   917 		Put8( aData & 255 );
       
   918 		}
       
   919 	*/
       
   920 	}
       
   921 	
       
   922 
       
   923 
       
   924 void CExifParser::Put32( TUint32 aData )
       
   925 	{
       
   926 	Put16( aData & 65535 );
       
   927 	Put16( aData / 65536 );
       
   928 	/*
       
   929 	if( iIntelByteOrder )
       
   930 		{
       
   931 		Put16( aData & 65535 );
       
   932 		Put16( aData / 65536 );
       
   933 		}
       
   934 	else
       
   935 		{
       
   936 		Put16( aData / 65536 );
       
   937 		Put16( aData & 65535 );
       
   938 		}	
       
   939 	*/
       
   940 	}
       
   941 
       
   942 
       
   943 TUint32 CExifParser::StoreData( TUint8* aData, TInt aCount )
       
   944 	{
       
   945 	if( iSaveDataBufPos & 1 ) iSaveDataBufPos++;	// must be even offset
       
   946 	TUint32 pos = iSaveDataBufPos;
       
   947 	TInt i;
       
   948 	for( i=0; i<aCount; i++ )
       
   949 		{
       
   950 		iSaveDataBuf[ iSaveDataBufPos++ ] = aData[ i ];
       
   951 		}
       
   952 	return pos;
       
   953 	}
       
   954 
       
   955 
       
   956 TInt CExifParser::IfdCount( TInt aIfd )
       
   957 	{
       
   958 	TInt count = 0;
       
   959 	TInt c = iEntry.Count();
       
   960 	TInt i;
       
   961 	for( i=0; i<c; i++ )
       
   962 		{
       
   963 		TExifEntry* e = iEntry[ i ];
       
   964 		if( e->iIfd == aIfd )
       
   965 			{
       
   966 			count++;
       
   967 			}
       
   968 		}
       
   969 	return count;
       
   970 	}
       
   971 
       
   972 
       
   973 
       
   974 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TInt32 aValue )
       
   975 	{
       
   976 	TUint32 uvalue = *( TUint32* )( &aValue );
       
   977 
       
   978 	TUint8* data = new( ELeave )TUint8[ 4 ];
       
   979 	CleanupStack::PushL(data);
       
   980 	if( iIntelByteOrder )
       
   981 		{
       
   982 		data[ 0 ] = uvalue & 255;
       
   983 		data[ 1 ] = ( uvalue >> 8 ) & 255;
       
   984 		data[ 2 ] = ( uvalue >> 16 ) & 255;
       
   985 		data[ 3 ] = ( uvalue >> 24 ) & 255;
       
   986 		}
       
   987 	else
       
   988 		{
       
   989 		data[ 3 ] = uvalue & 255;
       
   990 		data[ 2 ] = ( uvalue >> 8 ) & 255;
       
   991 		data[ 1 ] = ( uvalue >> 16 ) & 255;
       
   992 		data[ 0 ] = ( uvalue >> 24 ) & 255;
       
   993 		}
       
   994 	AddTagL( aIfd, aTag, ESLong, data, 4 );
       
   995 	CleanupStack::Pop();
       
   996 	}
       
   997 
       
   998 
       
   999 
       
  1000 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint32 aValue )
       
  1001 	{
       
  1002 	TUint8* data = new( ELeave )TUint8[ 4 ];
       
  1003 	CleanupStack::PushL(data);
       
  1004 	if( iIntelByteOrder )
       
  1005 		{
       
  1006 		data[ 0 ] = aValue & 255;
       
  1007 		data[ 1 ] = ( aValue >> 8 ) & 255;
       
  1008 		data[ 2 ] = ( aValue >> 16 ) & 255;
       
  1009 		data[ 3 ] = ( aValue >> 24 ) & 255;
       
  1010 		}
       
  1011 	else
       
  1012 		{
       
  1013 		data[ 3 ] = aValue & 255;
       
  1014 		data[ 2 ] = ( aValue >> 8 ) & 255;
       
  1015 		data[ 1 ] = ( aValue >> 16 ) & 255;
       
  1016 		data[ 0 ] = ( aValue >> 24 ) & 255;
       
  1017 		}
       
  1018 	AddTagL( aIfd, aTag, ELong, data, 4 );
       
  1019 	CleanupStack::Pop();
       
  1020 	}
       
  1021 
       
  1022 
       
  1023 
       
  1024 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint16 aValue )
       
  1025 	{
       
  1026 	TUint8* data = new( ELeave )TUint8[ 2 ];
       
  1027 	CleanupStack::PushL(data);
       
  1028 	if( iIntelByteOrder )
       
  1029 		{
       
  1030 		data[ 0 ] = aValue & 255;
       
  1031 		data[ 1 ] = aValue / 256;
       
  1032 		}
       
  1033 	else
       
  1034 		{
       
  1035 		data[ 1 ] = aValue & 255;
       
  1036 		data[ 0 ] = aValue / 256;
       
  1037 		}
       
  1038 	AddTagL( aIfd, aTag, EShort, data, 2 );
       
  1039 	CleanupStack::Pop();
       
  1040 	}
       
  1041 
       
  1042 
       
  1043 
       
  1044 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint8 aValue )
       
  1045 	{
       
  1046 	TUint8* data = new( ELeave )TUint8[ 1 ];
       
  1047 	CleanupStack::PushL(data);
       
  1048 	*data = aValue;
       
  1049 	AddTagL( aIfd, aTag, EByte, data, 1 );
       
  1050 	CleanupStack::Pop();
       
  1051 	}
       
  1052 
       
  1053 
       
  1054 
       
  1055 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TPtrC8 aData )
       
  1056 	{
       
  1057 	TUint8* data = new( ELeave )TUint8[ aData.Length() ];
       
  1058 	CleanupStack::PushL(data);
       
  1059 	Mem::Copy( data, aData.Ptr(), aData.Length() );
       
  1060 	AddTagL( aIfd, aTag, EUndefined, data, aData.Length() );
       
  1061 	CleanupStack::Pop();
       
  1062 	}
       
  1063 
       
  1064 
       
  1065 
       
  1066 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, const TUint8* aValue )
       
  1067 	{
       
  1068 	TInt l = User::StringLength( aValue ) + 1;
       
  1069 	TUint8* data = new( ELeave )TUint8[ l ];
       
  1070 	CleanupStack::PushL(data);
       
  1071 	Mem::Copy( data, aValue, l );
       
  1072 	AddTagL( aIfd, aTag, EAscii, data, l );
       
  1073 	CleanupStack::Pop();
       
  1074 	}
       
  1075 
       
  1076 
       
  1077 
       
  1078 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TUint32 aNominator, TUint32 aDenominator )
       
  1079 	{
       
  1080 	TUint8* data = new( ELeave )TUint8[ 8 ];
       
  1081 	CleanupStack::PushL(data);
       
  1082 	if( iIntelByteOrder )
       
  1083 		{
       
  1084 		data[ 0 ] = aNominator & 255;
       
  1085 		data[ 1 ] = ( aNominator >> 8 ) & 255;
       
  1086 		data[ 2 ] = ( aNominator >> 16 ) & 255;
       
  1087 		data[ 3 ] = ( aNominator >> 24 ) & 255;
       
  1088 		data[ 4 ] = aDenominator & 255;
       
  1089 		data[ 5 ] = ( aDenominator >> 8 ) & 255;
       
  1090 		data[ 6 ] = ( aDenominator >> 16 ) & 255;
       
  1091 		data[ 7 ] = ( aDenominator >> 24 ) & 255;
       
  1092 		}
       
  1093 	else
       
  1094 		{
       
  1095 		data[ 3 ] = aNominator & 255;
       
  1096 		data[ 2 ] = ( aNominator >> 8 ) & 255;
       
  1097 		data[ 1 ] = ( aNominator >> 16 ) & 255;
       
  1098 		data[ 0 ] = ( aNominator >> 24 ) & 255;
       
  1099 		data[ 7 ] = aDenominator & 255;
       
  1100 		data[ 6 ] = ( aDenominator >> 8 ) & 255;
       
  1101 		data[ 5 ] = ( aDenominator >> 16 ) & 255;
       
  1102 		data[ 4 ] = ( aDenominator >> 24 ) & 255;
       
  1103 		}
       
  1104 	AddTagL( aIfd, aTag, ERational, data, 8 );
       
  1105 	
       
  1106 	CleanupStack::Pop();
       
  1107 	}
       
  1108 
       
  1109 
       
  1110 
       
  1111 void CExifParser::AddTagL( TInt aIfd, TUint16 aTag, TInt aType, TUint8* aData, TInt aDataLen )
       
  1112 	{
       
  1113 	TExifEntry* e = new( ELeave )TExifEntry;
       
  1114 	e->iIfd = aIfd;
       
  1115 	e->iTag = aTag;
       
  1116 	e->iType = aType;
       
  1117 	e->iData = aData;
       
  1118 	e->iCount = aDataLen / KTypeLength[ aType ];
       
  1119 	iEntry.Append( e );
       
  1120 	}
       
  1121 
       
  1122