imaging/imagingplugins/codecs/JPEGCodec/Exif/exifreaderwriter.cpp
changeset 0 5752a19fdefe
equal deleted inserted replaced
-1:000000000000 0:5752a19fdefe
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <f32file.h>
       
    17 #include "exifreaderwriter.h"
       
    18 
       
    19 #include "ImageUtils.h"
       
    20 #include "ExifTagHelper.h"
       
    21 #include "ExifGeneralConsts.h"
       
    22 #include "ifdgeneral.h"
       
    23 #include "ExifTagDescriptions.h"
       
    24 
       
    25 // used for ordering exif tags when writing them
       
    26 const TInt KNumIfds = 5;
       
    27 const TInt KIfdOrder[KNumIfds] = 
       
    28 	{
       
    29 	EZeroth, 
       
    30 	EExifSub,
       
    31 	EInterop,
       
    32 	EGpsSub,
       
    33 	EFirst
       
    34 	};
       
    35 	
       
    36 HBufC8* CExifReaderWriter::CreateExifHeaderBaseL()
       
    37 	{
       
    38 	//write the GPS IFD tag in IFD 0 - need to write it twice to ensure correct offset
       
    39 	//the second write we have the correct offset
       
    40 	for (TInt i = 0; i < iIfds.Count(); i++)
       
    41 		{
       
    42 		if ((iIfds)[i]->Ifd() == EGpsSub)
       
    43 			{
       
    44 			if ((iIfds)[i]->Size())
       
    45 				{
       
    46 				TUint gpsIFDoffset = KIfdOffset;
       
    47 				TInt result = SetIntegerParam(KTag8825[ETagValue], EZeroth, gpsIFDoffset);
       
    48 				if (result != KErrNone)
       
    49 					{
       
    50 					User::Leave(result);
       
    51 					}
       
    52 				//loop through IFDs
       
    53 				for (TUint j = 0; j < iIfds.Count(); j++)
       
    54 	 				{
       
    55 	 				//calculate the offset to the GPS IFD 
       
    56 	 				TInt ifd = (iIfds)[j]->Ifd();
       
    57 	 				if (ifd <= EInterop)
       
    58 	 					{
       
    59 		 				gpsIFDoffset += (iIfds)[j]->Size() + KSizeOfEntryCount;
       
    60 	 					gpsIFDoffset += KIfdOffsetByteCount; // for size of pointer to next Ifd.
       
    61 	 					}
       
    62 	 				}
       
    63 	 			//write the offset to IFD0 8825 GPS tag
       
    64 				result = SetIntegerParam(KTag8825[ETagValue], EZeroth, gpsIFDoffset);
       
    65 				if (result != KErrNone)
       
    66 					{
       
    67 					User::Leave(result);
       
    68 					}
       
    69 				}
       
    70 			}
       
    71 		}
       
    72 		
       
    73 	// Need to obtain the size of each IFD object in order to determine initial
       
    74 	// alloc size of the total Exif data block.
       
    75 	TUint allocSize = 0;
       
    76 	
       
    77 	// Account for the Exif file header data.
       
    78 	allocSize = allocSize + KExifFileHeaderLength;
       
    79 	
       
    80 	
       
    81 	// Account for the thumbnail
       
    82 	if(iJpegThumbnailData)
       
    83 		{
       
    84 		allocSize += iJpegThumbnailData->Length();
       
    85 		}
       
    86 	
       
    87 	// Account for each Ifd.
       
    88 	TInt i;
       
    89 	for (i = 0; i < iIfds.Count(); i++)
       
    90 		{
       
    91 		TUint size = iIfds[i]->Size();
       
    92 		if (size > 0)
       
    93 			{
       
    94 			allocSize += KSizeOfEntryCount; 	// Need to allocate room for the Ifd entry count also.
       
    95 			allocSize += size;
       
    96 			allocSize += KIfdOffsetByteCount;	// Account for the offset to the next Ifd.
       
    97 			}
       
    98 		}
       
    99 
       
   100 	
       
   101 	// Maximum legal size of APP1 header is 64K.
       
   102 	if (allocSize > KMaxApp1Size)
       
   103 		{
       
   104 		User::Leave(KErrTooBig);
       
   105 		}
       
   106 		
       
   107 	// Allocate required buffer.
       
   108 	HBufC8* buffer = HBufC8::NewL(allocSize);
       
   109 	CleanupStack::PushL(buffer);
       
   110 	iData = const_cast<TUint8*>(buffer->Des().Ptr());
       
   111 	TUint8* tmpPtr = iData;
       
   112 	
       
   113 	WriteExifFileHeaderBaseL(allocSize - KBlockEndMarkerByteCount, tmpPtr);
       
   114 		
       
   115 	// Write each Ifd in turn.
       
   116 	TUint currentOffset = KIfdOffset;
       
   117 	for (TInt i = 0; i < KNumIfds; i++)
       
   118 		{
       
   119 		CIfdGeneral* ifd = GetIfd(KIfdOrder[i]);
       
   120 		if (ifd != NULL) 
       
   121 			{
       
   122 			TUint16 entryCount = ifd->EntryCount();
       
   123 			if (entryCount) 
       
   124 				{
       
   125 				TUint8* tempIfdBlock = ifd->CreateIfdBlockL(currentOffset);
       
   126 				
       
   127 				// Write Ifd entry count.		
       
   128 				tmpPtr = Mem::Copy(tmpPtr, &entryCount, KSizeOfEntryCount);
       
   129 				
       
   130 				// Write the Ifd to the Exif data block.
       
   131 				TInt length = ifd->Size();
       
   132 				length += KIfdOffsetByteCount; // for size of pointer to next Ifd.
       
   133 				tmpPtr = Mem::Copy(tmpPtr, tempIfdBlock, length);
       
   134 						
       
   135 				// Free data block created for this Ifd.
       
   136 				User::Free(tempIfdBlock);
       
   137 
       
   138 				currentOffset += length + KSizeOfEntryCount;
       
   139 				}		
       
   140 			}
       
   141 		} // end for
       
   142 	
       
   143 	SetFirstIfdOffsetBase();
       
   144 	
       
   145 	// finally, embed the thumbnail
       
   146 	if (iJpegThumbnailData)
       
   147 		{
       
   148 		// Now know the size of the other Ifd's, can set the offset to the 1st Ifd.
       
   149 		
       
   150 		TUint thumbnailLength = iJpegThumbnailData->Length();
       
   151 		//return value the copy operation is not used, so discarded
       
   152 		Mem::Copy(tmpPtr, iJpegThumbnailData->Ptr(), thumbnailLength);
       
   153 	
       
   154 		// No need to account for EOI as it is written elsewhere.
       
   155 
       
   156 		// If the source does not have JPEGInterchangeFormatLength (tag 0x0202) then
       
   157 		// ThumbnailLengthOffset will return an error. 0x0202 is mandatory with thumbs
       
   158 		// so this should not happen except with corrupt sources.
       
   159 		TUint thumbnailLengthOffset = 0;
       
   160 		if (GetThumbnailLengthOffsetBase(thumbnailLengthOffset) == KErrNone)
       
   161 			{
       
   162 			Mem::Copy(iData + thumbnailLengthOffset, &thumbnailLength, sizeof(TUint));
       
   163 			}
       
   164 		}
       
   165 
       
   166 	buffer->Des().SetLength(allocSize);
       
   167 	CleanupStack::Pop();
       
   168 	return buffer;
       
   169 	}
       
   170 	
       
   171 CExifReaderWriter::CExifReaderWriter() 
       
   172 	{
       
   173 	}
       
   174 
       
   175 // Set 8-bit data.
       
   176 TInt CExifReaderWriter::SetParam8(TUint aTag, TUint aIfd,  HBufC8* aParam)
       
   177 	{
       
   178 	TInt err = DoSetParam8(aTag, aIfd, aParam);
       
   179 	if(err == KErrNone)
       
   180 		{
       
   181 		iExifDataModified = ETrue;
       
   182 		}
       
   183 	return err;
       
   184 	}
       
   185 
       
   186 // Set 16-bit data.  Only used for Unicode 'User Comment' tag.
       
   187 TInt CExifReaderWriter::SetParam16(TUint aTag, TUint aIfd,  HBufC16* aParam)
       
   188 	{
       
   189 	TInt err = DoSetParam16(aTag, aIfd, aParam);
       
   190 	if(err == KErrNone)
       
   191 		{
       
   192 		iExifDataModified = ETrue;
       
   193 		}
       
   194 	return err;
       
   195 	}
       
   196 
       
   197 TInt CExifReaderWriter::SetIntegerParam(TUint aTag, TUint aIfd,  TInt aParam)
       
   198 	{
       
   199 	TInt err = DoSetIntegerParam(aTag, aIfd, aParam);
       
   200 	if(err == KErrNone)
       
   201 		{
       
   202 		iExifDataModified = ETrue;
       
   203 		}
       
   204 	return err;
       
   205 	}
       
   206 
       
   207 
       
   208 TInt CExifReaderWriter::SetRationalParam(TUint aTag, TUint aIfd, TInt aNumerator, TInt aDenominator)
       
   209 	{
       
   210 	TInt err = DoSetRationalParam(aTag, aIfd, aNumerator, aDenominator);
       
   211 	if( err == KErrNone)
       
   212 		{
       
   213 		iExifDataModified = ETrue;
       
   214 		}
       
   215 	return err;
       
   216 	}
       
   217 	
       
   218 TInt CExifReaderWriter::SetShortParam(TUint aTag, TUint aIfd, TUint16 aParam)
       
   219 	{
       
   220 	TInt err = DoSetShortParam(aTag, aIfd, aParam);
       
   221 	if( err == KErrNone )
       
   222 		{
       
   223 		iExifDataModified = ETrue;
       
   224 		}
       
   225 	return err;
       
   226 	}
       
   227 	
       
   228 TInt CExifReaderWriter::SetIntegerArrayParam(TUint aTag, TUint aIfd, CArrayFix<TInt>& aParam)
       
   229 	{
       
   230 	TInt err = DoSetIntegerArrayParam(aTag, aIfd, aParam);
       
   231 	if(err == KErrNone)
       
   232 		{
       
   233 		iExifDataModified = ETrue;
       
   234 		}
       
   235 	return err;
       
   236 	}
       
   237 
       
   238 TInt CExifReaderWriter::SetRationalArrayParam(TUint aTag, TUint aIfd, CArrayFix<TRational>& aParam)
       
   239 	{
       
   240 	TInt err = DoSetRationalArrayParam(aTag, aIfd, aParam);
       
   241 	if(err == KErrNone)
       
   242 		{
       
   243 		iExifDataModified = ETrue;
       
   244 		}
       
   245 	return err;
       
   246 	}
       
   247 	
       
   248 TInt CExifReaderWriter::SetShortArrayParam(TUint aTag, TUint aIfd, CArrayFix<TUint16>& aParam)
       
   249 	{
       
   250 	TInt err = DoSetShortArrayParam(aTag, aIfd, aParam);
       
   251 	if(err == KErrNone)
       
   252 		{
       
   253 		iExifDataModified = ETrue;
       
   254 		}
       
   255 	return err;
       
   256 	}
       
   257 
       
   258 	
       
   259 // Set 8-bit data.
       
   260 TInt CExifReaderWriter::DoSetParam8(TUint aTag, TUint aIfd,  HBufC8* aParam)
       
   261 	{
       
   262 	if(aParam == NULL)
       
   263 		{
       
   264 		return KErrArgument;
       
   265 		}
       
   266 	
       
   267 	TInt internalIfdNumber = 0;
       
   268 	CIfdGeneral* internalIfd = NULL;
       
   269 	TInt err = KErrNone;
       
   270 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   271 	if(err!=KErrNone)
       
   272 		{
       
   273 		return err;
       
   274 		}
       
   275 		
       
   276 	if(internalIfd->EntryExists(aTag))
       
   277 		{
       
   278 		// Set the existing entry.
       
   279 		return internalIfd->SetParam8(aTag, aParam);	
       
   280 		}
       
   281 	else
       
   282 		{
       
   283 		// Get the required parameters.
       
   284 		TUint format = 0;
       
   285 		err = internalIfd->GetFormat(aTag, format);		
       
   286 		if (err == KErrNone) 
       
   287 			{
       
   288 			TRAP(err, internalIfd->AddParam8L(aTag, format, aParam->Length(), aParam));
       
   289 			
       
   290 			if (internalIfdNumber == EGpsSub)
       
   291 				{
       
   292 				ProcessGpsIfdAddParamResult(internalIfd, err);
       
   293 				}				
       
   294 			}
       
   295 			
       
   296 		return err;
       
   297 		}		
       
   298 	}
       
   299 
       
   300 // Set 16-bit data.  Only used for Unicode 'User Comment' tag.
       
   301 TInt CExifReaderWriter::DoSetParam16(TUint aTag, TUint aIfd,  HBufC16* aParam)
       
   302 	{
       
   303 	if(aParam == NULL)
       
   304 		{
       
   305 		return KErrArgument;
       
   306 		}	
       
   307 	
       
   308 	// The only tags which may contain 16-bit data are 0x9286 (UserComment),
       
   309 	// 0x001B (GpsProcessingMethod) or 0x001C (GpsAreaInformation).
       
   310 	if(aTag != KTag9286[ETagValue] && aTag != KTagGPS001B[ETagValue] && aTag != KTagGPS001C[ETagValue])
       
   311 		{
       
   312 		return KErrArgument;
       
   313 		}
       
   314 		
       
   315 	TInt internalIfdNumber = 0;
       
   316 	CIfdGeneral* internalIfd = NULL;
       
   317 	TInt err = KErrNone;
       
   318 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   319 	if(err!=KErrNone)
       
   320 		{
       
   321 		return err;
       
   322 		}
       
   323 		
       
   324 	if(internalIfd->EntryExists(aTag))
       
   325 		{
       
   326 		// Set the existing entry.
       
   327 		return internalIfd->SetParam16(aTag, aParam);	
       
   328 		}
       
   329 	else
       
   330 		{
       
   331 		// Get the required parameters.
       
   332 		TUint format = 0;
       
   333 		err = internalIfd->GetFormat(aTag, format);
       
   334 		if (err == KErrNone)
       
   335 			{
       
   336 			TRAP(err, internalIfd->AddParam16L(aTag, format, aParam->Length(), aParam));
       
   337 
       
   338 			if (internalIfdNumber == EGpsSub)
       
   339 				{
       
   340 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   341 				}
       
   342 			}
       
   343 
       
   344 		return err;
       
   345 		}
       
   346 	}
       
   347 	
       
   348 // Sets single integer data (including short, long and integer).
       
   349 TInt CExifReaderWriter::DoSetIntegerParam(TUint aTag, TUint aIfd,  TInt aParam)
       
   350 	{
       
   351 	TInt internalIfdNumber = 0;
       
   352 	CIfdGeneral* internalIfd = NULL;
       
   353 	TInt err = KErrNone;
       
   354 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   355 	if(err!=KErrNone)
       
   356 		{
       
   357 		return err;
       
   358 		}
       
   359 		
       
   360 	if(internalIfd->EntryExists(aTag))
       
   361 		{
       
   362 		// Set the existing entry.
       
   363 		return internalIfd->SetIntegerParam(aTag, aParam);	
       
   364 		}
       
   365 	else
       
   366 		{
       
   367 		// Get the required parameters.
       
   368 		TUint format = 0;
       
   369 		err = internalIfd->GetFormat(aTag, format);
       
   370 		if (err == KErrNone)
       
   371 			{
       
   372 			// Sets a single integer value.
       
   373 			TRAP(err, internalIfd->AddIntegerParamL(aTag, format, 1, aParam));
       
   374 			
       
   375 			if (internalIfdNumber == EGpsSub)
       
   376 				{
       
   377 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   378 				}
       
   379 			}
       
   380 			
       
   381 		return err;
       
   382 		}
       
   383 	}
       
   384 
       
   385 // Sets single rational data (i.e. one numerator and one denominator).
       
   386 TInt CExifReaderWriter::DoSetRationalParam(TUint aTag, TUint aIfd, TInt aNumerator, TInt aDenominator)
       
   387 	{
       
   388 	TInt internalIfdNumber = 0;
       
   389 	CIfdGeneral* internalIfd = NULL;
       
   390 	TInt err = KErrNone;
       
   391 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   392 	if(err!=KErrNone)
       
   393 		{
       
   394 		return err;
       
   395 		}
       
   396 
       
   397 	if(internalIfd->EntryExists(aTag))
       
   398 		{
       
   399 		// Set the existing entry.
       
   400 		return internalIfd->SetRationalParam(aTag, aNumerator, aDenominator);	
       
   401 		}
       
   402 	else
       
   403 		{
       
   404 		// Get the required parameters.
       
   405 		TUint format = 0;
       
   406 		err = internalIfd->GetFormat(aTag, format);
       
   407 		if (err == KErrNone)
       
   408 			{
       
   409 			TRAP(err, internalIfd->AddRationalParamL(aTag, format, 1, aNumerator, aDenominator));
       
   410 
       
   411 			if (internalIfdNumber == EGpsSub)
       
   412 				{
       
   413 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   414 				}
       
   415 			}
       
   416 		return err;
       
   417 		}
       
   418 
       
   419 	}
       
   420 
       
   421 TInt CExifReaderWriter::DoSetShortParam(TUint aTag, TUint aIfd, TUint16 aParam)
       
   422 	{
       
   423 	TInt internalIfdNumber = 0;
       
   424 	CIfdGeneral* internalIfd = NULL;
       
   425 	TInt err = KErrNone;
       
   426 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   427 	if(err!=KErrNone)
       
   428 		{
       
   429 		return err;
       
   430 		}
       
   431 		
       
   432 	if(internalIfd->EntryExists(aTag))
       
   433 		{
       
   434 		// Set the existing entry.
       
   435 		return internalIfd->SetShortParam(aTag, aParam);	
       
   436 		}
       
   437 	else
       
   438 		{
       
   439 		// Get the required parameters.
       
   440 		TUint format = 0;
       
   441 		err = internalIfd->GetFormat(aTag, format);
       
   442 		if (err == KErrNone)
       
   443 			{
       
   444 			// Sets a single integer value.
       
   445 			TRAP(err, internalIfd->AddShortParamL(aTag, format, 1, aParam));
       
   446 			
       
   447 			if (internalIfdNumber == EGpsSub)
       
   448 				{
       
   449 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   450 				}
       
   451 			}
       
   452 		return err;
       
   453 		}
       
   454 	}
       
   455 
       
   456 TInt CExifReaderWriter::DoSetIntegerArrayParam(TUint aTag, TUint aIfd, CArrayFix<TInt>& aParam)
       
   457 	{	
       
   458 	TInt internalIfdNumber = 0;
       
   459 	CIfdGeneral* internalIfd = NULL;
       
   460 	TInt err = KErrNone;
       
   461 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   462 	if(err!=KErrNone)
       
   463 		{
       
   464 		return err;
       
   465 		}
       
   466 	
       
   467 	if(internalIfd->EntryExists(aTag))
       
   468 		{
       
   469 		// Set the existing entry.
       
   470 		TRAP(err, internalIfd->SetIntegerArrayParamL(aTag, aParam));	
       
   471 		return err;
       
   472 		}
       
   473 	else
       
   474 		{
       
   475 		// Get the required parameters.
       
   476 		TUint format = 0;
       
   477 		err = internalIfd->GetFormat(aTag, format);
       
   478 		if (err == KErrNone)
       
   479 			{
       
   480 			// Sets a single integer value.
       
   481 			TRAP(err, internalIfd->AddIntegerArrayParamL(aTag, format, aParam));
       
   482 			if (internalIfdNumber == EGpsSub)
       
   483 				{
       
   484 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   485 				}
       
   486 			}
       
   487 		return err;
       
   488 		}
       
   489 	}
       
   490 	
       
   491 TInt CExifReaderWriter::DoSetRationalArrayParam(TUint aTag, TUint aIfd, CArrayFix<TRational>& aParam)
       
   492 	{
       
   493 	TInt internalIfdNumber = 0;
       
   494 	CIfdGeneral* internalIfd = NULL;
       
   495 	TInt err = KErrNone;
       
   496 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   497 	if(err!=KErrNone)
       
   498 		{
       
   499 		return err;
       
   500 		}
       
   501 	
       
   502 	if(internalIfd->EntryExists(aTag))
       
   503 		{
       
   504 		// Set the existing entry.
       
   505 		TRAP(err, internalIfd->SetRationalArrayParamL(aTag, aParam));	
       
   506 		return err;
       
   507 		}
       
   508 	else
       
   509 		{
       
   510 		// Get the required parameters.
       
   511 		TUint format = 0;
       
   512 		err = internalIfd->GetFormat(aTag, format);
       
   513 		if (err == KErrNone)
       
   514 			{
       
   515 			// Sets a single integer value.
       
   516 			TRAP(err, internalIfd->AddRationalArrayParamL(aTag, format, aParam));
       
   517 			
       
   518 			if (internalIfdNumber == EGpsSub)
       
   519 				{
       
   520 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   521 				}
       
   522 			}
       
   523 			
       
   524 		return err;
       
   525 		}
       
   526 	}
       
   527 
       
   528 TInt CExifReaderWriter::DoSetShortArrayParam(TUint aTag, TUint aIfd, CArrayFix<TUint16>& aParam)
       
   529 	{
       
   530 	TInt internalIfdNumber = 0;
       
   531 	CIfdGeneral* internalIfd = NULL;
       
   532 	TInt err = KErrNone;
       
   533 	TRAP(err, FindInternalIfdDataL(aTag, aIfd, internalIfdNumber, internalIfd));
       
   534 	if(err!=KErrNone)
       
   535 		{
       
   536 		return err;
       
   537 		}
       
   538 			
       
   539 	if(internalIfd->EntryExists(aTag))
       
   540 		{
       
   541 		// Set the existing entry.
       
   542 		TRAP(err, internalIfd->SetShortArrayParamL(aTag, aParam));	
       
   543 		return err;
       
   544 		}
       
   545 	else
       
   546 		{
       
   547 		// Get the required parameters.
       
   548 		TUint format = 0;
       
   549 		err = internalIfd->GetFormat(aTag, format);
       
   550 		if (err == KErrNone)
       
   551 			{
       
   552 			// Sets a single integer value.
       
   553 			TRAP(err, internalIfd->AddShortArrayParamL(aTag, format, aParam));
       
   554 			if (internalIfdNumber == EGpsSub)
       
   555 				{
       
   556 				err = ProcessGpsIfdAddParamResult(internalIfd, err);
       
   557 				}
       
   558 			}
       
   559 		return err;
       
   560 		}
       
   561 	}
       
   562 
       
   563 
       
   564 CExifReaderWriter::~CExifReaderWriter()
       
   565 	{
       
   566 	iIfds.ResetAndDestroy();
       
   567 	delete iJpegThumbnailData;
       
   568 	}
       
   569 
       
   570 TInt CExifReaderWriter::GetIntegerParam(TUint aTag, TUint aIfd, TInt& aParam) const
       
   571 	{
       
   572 	TInt err = KErrNotFound;
       
   573 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   574 	
       
   575 	if (ifd != NULL)
       
   576 		{
       
   577 		err = ifd->GetIntegerParam(aTag, aParam);	
       
   578 		}
       
   579 	return err;
       
   580 	}
       
   581 
       
   582 TInt CExifReaderWriter::GetShortParam(TUint aTag, TUint aIfd, TUint16& aParam) const
       
   583 	{
       
   584 	TInt err = KErrNotFound;
       
   585 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   586 	
       
   587 	if (ifd != NULL)
       
   588 		{
       
   589 		err = ifd->GetShortParam(aTag, aParam);	
       
   590 		}
       
   591 	return err;
       
   592 	}
       
   593 
       
   594 TInt CExifReaderWriter::GetRationalParam(TUint aTag, TUint aIfd, TInt& aNumer, TInt& aDenom) const
       
   595 	{
       
   596 	TInt err = KErrNotFound;
       
   597 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   598 	
       
   599 	if (ifd != NULL)
       
   600 		{
       
   601 		err = ifd->GetRationalParam(aTag, aNumer, aDenom);	
       
   602 		}
       
   603 	return err;
       
   604 	}
       
   605 
       
   606 TInt CExifReaderWriter::GetParam8(TUint aTag, TUint aIfd, HBufC8*& aParam) const
       
   607 	{
       
   608 	TInt err = KErrNotFound;
       
   609 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   610 	
       
   611 	if (ifd != NULL)
       
   612 		{
       
   613 		err = ifd->GetParam8(aTag, aParam);	
       
   614 		}
       
   615 	return err;
       
   616 	}
       
   617 
       
   618 TInt CExifReaderWriter::GetParam16(TUint aTag, TUint aIfd, HBufC16*& aParam) const
       
   619 	{
       
   620 	// The only tags which may contain 16-bit data are 0x9286 (UserComment),
       
   621 	// 0x001B (GpsProcessingMethod) or 0x001C (GpsAreaInformation).
       
   622 	if(aTag != KTag9286[ETagValue] && aTag != KTagGPS001B[ETagValue] && aTag != KTagGPS001C[ETagValue])
       
   623 		{
       
   624 		return KErrArgument;
       
   625 		}
       
   626 		
       
   627 	TInt err = KErrNotFound;
       
   628 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   629 	
       
   630 	if (ifd != NULL)
       
   631 		{
       
   632 		err = ifd->GetParam16(aTag, aParam);	
       
   633 		}
       
   634 	return err;
       
   635 	}
       
   636 
       
   637 TInt CExifReaderWriter::GetIntegerArrayParam(TUint aTag, TUint aIfd, CArrayFix<TInt>& aParam) const
       
   638 	{
       
   639 	TInt err = KErrNotFound;
       
   640 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   641 	
       
   642 	if (ifd != NULL)
       
   643 		{
       
   644 		TRAP(err, ifd->GetIntegerArrayParamL(aTag, aParam));	
       
   645 		}
       
   646 	return err;
       
   647 	}
       
   648 
       
   649 TInt CExifReaderWriter::GetShortArrayParam(TUint aTag, TUint aIfd, CArrayFix<TUint16>& aParam) const
       
   650 	{
       
   651 	TInt err = KErrNotFound;
       
   652 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   653 	
       
   654 	if (ifd != NULL)
       
   655 		{
       
   656 		TRAP(err, ifd->GetShortArrayParamL(aTag, aParam));	
       
   657 		}
       
   658 	return err;
       
   659 	}
       
   660 
       
   661 TInt CExifReaderWriter::GetRationalArrayParam(TUint aTag, TUint aIfd, CArrayFix<TRational>& aParam) const
       
   662 	{
       
   663 	TInt err = KErrNotFound;
       
   664 	CIfdGeneral* ifd = FindIfd(aTag, aIfd);
       
   665 	
       
   666 	if (ifd != NULL)
       
   667 		{
       
   668 		TRAP(err, ifd->GetRationalArrayParamL(aTag, aParam));	
       
   669 		}
       
   670 	return err;
       
   671 	}
       
   672 
       
   673 void CExifReaderWriter::InitializeIfdsL(TBool aAlwaysCreateIfd1, TBool aCreateGpsIfd)
       
   674 	{
       
   675 	// All of the IFD's should be present, because each has at least one Mandatory Ifd entry.	
       
   676 	CIfd0* ifd0 = CIfd0::NewLC();
       
   677 	iIfds.AppendL(ifd0);
       
   678 	CleanupStack::Pop(ifd0);
       
   679 	
       
   680 	CExifIfd* exifIfd = CExifIfd::NewLC();
       
   681 	iIfds.AppendL(exifIfd);
       
   682 	CleanupStack::Pop(exifIfd);
       
   683 	
       
   684 	CInteropIfd* interopIfd = CInteropIfd::NewLC();
       
   685 	iIfds.AppendL(interopIfd);
       
   686 	CleanupStack::Pop(interopIfd);
       
   687 	 
       
   688 	if(iEncodeThumbnail || aAlwaysCreateIfd1)
       
   689 		{
       
   690 		CIfd1* ifd1 = CIfd1::NewLC();
       
   691 		iIfds.AppendL(ifd1);
       
   692 		CleanupStack::Pop(ifd1);
       
   693 		}	
       
   694 		
       
   695 	if (aCreateGpsIfd) 
       
   696 		{
       
   697 		CGpsIfd* gpsIfd = CGpsIfd::NewLC();
       
   698 		iIfds.AppendL(gpsIfd);
       
   699 		CleanupStack::Pop(gpsIfd);
       
   700 		}
       
   701 	}
       
   702 
       
   703 
       
   704 void CExifReaderWriter::InitializeIfdsL(TUint8* aData, TUint aApp1Size)
       
   705 	{
       
   706 	iData = aData; 
       
   707 	
       
   708 	// Note that iApp1Size includes 2bytes for the APP1 length field and 6bytes for the
       
   709 	// EXIF header so these both need to be subtracted to determine the end of the EXIF
       
   710 	// data.
       
   711 	iExifDataLength = aApp1Size - KOffsetFromExifHeaderToByteAlignment - KApp1SizeLength;
       
   712 	if(iData)
       
   713 		{
       
   714 		ReadHeaderL();
       
   715 		SetUpIfdsL();
       
   716 		}
       
   717 	}
       
   718 	
       
   719 // Returns the internal Ifd (i.e. EIfd values) from the given external Ifd (i.e. 0th or 1st)
       
   720 // that contains the provided tag.  This is because the Exif Sub Ifd and the Interoperability
       
   721 // Ifd are both considered to be part of the 0th Ifd.
       
   722 // Returns KErrArgument if not valid.
       
   723 TInt CExifReaderWriter::InternalIfd(const TUint aTag, const TInt aExternalIfd) const
       
   724 	{
       
   725 	if(aExternalIfd == 0)
       
   726 		{
       
   727 		// Can be either 0th, Exif Sub or Interoperability Ifd.
       
   728 		if(TExifTagHelper::IsCorrectParentIfd(aTag, EZeroth))
       
   729 			{
       
   730 			return EZeroth;			
       
   731 			}
       
   732 		if(TExifTagHelper::IsCorrectParentIfd(aTag, EExifSub))
       
   733 			{
       
   734 			return EExifSub;
       
   735 			}
       
   736 		if(TExifTagHelper::IsCorrectParentIfd(aTag, EInterop))
       
   737 			{
       
   738 			return EInterop;
       
   739 			}
       
   740 		if(TExifTagHelper::IsCorrectParentIfd(aTag, EGpsSub))
       
   741 			{
       
   742 			return EGpsSub;
       
   743 			}		
       
   744 		}
       
   745 	else if(aExternalIfd == 1)
       
   746 		{
       
   747 		if(TExifTagHelper::IsCorrectParentIfd(aTag, EFirst))
       
   748 			{
       
   749 			return EFirst;
       
   750 			}
       
   751 		}
       
   752 
       
   753 	//Check if upper 16 bits are used to specifiy a sub-IFD.
       
   754  	//Only IFD 0 sub IFDs can currently be checked for.
       
   755  	else if (TExifIfdHelper::IfdContainsIfd0SubIfd(aExternalIfd, EGpsSub))
       
   756  		{
       
   757  		return EGpsSub;
       
   758  		}
       
   759 	return KErrNotFound;
       
   760 	}
       
   761 	
       
   762 TInt CExifReaderWriter::CheckTagL(const TUint aTag, const TUint aIfd) const
       
   763 	{
       
   764 	TInt realIfd = InternalIfd(aTag, aIfd);
       
   765 	
       
   766 	if (!TExifIfdHelper::IsValidInternalIfd(realIfd))
       
   767 		{
       
   768 		User::Leave(KErrNotFound);
       
   769 		}
       
   770 	return realIfd;
       
   771 	}
       
   772 
       
   773 
       
   774 // Updates aIfdIndex with the index of the given IFD if found.
       
   775 TBool CExifReaderWriter::FindIfdIndex(TInt aRealIfd, TInt& aIfdIndex) const
       
   776 	{
       
   777 	for(TInt i = 0; i < iIfds.Count(); ++i)
       
   778 		{
       
   779 		if(iIfds[i]->Ifd() == aRealIfd)
       
   780 			{
       
   781 			aIfdIndex = i;
       
   782 			return ETrue;
       
   783 			}
       
   784 		}
       
   785 	return EFalse;
       
   786 	}
       
   787 
       
   788 // Returns the CIfdGeneral* for this tag/ifd pair if it exists, else NULL
       
   789 CIfdGeneral* CExifReaderWriter::FindIfd(const TUint aTag, const TUint aExternalIfd) const
       
   790 	{
       
   791 	TInt realIfd=0;
       
   792 	TInt err = KErrNone;
       
   793 	TRAP(err, realIfd=CheckTagL(aTag, aExternalIfd));
       
   794 	if(err==KErrNone)
       
   795 		{		
       
   796 		TInt ifdIndex=0;
       
   797 		if(FindIfdIndex(realIfd, ifdIndex))
       
   798 			{
       
   799 			return iIfds[ifdIndex];
       
   800 			}
       
   801 		}
       
   802 	return NULL;
       
   803 	}
       
   804 	
       
   805 // This is the preamble for most Set functions.  Its purpose is to fetch the Internal
       
   806 // Ifd information for the given aTag/aExternalIfdNumber pair.  The Internal Ifd 
       
   807 // information fetched consists of a pointer to the CIfd object and the Internal Ifd 
       
   808 // Number.
       
   809 //
       
   810 // Note: If aExternalIfdNumber corresponds to the GPS Ifd, then it is possible that the 
       
   811 // Ifd object for it does not exist yet.  This is because the GPS Ifd has no mandatory
       
   812 // tags so it need not be present in metadata.  In this case, this method will create
       
   813 // the Ifd object for GPS & add it to the iIfds array before returning its information
       
   814 // to the caller.
       
   815 //
       
   816 // If it can not return an internal representation for the given aTag/aExternalIfdNumber 
       
   817 // pair, then this method leaves with KErrNotSupported.
       
   818 void CExifReaderWriter::FindInternalIfdDataL(const TUint aTag, const TUint aExternalIfdNumber, TInt& aInternalIfdNumber, CIfdGeneral*& aInternalIfd)
       
   819 	{
       
   820 	aInternalIfdNumber = CheckTagL(aTag, aExternalIfdNumber);
       
   821 
       
   822 	//All the CExifReaderWriter::Set() methods used to use the realIfd as the array index.
       
   823 	//However, since the GPS IFD is optional this is invalid & now we check to get 
       
   824 	//the correct array index.	
       
   825 	TInt ifdIndex = 0;
       
   826 	if (!FindIfdIndex(aInternalIfdNumber, ifdIndex))
       
   827 		{
       
   828 		//ifd does not yet exist internally
       
   829 		if (aInternalIfdNumber == EGpsSub)
       
   830 			{
       
   831 			//Currently this can only be GPS IFD since the other IFDs have madatory entries.
       
   832 			//We need to create an empty GPS ifd. First create GPS IFD pointer in 0 IFD
       
   833 			//We don't care about offset value at this point - this gets written in TExifAccessor::CreateExifHeaderL
       
   834 			CGpsIfd* gpsIfd = CGpsIfd::NewLC(0, NULL, ETrue);
       
   835 			iIfds.AppendL(gpsIfd);
       
   836 			CleanupStack::Pop(gpsIfd);
       
   837 			aInternalIfd = gpsIfd;
       
   838 			}
       
   839 		else
       
   840 			{
       
   841 			//ifd is real but there are no entries
       
   842 			User::Leave(KErrNotFound);
       
   843 			}
       
   844 		}
       
   845 	else
       
   846 		{
       
   847 		aInternalIfd = iIfds[ifdIndex];		
       
   848 		}	
       
   849 	}
       
   850 
       
   851 // Helper Function
       
   852 /*static*/
       
   853 TUint CExifReaderWriter::ReadUint32(const TBool aIntelByteAlign, const TUint8* aPtr)
       
   854 	{
       
   855 	if(aIntelByteAlign)
       
   856 		{
       
   857 		return PtrReadUtil::ReadUint32(aPtr);
       
   858 		}
       
   859 	else // Motorola
       
   860 		{
       
   861 		return PtrReadUtil::ReadBigEndianUint32(aPtr);
       
   862 		}
       
   863 	}
       
   864 
       
   865 // Helper Function	
       
   866 /*static*/
       
   867 TUint16 CExifReaderWriter::ReadUint16(const TBool aIntelByteAlign, const TUint8* aPtr)
       
   868 	{
       
   869 	if(aIntelByteAlign)
       
   870 		{
       
   871 		return PtrReadUtil::ReadUint16(aPtr);
       
   872 		}
       
   873 	else // Motorola
       
   874 		{
       
   875 		return PtrReadUtil::ReadBigEndianUint16(aPtr);
       
   876 		}
       
   877 	}
       
   878 
       
   879 
       
   880 void CExifReaderWriter::ReadHeaderL()
       
   881 	{
       
   882 	// Check integrity of header.
       
   883 	TPtrC8 exifHeaderPtr(iData, KExifHeaderLength);
       
   884 	if(KExifHeader().Compare(exifHeaderPtr))
       
   885 		{
       
   886 		User::Leave(KErrCorrupt);
       
   887 		}
       
   888 	
       
   889 	TUint16 byteAlignment = 0;	
       
   890 	Mem::Copy(&byteAlignment, iData+KOffsetFromExifHeaderToByteAlignment, sizeof(byteAlignment));
       
   891 	if(byteAlignment == KIntelByteAlignment)
       
   892 		{
       
   893 		iIntel = ETrue;		
       
   894 		}
       
   895 	else if(byteAlignment == KMotorolaByteAlignment)
       
   896 		{
       
   897 		iIntel = EFalse;
       
   898 		}
       
   899 	else
       
   900 		{
       
   901 		User::Leave(KErrCorrupt);
       
   902 		}
       
   903 			
       
   904 	iBase = iData+KOffsetFromExifHeaderToByteAlignment;
       
   905 	
       
   906 	
       
   907 	TUint16 readFortyTwo = ReadUint16(iIntel, iData + KOffsetFromExifHeaderToByteAlignment + sizeof(byteAlignment));
       
   908 	if (readFortyTwo != KFortyTwo)
       
   909 		{
       
   910 		readFortyTwo = ReadUint16(!iIntel, iData + KOffsetFromExifHeaderToByteAlignment + sizeof(byteAlignment));
       
   911 		if (readFortyTwo != KFortyTwo)
       
   912 			{
       
   913 			User::Leave(KErrArgument);
       
   914 			}
       
   915 		}
       
   916 		
       
   917 	iOffsetToZerothIfd = ReadUint32(iIntel, iData + KOffsetToZerothOffset);
       
   918 	if ( CheckExifOffset(iOffsetToZerothIfd) != KErrNone )
       
   919 		{
       
   920 		iOffsetToZerothIfd = ReadUint32(!iIntel, iData + KOffsetToZerothOffset);
       
   921 		if ( CheckExifOffset(iOffsetToZerothIfd) != KErrNone )
       
   922 			{
       
   923 			// If we've got this far then it probably really is an exif file
       
   924 			// but the offset is corrupt
       
   925 			iOffsetToZerothIfd = KIfdOffset; //so we'll try a default value
       
   926 			}
       
   927 		}
       
   928 	}
       
   929 
       
   930 /**
       
   931 	Attempts to create a sub-IFD whose offset is given by an entry in another IFD and append
       
   932 	it to iIfds.
       
   933 	However, if the given tag is not found, the offset is wrong or the IFD data is corrupt
       
   934 	then nothing will be appended to iIfds and NULL shall be returned.
       
   935 	
       
   936 	@param	aIfd	The IFD containing the entry with the offset to the sub-IFD.
       
   937 	@param	aTag	The tag of the entry containing the offset.
       
   938 
       
   939 	@return	Pointer to the sub-IFD that was created and appended to iIFds
       
   940 			or NULL if it could not be created. (This does not transfer ownership
       
   941 			of the IFD since it is owned by iIfds!)
       
   942 			
       
   943 	@leave	KErrNoMemory	If the sub-IFD could not be created due to OOM. (This
       
   944 							is the only type of leave this function can make!)
       
   945 	
       
   946 */
       
   947 CIfdGeneral* CExifReaderWriter::CreateAndAppendSubIfdL(CIfdGeneral& aIfd, TUint aTag)
       
   948 	{
       
   949 	TInt offsetValue = 0;
       
   950 	CIfdGeneral* subIfd = NULL;
       
   951 	
       
   952 	TInt err = aIfd.GetIntegerParam( aTag, offsetValue );
       
   953 	if(err == KErrNone)
       
   954 		{		
       
   955 		// offset tag found	
       
   956 		if((err = CheckExifOffset( offsetValue )) != KErrNone)
       
   957 			{
       
   958 			// offset wrong
       
   959 			aIfd.RemoveEntryL( aTag );
       
   960 			}
       
   961 		else
       
   962 			{
       
   963 			// offset OK - try to create IFD
       
   964 			if( aTag == KTag8769[ETagValue] )
       
   965 				{
       
   966 				// EXIF sub-IFD
       
   967 				TRAP(err, subIfd = CExifIfd::NewL(offsetValue, iBase, iIntel, iExifDataLength) );
       
   968 				}
       
   969 			else if( aTag == KTagA005[ETagValue] )
       
   970 				{
       
   971 				// Interoperability sub-IFD
       
   972 				TRAP(err, subIfd = CInteropIfd::NewL(offsetValue, iBase, iIntel, iExifDataLength) );
       
   973 				}
       
   974 			else if( aTag == KTag8825[ETagValue] )
       
   975 				{
       
   976 				// GPS sub-IFD
       
   977 				TRAP(err, subIfd = CGpsIfd::NewL(offsetValue, iBase, iIntel, iExifDataLength) );
       
   978 				}
       
   979 			else
       
   980 				{
       
   981 				return NULL;
       
   982 				}
       
   983 				
       
   984 			if( err != KErrNone )
       
   985 				{
       
   986 				// could not create IFD
       
   987 				if( err == KErrNoMemory )
       
   988 					{
       
   989 					User::Leave( err );
       
   990 					}
       
   991 				else
       
   992 					{
       
   993 					aIfd.RemoveEntryL( aTag );
       
   994 					}
       
   995 				}
       
   996 			else
       
   997 				{
       
   998 				// IFD created successfully
       
   999 				CleanupStack::PushL(subIfd);
       
  1000 				iIfds.AppendL(subIfd);
       
  1001 				CleanupStack::Pop(subIfd);
       
  1002 				}
       
  1003 			}
       
  1004 		}
       
  1005 		return subIfd;
       
  1006 	}
       
  1007 
       
  1008 /**
       
  1009 	Extracts IFDs and their entries from the EXIF data.
       
  1010 	If entries in an IFD are corrupt they will be ignored. If many corrupt
       
  1011 	entries occur in sequence the(sub-)IFD that contains them is considered
       
  1012 	corrupt and ignored. (See CIfdGeneral::AddAllIfdEntriesL() for more details)
       
  1013 	
       
  1014 	If IFD0 is corrupt this function will leave with KErrCorrupt, if any of the other
       
  1015 	(sub-)IFDs are corrupt they are ignored and the corresponding entry that points
       
  1016 	to them is removed. (e.g.: If the EXIF IFD is found to be corrupt then the EXIF IFD
       
  1017 	offset tag (0x8769) in IFD0 will be removed)
       
  1018 
       
  1019 	@see 	CIfdGeneral::AddAllIfdEntriesL() 
       
  1020 	
       
  1021 	@leave	KErrNoMemory	If there is insufficient memory to process the data
       
  1022 	@leave	KErrCorrupt		If IFD0 is too corrupted for anything to be reliably
       
  1023 							extracted from it.
       
  1024 */
       
  1025 void CExifReaderWriter::SetUpIfdsL()
       
  1026 	{
       
  1027 	// IFD0
       
  1028 	CIfd0* ifd0 = CIfd0::NewLC(iOffsetToZerothIfd, iBase, iIntel, iExifDataLength);
       
  1029 	iIfds.AppendL(ifd0);
       
  1030 	CleanupStack::Pop(ifd0);
       
  1031 	
       
  1032 	// EXIF sub-IFD
       
  1033 	CIfdGeneral* exifIfd = CreateAndAppendSubIfdL( *ifd0, KTag8769[ETagValue]);
       
  1034 	if( exifIfd )
       
  1035 		{
       
  1036 		// Interoperability sub-IFD
       
  1037 		CreateAndAppendSubIfdL( *exifIfd, KTagA005[ETagValue]);
       
  1038 		}
       
  1039 		
       
  1040 	// GPS sub-IFD
       
  1041 	CreateAndAppendSubIfdL( *ifd0, KTag8825[ETagValue]);
       
  1042 
       
  1043 	// IFD1	
       
  1044 	TRAPD(err, SetIfd1L());
       
  1045 	if( err == KErrNoMemory )
       
  1046 		{
       
  1047 		User::Leave(err);
       
  1048 		}
       
  1049 	// else ignore
       
  1050 	}
       
  1051 
       
  1052 /**
       
  1053 	Check that an offset relative to the EXIF data is valid.
       
  1054 	Note that offsets in the EXIF data are relative to iBase (the
       
  1055 	start of the EXIF data contained within the APP1 block) and not 
       
  1056 	iData (the start of the APP1 block).
       
  1057 	
       
  1058 	@param	aOffset	An offset pointing to an IFD or value within
       
  1059 					the EXIF data.
       
  1060 					
       
  1061 	@return	KErrNone	If the offset is between KIfdOffset (the 8 bytes of
       
  1062 						the TIFF header) and the end of the EXIF data (the
       
  1063 						end of the APP1 block minus the APP1 headers that
       
  1064 						precede the EXIF data)
       
  1065 			KErrCorrupt	If the offset is outside that range.
       
  1066 	
       
  1067 */
       
  1068 TInt CExifReaderWriter::CheckExifOffset(const TUint aOffset)
       
  1069 	{
       
  1070 	TInt err = KErrNone;
       
  1071 	// ensure that aOffset is within a valid section of the EXIF data
       
  1072 	if ((aOffset < KIfdOffset) || (aOffset >= iExifDataLength))
       
  1073 		{
       
  1074 		err = KErrCorrupt;
       
  1075 		}
       
  1076 	return err;
       
  1077 	}
       
  1078 	
       
  1079 // This method is to be called after at attempt was made to add a param to a GPS Ifd.
       
  1080 // It must only be called with the GPS Ifd.
       
  1081 // 
       
  1082 // Its purpose is to process the result (aAddParamResult) of a CIfd::AddParamXXX() 
       
  1083 // operation on a GPS Ifd.
       
  1084 //
       
  1085 // It will add the GPS Ifd pointer to Ifd 0 if a param was sucessfully added to a 
       
  1086 // brand new GPS Ifd. (i.e. if aErr==KErrNone && aGpsIfd->EntryCount() == 1).
       
  1087 //
       
  1088 // If an attempt to add a param to a brand new GPS Ifd failed, or if the GPS Ifd pointer
       
  1089 // could not be added to Ifd 0, then the GPS Ifd is deleted and is returned.
       
  1090 TInt CExifReaderWriter::ProcessGpsIfdAddParamResult(CIfdGeneral*& aGpsIfd, TInt aAddParamResult)
       
  1091 	{
       
  1092 	ASSERT(aGpsIfd != NULL);
       
  1093 	ASSERT(aGpsIfd->Ifd() == EGpsSub);
       
  1094 
       
  1095 	TInt result = KErrNone;
       
  1096 	if ((aAddParamResult==KErrNone) && (aGpsIfd->EntryCount() == 1))
       
  1097 		{
       
  1098 		// The very first GPS tag has just been added to this Ifd, so add GPS Ifd pointer 
       
  1099 		// to Ifd 0.  Don't care about offset value at this point - this gets written in 
       
  1100 		// TExifAccessor::CreateExifHeaderL()
       
  1101 		result = SetIntegerParam(KTag8825[ETagValue],EZeroth, 0);
       
  1102 		}
       
  1103 		
       
  1104 	if ((result != KErrNone) || (aGpsIfd->EntryCount() == 0))
       
  1105 		{
       
  1106 		// Either it was not possible to add a GPS Ifd Pointer to Ifd 0, or
       
  1107 		// The GPS Ifd has no tags.  In either case, it should be removed.
       
  1108 		TInt gpsIndex = 0;
       
  1109 		if (FindIfdIndex(EGpsSub, gpsIndex))
       
  1110 			{
       
  1111 			delete iIfds[gpsIndex];
       
  1112 			iIfds.Remove(gpsIndex);
       
  1113 			}
       
  1114 		if (result == KErrNone)
       
  1115 			{
       
  1116 			//Can only be here if aAddParamResult != KErrNone.
       
  1117 			result = aAddParamResult;
       
  1118 			}
       
  1119 		}
       
  1120 	return result;
       
  1121 	}
       
  1122 	
       
  1123 	
       
  1124 void CExifReaderWriter::RemoveThumbnailData()
       
  1125 	{	
       
  1126 	for(TInt i=0; i<iIfds.Count(); i++)
       
  1127 		{
       
  1128 		if((iIfds)[i]->Ifd()==EFirst)
       
  1129 			{
       
  1130 			delete iIfds[i];
       
  1131 			iIfds.Remove(i);
       
  1132 			return;
       
  1133 			}
       
  1134 		}
       
  1135 	}
       
  1136 	
       
  1137 	
       
  1138 CIfdGeneral* CExifReaderWriter::GetIfd(TInt aIfd)
       
  1139 	{
       
  1140 	TInt index;
       
  1141 	if (FindIfdIndex(aIfd, index))
       
  1142 		return iIfds[index];	
       
  1143 	else
       
  1144 		return NULL;
       
  1145 	}
       
  1146 
       
  1147 
       
  1148 
       
  1149 // Will only set the thumbnail if it is JPEG encoded.
       
  1150 void CExifReaderWriter::SetThumbnailDataBaseL(CIfdGeneral* ifd1, TBool aKeepIfd1)
       
  1151 	{
       
  1152 	ASSERT(ifd1);
       
  1153 	
       
  1154 	delete iJpegThumbnailData;
       
  1155 	iJpegThumbnailData = NULL;
       
  1156 	
       
  1157 	// Check for tag 0x0103 (Compression). It must indicate JPEG.
       
  1158 	TUint16 jpegCompressionValue = 0;	
       
  1159 	TInt err = ifd1->GetShortParam(KThumbTag0103[ETagValue], jpegCompressionValue);
       
  1160 	if(err == KErrNone && jpegCompressionValue == KJPEGEncodedThumbnail)
       
  1161 		{
       
  1162 		// This is a JPEG thumbnail. Check for tag 0x0201 (offset to the JPEG thumbnail SOI).
       
  1163  		TInt offset = 0;	
       
  1164  
       
  1165  		err = ifd1->GetIntegerParam(KThumbTag0201[ETagValue], offset);
       
  1166 		if(err == KErrNone)
       
  1167  			{
       
  1168  			// Check for tag 0x0202 (size of the JPEG thumbnail).
       
  1169  			TInt thumbSize = 0;
       
  1170  			
       
  1171  			err = ifd1->GetIntegerParam(KThumbTag0202[ETagValue], thumbSize);
       
  1172  			if (err == KErrNone)
       
  1173  				{
       
  1174 				TInt sizeTIFFHeader = KByteAlignmentByteCount + KFortyTwoByteCount + KIfdOffsetByteCount; 
       
  1175 			                                                
       
  1176 				if (thumbSize != (iExifDataLength - offset))
       
  1177 					{
       
  1178 					// incorrect offset/thumbSize - try correcting
       
  1179 					if ((offset >= sizeTIFFHeader)	&& (offset < iExifDataLength))
       
  1180 						{
       
  1181 						// offset looks good so adjust the size
       
  1182 						thumbSize = iExifDataLength - offset;
       
  1183 						}
       
  1184 					else if ((thumbSize >= 0) && (thumbSize < (iExifDataLength - sizeTIFFHeader)))
       
  1185 						{
       
  1186 						// size looks good so adjust the offset
       
  1187 						offset = iExifDataLength - thumbSize;
       
  1188 						}
       
  1189 					else
       
  1190 						{
       
  1191 						// can't be corrected - ignore thumbnail
       
  1192 						thumbSize = 0;
       
  1193 						}				
       
  1194 					}
       
  1195  				// If the size is valid, read thumbSize bytes at offset from iBase.
       
  1196 				if (thumbSize > 0)
       
  1197  					{			
       
  1198  					iJpegThumbnailData = HBufC8::NewL(thumbSize);
       
  1199  					iJpegThumbnailData->Des().Copy(&iBase[offset], thumbSize);
       
  1200 					return;	
       
  1201 					}			
       
  1202 				} // Check for 0x0202
       
  1203 			} // Check for 0x0201
       
  1204 		} // JPEG thumbnail
       
  1205 
       
  1206 	// Either:
       
  1207 	// -	The source IFD1 did not contain tag 0x0103 (Compression);
       
  1208 	// -	We have an uncompressed (bitmap) thumbnail (jpegCompressionValue == 1);
       
  1209 	// -	We have a thumbnail of an unknown/unsupported compression type. 
       
  1210 	// -	There were unrecoverable errors with tags 0x0201 (offset to thumbnail SOI) and 0x0202 (size of thumbnail).
       
  1211 	//
       
  1212 	// Bitmap thumbnails are supported by the Exif spec, but we do not currently have 
       
  1213 	// the means to support them fully in our software. Likewise we have no way of 
       
  1214 	// dealing with unknown compression types or images with badly corrupt 0x0201 and/or 0x0202.
       
  1215 	// The only thing to do is remove the corrupt copy of the source IFD1 from iIfds and
       
  1216 	// replace it with a default (which will be populated or removed as necessary later on).
       
  1217 
       
  1218 	// Remove the old IFD1 that describes the source thumbnail image
       
  1219 	RemoveThumbnailData();
       
  1220 
       
  1221 	
       
  1222 	if (aKeepIfd1)
       
  1223 		{
       
  1224 		// Add a new default IFD1 to describe the thumbnail image that we will generate.
       
  1225 		ifd1 = CIfd1::NewLC(0, NULL, iIntel);
       
  1226 		iIfds.AppendL(ifd1);
       
  1227 		CleanupStack::Pop(ifd1);		
       
  1228 		}
       
  1229 	}
       
  1230 
       
  1231 
       
  1232 
       
  1233 
       
  1234 // Copies the standard Exif file header stuff to the given buffer.
       
  1235 void CExifReaderWriter::WriteExifFileHeaderBaseL(const TUint aApp1Size, TUint8*& aPtr)
       
  1236 	{
       
  1237 	if(aApp1Size < KExifFileHeaderLength)
       
  1238 		{
       
  1239 		User::Leave(KErrNoMemory);
       
  1240 		}
       
  1241 	aPtr = Mem::Copy(aPtr, &KApp1Marker, KApp1MarkerByteCount);
       
  1242 	TUint8 appSizePtr[KApp1SizeLength];
       
  1243 	PtrWriteUtil::WriteBigEndianInt16(appSizePtr,aApp1Size);
       
  1244 	aPtr = Mem::Copy(aPtr, &appSizePtr, KApp1SizeLength);
       
  1245 	aPtr = Mem::Copy(aPtr, &KExifMarker, KExifMarkerByteCount);
       
  1246 	aPtr = Mem::Copy(aPtr, &KExifMarkerEnd, KExifMarkerEndByteCount);
       
  1247 	aPtr = Mem::Copy(aPtr, &KIntelByteAlignment, KByteAlignmentByteCount);
       
  1248 	aPtr = Mem::Copy(aPtr, &KFortyTwo, KFortyTwoByteCount);
       
  1249 	aPtr = Mem::Copy(aPtr, &KIfdOffset, KIfdOffsetByteCount);	
       
  1250 	}
       
  1251 	
       
  1252 void CExifReaderWriter::SetFirstIfdOffsetBase()
       
  1253 	{
       
  1254 	// Only set the first ifd offset if we have thumbnail data, or we will encode it
       
  1255 	if (iEncodeThumbnail || iJpegThumbnailData) 
       
  1256 		{
       
  1257 		// Locate the 1st Ifd offset - immediately after all tag data in the 0th Ifd (and before offset data).
       
  1258 		TUint offsetToFirstOffsetField = KExifFileHeaderLength;	
       
  1259 		CIfdGeneral* ifd = GetIfd(EZeroth);
       
  1260 		ASSERT(ifd);
       
  1261 		TUint16 size = ifd->EntryCount() * KMinimumIfdEntrySize;
       
  1262 		offsetToFirstOffsetField += size + KSizeOfEntryCount; // Need to account for the Ifd entry count.
       
  1263 		
       
  1264 		TInt offsetValue = KExifFileHeaderLength;
       
  1265 		// get the sizes of the ifds
       
  1266 		for(TInt i = 0; i < iIfds.Count(); i++)
       
  1267 			{
       
  1268 			CIfdGeneral* iFd = (iIfds)[i];
       
  1269 			TInt id = iFd->Ifd();
       
  1270 			if ((id == EZeroth)	||
       
  1271 				(id == EExifSub) ||
       
  1272 				(id == EInterop) ||
       
  1273 				(id == EGpsSub))
       
  1274 				{
       
  1275 				if (iFd->Size() != 0) 
       
  1276 					{
       
  1277 					offsetValue += KSizeOfEntryCount + iFd->Size() + KIfdOffsetByteCount;	
       
  1278 					}
       
  1279 				}
       
  1280 			}
       
  1281 
       
  1282 		// Number of bytes from the start of the Exif header to the 1st Ifd.
       
  1283 		// Since all offsets are calculated from the byte alignment, deduct this.
       
  1284 		offsetValue -= KByteCountToByteAlignment;	
       
  1285 		Mem::Copy(iData + offsetToFirstOffsetField, &offsetValue, sizeof(offsetValue));
       
  1286 		}
       
  1287 
       
  1288 	}
       
  1289 	
       
  1290 	
       
  1291 TInt CExifReaderWriter::GetThumbnailLengthOffsetBase(TUint& aThumbnailLengthOffset)
       
  1292 	{
       
  1293 	TUint offsetToLengthField = 0;
       
  1294 	TUint numFirstIfdEntries = 0;
       
  1295 
       
  1296 	offsetToLengthField += KExifFileHeaderLength;
       
  1297 	
       
  1298 	for (TInt i = 0; i < iIfds.Count(); i++)
       
  1299 		{
       
  1300 		TUint16 size = (iIfds)[i]->Size();
       
  1301 		if ((size > 0) && ((iIfds)[i]->Ifd() != EFirst))
       
  1302 			{
       
  1303 			offsetToLengthField += KSizeOfEntryCount; // Need to account for the Ifd entry count.
       
  1304 			offsetToLengthField += KIfdOffsetByteCount; // Need to account for the offset to the 1st Ifd.
       
  1305 			offsetToLengthField += size;
       
  1306 			}
       
  1307 		else if ((iIfds)[i]->Ifd() == EFirst)
       
  1308 			{
       
  1309 			numFirstIfdEntries = (iIfds)[i]->EntryCount(); 	
       
  1310 			}
       
  1311 		}
       
  1312 		
       
  1313 	offsetToLengthField += KSizeOfEntryCount; // For first Ifd's entry count.
       
  1314 	
       
  1315 	TUint8* tempPtr = iData + offsetToLengthField; // point to first entry in 1st Ifd.
       
  1316 	
       
  1317 	// Now step every 12 bytes to find location of the tag.
       
  1318 	TUint16 jpegLengthTag = KThumbTag0202[ETagValue];
       
  1319 	for (TUint j = 0; j < numFirstIfdEntries; j++)
       
  1320 		{
       
  1321 		TUint16 tag = PtrReadUtil::ReadUint16(tempPtr);
       
  1322 		if (tag == jpegLengthTag)
       
  1323 			{						
       
  1324 			aThumbnailLengthOffset = offsetToLengthField+KValueOffsetFieldPosition;
       
  1325 			return KErrNone;
       
  1326 			}
       
  1327 		offsetToLengthField += KMinimumIfdEntrySize;
       
  1328 		tempPtr += KMinimumIfdEntrySize;
       
  1329 		}	
       
  1330 	return KErrNotFound;
       
  1331 	}
       
  1332 	
       
  1333 HBufC8* CExifReaderWriter::GetJpegThumbnailData()
       
  1334 	{
       
  1335 	// don't delete previous parameter, this makes no sense in this case
       
  1336 	return iJpegThumbnailData;
       
  1337 	}
       
  1338 	
       
  1339 void CExifReaderWriter::SetThumbnailData(HBufC8* aJpegData)
       
  1340 	{
       
  1341 	delete iJpegThumbnailData;
       
  1342 	iJpegThumbnailData= aJpegData;
       
  1343 	if(iJpegThumbnailData != NULL) //Ensure new thumbnail data is added
       
  1344 		{
       
  1345 		iExifDataModified = ETrue;
       
  1346 		}
       
  1347 	}
       
  1348 
       
  1349 TBool CExifReaderWriter::IsExifDataModified() 
       
  1350 	{
       
  1351 	return iExifDataModified;
       
  1352 	}
       
  1353 	
       
  1354 void CExifReaderWriter::ResetExifDataModified() 
       
  1355 	{
       
  1356 	iExifDataModified = EFalse;
       
  1357 	}