Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2006-2007 Adobe Systems Incorporated
      3 // All Rights Reserved.
      4 //
      5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
      6 // accordance with the terms of the Adobe license agreement accompanying it.
      7 /*****************************************************************************/
      8 
      9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_info.cpp#1 $ */
     10 /* $DateTime: 2012/05/30 13:28:51 $ */
     11 /* $Change: 832332 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_info.h"
     17 
     18 #include "dng_camera_profile.h"
     19 #include "dng_exceptions.h"
     20 #include "dng_globals.h"
     21 #include "dng_host.h"
     22 #include "dng_tag_codes.h"
     23 #include "dng_parse_utils.h"
     24 #include "dng_safe_arithmetic.h"
     25 #include "dng_tag_types.h"
     26 #include "dng_tag_values.h"
     27 #include "dng_utils.h"
     28 
     29 /*****************************************************************************/
     30 
     31 dng_info::dng_info ()
     32 
     33 	:	fTIFFBlockOffset         (0)
     34 	,	fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
     35 	,	fBigEndian				 (false)
     36 	,	fMagic					 (0)
     37 	,	fExif					 ()
     38 	,	fShared					 ()
     39 	,	fMainIndex				 (-1)
     40 	,	fMaskIndex				 (-1)
     41 	,	fIFDCount				 (0)
     42 	,	fChainedIFDCount		 (0)
     43 	,	fMakerNoteNextIFD		 (0)
     44 
     45 	{
     46 
     47 	}
     48 
     49 /*****************************************************************************/
     50 
     51 dng_info::~dng_info ()
     52 	{
     53 
     54 	}
     55 
     56 /*****************************************************************************/
     57 
     58 void dng_info::ValidateMagic ()
     59 	{
     60 
     61 	switch (fMagic)
     62 		{
     63 
     64 		case magicTIFF:
     65 		case magicExtendedProfile:
     66 		case magicRawCache:
     67 		case magicPanasonic:
     68 		case magicOlympusA:
     69 		case magicOlympusB:
     70 			{
     71 
     72 			return;
     73 
     74 			}
     75 
     76 		default:
     77 			{
     78 
     79 			#if qDNGValidate
     80 
     81 			ReportError ("Invalid TIFF magic number");
     82 
     83 			#endif
     84 
     85 			ThrowBadFormat ();
     86 
     87 			}
     88 
     89 		}
     90 
     91 	}
     92 
     93 /*****************************************************************************/
     94 
     95 void dng_info::ParseTag (dng_host &host,
     96 						 dng_stream &stream,
     97 						 dng_exif *exif,
     98 						 dng_shared *shared,
     99 						 dng_ifd *ifd,
    100 						 uint32 parentCode,
    101 						 uint32 tagCode,
    102 						 uint32 tagType,
    103 						 uint32 tagCount,
    104 						 uint64 tagOffset,
    105 						 int64 offsetDelta)
    106 	{
    107 
    108 	bool isSubIFD = parentCode >= tcFirstSubIFD &&
    109 					parentCode <= tcLastSubIFD;
    110 
    111 	bool isMainIFD = (parentCode == 0 || isSubIFD) &&
    112 					 ifd &&
    113 					 ifd->fUsesNewSubFileType &&
    114 			 		 ifd->fNewSubFileType == sfMainImage;
    115 
    116 	// Panasonic RAW format stores private tags using tag codes < 254 in
    117 	// IFD 0.  Redirect the parsing of these tags into a logical
    118 	// "PanasonicRAW" IFD.
    119 
    120 	// Panasonic is starting to use some higher numbers also (280..283).
    121 
    122 	if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
    123 											(tagCode >= 280 && tagCode <= 283)))
    124 		{
    125 
    126 		parentCode = tcPanasonicRAW;
    127 
    128 		ifd = NULL;
    129 
    130 		}
    131 
    132 	stream.SetReadPosition (tagOffset);
    133 
    134 	if (ifd && ifd->ParseTag (stream,
    135 						 	  parentCode,
    136 						 	  tagCode,
    137 						 	  tagType,
    138 						 	  tagCount,
    139 						 	  tagOffset))
    140 		{
    141 
    142 		return;
    143 
    144 		}
    145 
    146 	stream.SetReadPosition (tagOffset);
    147 
    148 	if (exif && shared && exif->ParseTag (stream,
    149 										  *shared,
    150 										  parentCode,
    151 										  isMainIFD,
    152 										  tagCode,
    153 										  tagType,
    154 										  tagCount,
    155 										  tagOffset))
    156 		{
    157 
    158 		return;
    159 
    160 		}
    161 
    162 	stream.SetReadPosition (tagOffset);
    163 
    164 	if (shared && exif && shared->ParseTag (stream,
    165 											*exif,
    166 								    		parentCode,
    167 								    		isMainIFD,
    168 								    		tagCode,
    169 								    		tagType,
    170 								    		tagCount,
    171 								    		tagOffset,
    172 								    		offsetDelta))
    173 		{
    174 
    175 		return;
    176 
    177 		}
    178 
    179 	if (parentCode == tcLeicaMakerNote &&
    180 		tagType == ttUndefined &&
    181 		tagCount >= 14)
    182 		{
    183 
    184 		if (ParseMakerNoteIFD (host,
    185 							   stream,
    186 							   tagCount,
    187 							   tagOffset,
    188 							   offsetDelta,
    189 							   tagOffset,
    190 							   stream.Length (),
    191 							   tcLeicaMakerNote))
    192 			{
    193 
    194 			return;
    195 
    196 			}
    197 
    198 		}
    199 
    200 	if (parentCode == tcOlympusMakerNote &&
    201 		tagType == ttUndefined &&
    202 		tagCount >= 14)
    203 		{
    204 
    205 		uint32 olympusMakerParent = 0;
    206 
    207 		switch (tagCode)
    208 			{
    209 
    210 			case 8208:
    211 				olympusMakerParent = tcOlympusMakerNote8208;
    212 				break;
    213 
    214 			case 8224:
    215 				olympusMakerParent = tcOlympusMakerNote8224;
    216 				break;
    217 
    218 			case 8240:
    219 				olympusMakerParent = tcOlympusMakerNote8240;
    220 				break;
    221 
    222 			case 8256:
    223 				olympusMakerParent = tcOlympusMakerNote8256;
    224 				break;
    225 
    226 			case 8272:
    227 				olympusMakerParent = tcOlympusMakerNote8272;
    228 				break;
    229 
    230 			case 12288:
    231 				olympusMakerParent = tcOlympusMakerNote12288;
    232 				break;
    233 
    234 			default:
    235 				break;
    236 
    237 			}
    238 
    239 		if (olympusMakerParent)
    240 			{
    241 
    242 			// Olympus made a mistake in some camera models in computing
    243 			// the size of these sub-tags, so we fudge the count.
    244 
    245 			if (ParseMakerNoteIFD (host,
    246 								   stream,
    247 							       stream.Length () - tagOffset,
    248 				   	  		       tagOffset,
    249 				   	  		       offsetDelta,
    250 				   	  		       tagOffset,
    251 				   	  		       stream.Length (),
    252 				   	  		       olympusMakerParent))
    253 				{
    254 
    255 				return;
    256 
    257 				}
    258 
    259 			}
    260 
    261 		}
    262 
    263 	if (parentCode == tcRicohMakerNote &&
    264 		tagCode == 0x2001 &&
    265 		tagType == ttUndefined &&
    266 		tagCount > 22)
    267 		{
    268 
    269 		char header [20];
    270 
    271 		stream.SetReadPosition (tagOffset);
    272 
    273 		stream.Get (header, sizeof (header));
    274 
    275 		if (memcmp (header, "[Ricoh Camera Info]", 19) == 0)
    276 			{
    277 
    278 			ParseMakerNoteIFD (host,
    279 							   stream,
    280 							   tagCount - 20,
    281 				   	  		   tagOffset + 20,
    282 				   	  		   offsetDelta,
    283 				   	  		   tagOffset + 20,
    284 				   	  		   tagOffset + tagCount,
    285 				   	  		   tcRicohMakerNoteCameraInfo);
    286 
    287 			return;
    288 
    289 			}
    290 
    291 		}
    292 
    293 	#if qDNGValidate
    294 
    295 		{
    296 
    297 		stream.SetReadPosition (tagOffset);
    298 
    299 		if (gVerbose)
    300 			{
    301 
    302 			printf ("*");
    303 
    304 			DumpTagValues (stream,
    305 						   LookupTagType (tagType),
    306 						   parentCode,
    307 						   tagCode,
    308 						   tagType,
    309 						   tagCount);
    310 
    311 			}
    312 
    313 		// If type is ASCII, then parse anyway so we report any ASCII
    314 		// NULL termination or character set errors.
    315 
    316 		else if (tagType == ttAscii)
    317 			{
    318 
    319 			dng_string s;
    320 
    321 			ParseStringTag (stream,
    322 							parentCode,
    323 							tagCode,
    324 							tagCount,
    325 							s,
    326 							false);
    327 
    328 			}
    329 
    330 		}
    331 
    332 	#endif
    333 
    334 	}
    335 
    336 /*****************************************************************************/
    337 
    338 bool dng_info::ValidateIFD (dng_stream &stream,
    339 						    uint64 ifdOffset,
    340 						    int64 offsetDelta)
    341 	{
    342 
    343 	// Make sure we have a count.
    344 
    345 	if (ifdOffset + 2 > stream.Length ())
    346 		{
    347 		return false;
    348 		}
    349 
    350 	// Get entry count.
    351 
    352 	stream.SetReadPosition (ifdOffset);
    353 
    354 	uint32 ifdEntries = stream.Get_uint16 ();
    355 
    356 	if (ifdEntries < 1)
    357 		{
    358 		return false;
    359 		}
    360 
    361 	// Make sure we have room for all entries and next IFD link.
    362 
    363 	if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
    364 		{
    365 		return false;
    366 		}
    367 
    368 	// Check each entry.
    369 
    370 	for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
    371 		{
    372 
    373 		stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
    374 
    375 		stream.Skip (2);		// Ignore tag code.
    376 
    377 		uint32 tagType  = stream.Get_uint16 ();
    378 		uint32 tagCount = stream.Get_uint32 ();
    379 
    380 		uint32 tag_type_size = TagTypeSize (tagType);
    381 
    382 		if (tag_type_size == 0)
    383 			{
    384 			return false;
    385 			}
    386 
    387 		uint32 tag_data_size = SafeUint32Mult(tagCount, tag_type_size);
    388 
    389 		if (tag_data_size > 4)
    390 			{
    391 
    392 			uint64 tagOffset = stream.Get_uint32 ();
    393 
    394 			tagOffset += offsetDelta;
    395 
    396 			if (SafeUint64Add(tagOffset, tag_data_size) > stream.Length())
    397 				{
    398 				return false;
    399 				}
    400 
    401 			}
    402 
    403 		}
    404 
    405 	return true;
    406 
    407 	}
    408 
    409 /*****************************************************************************/
    410 
    411 void dng_info::ParseIFD (dng_host &host,
    412 						 dng_stream &stream,
    413 						 dng_exif *exif,
    414 						 dng_shared *shared,
    415 						 dng_ifd *ifd,
    416 						 uint64 ifdOffset,
    417 						 int64 offsetDelta,
    418 						 uint32 parentCode)
    419 	{
    420 
    421 	#if qDNGValidate
    422 
    423 	bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
    424 						parentCode <= tcLastMakerNoteIFD);
    425 
    426 	#endif
    427 
    428 	stream.SetReadPosition (ifdOffset);
    429 
    430 	if (ifd)
    431 		{
    432 		ifd->fThisIFD = ifdOffset;
    433 		}
    434 
    435 	uint32 ifdEntries = stream.Get_uint16 ();
    436 
    437 	#if qDNGValidate
    438 
    439 	if (gVerbose)
    440 		{
    441 
    442 		printf ("%s: Offset = %u, Entries = %u\n\n",
    443 				LookupParentCode (parentCode),
    444 			    (unsigned) ifdOffset,
    445 			    (unsigned) ifdEntries);
    446 
    447 		}
    448 
    449 	if ((ifdOffset & 1) && !isMakerNote)
    450 		{
    451 
    452 		char message [256];
    453 
    454 		sprintf (message,
    455 				 "%s has odd offset (%u)",
    456 				 LookupParentCode (parentCode),
    457 				 (unsigned) ifdOffset);
    458 
    459 		ReportWarning (message);
    460 
    461 		}
    462 
    463 	#endif
    464 
    465 	uint32 prev_tag_code = 0;
    466 
    467 	for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
    468 		{
    469 
    470 		stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
    471 
    472 		uint32 tagCode  = stream.Get_uint16 ();
    473 		uint32 tagType  = stream.Get_uint16 ();
    474 
    475 		// Minolta 7D files have a bug in the EXIF block where the count
    476 		// is wrong, and we run off into next IFD link.  So if abort parsing
    477 		// if we get a zero code/type combinations.
    478 
    479 		if (tagCode == 0 && tagType == 0)
    480 			{
    481 
    482 			#if qDNGValidate
    483 
    484 			char message [256];
    485 
    486 			sprintf (message,
    487 					 "%s had zero/zero tag code/type entry",
    488 					 LookupParentCode (parentCode));
    489 
    490 			ReportWarning (message);
    491 
    492 			#endif
    493 
    494 			return;
    495 
    496 			}
    497 
    498 		uint32 tagCount = stream.Get_uint32 ();
    499 
    500 		#if qDNGValidate
    501 
    502 			{
    503 
    504 			if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote)
    505 				{
    506 
    507 				char message [256];
    508 
    509 				sprintf (message,
    510 						 "%s tags are not sorted in ascending numerical order",
    511 						 LookupParentCode (parentCode));
    512 
    513 				ReportWarning (message);
    514 
    515 				}
    516 
    517 			}
    518 
    519 		#endif
    520 
    521 		prev_tag_code = tagCode;
    522 
    523 		uint32 tag_type_size = TagTypeSize (tagType);
    524 
    525 		if (tag_type_size == 0)
    526 			{
    527 
    528 			#if qDNGValidate
    529 
    530 				{
    531 
    532 				char message [256];
    533 
    534 				sprintf (message,
    535 						 "%s %s has unknown type (%u)",
    536 						 LookupParentCode (parentCode),
    537 						 LookupTagCode (parentCode, tagCode),
    538 						 (unsigned) tagType);
    539 
    540 				ReportWarning (message);
    541 
    542 				}
    543 
    544 			#endif
    545 
    546 			continue;
    547 
    548 			}
    549 
    550 		uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
    551 
    552 		if (SafeUint32Mult(tagCount, tag_type_size) > 4)
    553 			{
    554 
    555 			tagOffset = stream.Get_uint32 ();
    556 
    557 			#if qDNGValidate
    558 
    559 				{
    560 
    561 				if (!(ifdOffset & 1) &&
    562 				     (tagOffset & 1) &&
    563 				    !isMakerNote     &&
    564 				    parentCode != tcKodakDCRPrivateIFD &&
    565 					parentCode != tcKodakKDCPrivateIFD)
    566 					{
    567 
    568 					char message [256];
    569 
    570 					sprintf (message,
    571 							 "%s %s has odd data offset (%u)",
    572 						 	 LookupParentCode (parentCode),
    573 						 	 LookupTagCode (parentCode, tagCode),
    574 							 (unsigned) tagOffset);
    575 
    576 					ReportWarning (message);
    577 
    578 					}
    579 
    580 				}
    581 
    582 			#endif
    583 
    584 			tagOffset += offsetDelta;
    585 
    586 			stream.SetReadPosition (tagOffset);
    587 
    588 			}
    589 
    590 		ParseTag (host,
    591 				  stream,
    592 			      exif,
    593 				  shared,
    594 				  ifd,
    595 				  parentCode,
    596 				  tagCode,
    597 				  tagType,
    598 				  tagCount,
    599 				  tagOffset,
    600 				  offsetDelta);
    601 
    602 		}
    603 
    604 	stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
    605 
    606 	uint32 nextIFD = stream.Get_uint32 ();
    607 
    608 	#if qDNGValidate
    609 
    610 	if (gVerbose)
    611 		{
    612 		printf ("NextIFD = %u\n", (unsigned) nextIFD);
    613 		}
    614 
    615 	#endif
    616 
    617 	if (ifd)
    618 		{
    619 		ifd->fNextIFD = nextIFD;
    620 		}
    621 
    622 	#if qDNGValidate
    623 
    624 	if (nextIFD)
    625 		{
    626 
    627 		if (parentCode != 0 &&
    628 				(parentCode < tcFirstChainedIFD ||
    629 				 parentCode > tcLastChainedIFD  ))
    630 			{
    631 
    632 			char message [256];
    633 
    634 			sprintf (message,
    635 					 "%s has an unexpected non-zero NextIFD (%u)",
    636 				 	 LookupParentCode (parentCode),
    637 				 	 (unsigned) nextIFD);
    638 
    639 			ReportWarning (message);
    640 
    641 			}
    642 
    643 		}
    644 
    645 	if (gVerbose)
    646 		{
    647 		printf ("\n");
    648 		}
    649 
    650 	#endif
    651 
    652 	}
    653 
    654 /*****************************************************************************/
    655 
    656 bool dng_info::ParseMakerNoteIFD (dng_host &host,
    657 								  dng_stream &stream,
    658 								  uint64 ifdSize,
    659 						 		  uint64 ifdOffset,
    660 								  int64 offsetDelta,
    661 								  uint64 minOffset,
    662 								  uint64 maxOffset,
    663 						 		  uint32 parentCode)
    664 	{
    665 
    666 	uint32 tagIndex;
    667 	uint32 tagCode;
    668 	uint32 tagType;
    669 	uint32 tagCount;
    670 
    671 	// Assume there is no next IFD pointer.
    672 
    673 	fMakerNoteNextIFD = 0;
    674 
    675 	// If size is too small to hold a single entry IFD, abort.
    676 
    677 	if (ifdSize < 14)
    678 		{
    679 		return false;
    680 		}
    681 
    682 	// Get entry count.
    683 
    684 	stream.SetReadPosition (ifdOffset);
    685 
    686 	uint32 ifdEntries = stream.Get_uint16 ();
    687 
    688 	// Make the entry count if reasonable for the MakerNote size.
    689 
    690 	if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
    691 		{
    692 		return false;
    693 		}
    694 
    695 	// Scan IFD to verify all the tag types are all valid.
    696 
    697 	for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
    698 		{
    699 
    700 		stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
    701 
    702 		tagType = stream.Get_uint16 ();
    703 
    704 		// Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we
    705 		// need to ignore them.  This was a "firmware 1.0.4" Canon 40D raw file.
    706 
    707 		if (parentCode == tcCanonMakerNote && tagType == 0)
    708 			{
    709 			continue;
    710 			}
    711 
    712 		if (TagTypeSize (tagType) == 0)
    713 			{
    714 			return false;
    715 			}
    716 
    717 		}
    718 
    719 	// OK, the IFD looks reasonable enough to parse.
    720 
    721 	#if qDNGValidate
    722 
    723 	if (gVerbose)
    724 		{
    725 
    726 		printf ("%s: Offset = %u, Entries = %u\n\n",
    727 				LookupParentCode (parentCode),
    728 			    (unsigned) ifdOffset,
    729 			    (unsigned) ifdEntries);
    730 
    731 		}
    732 
    733 	#endif
    734 
    735 	for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
    736 		{
    737 
    738 		stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
    739 
    740 		tagCode  = stream.Get_uint16 ();
    741 		tagType  = stream.Get_uint16 ();
    742 		tagCount = stream.Get_uint32 ();
    743 
    744 		if (tagType == 0)
    745 			{
    746 			continue;
    747 			}
    748 
    749 		uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
    750 
    751 		uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
    752 
    753 		if (tagSize > 4)
    754 			{
    755 
    756 			tagOffset = stream.Get_uint32 () + offsetDelta;
    757 
    758 			if (tagOffset           < minOffset ||
    759 				SafeUint64Add(tagOffset, tagSize) > maxOffset)
    760 				{
    761 
    762 				// Tag data is outside the valid offset range,
    763 				// so ignore this tag.
    764 
    765 				continue;
    766 
    767 				}
    768 
    769 			stream.SetReadPosition (tagOffset);
    770 
    771 			}
    772 
    773 		// Olympus switched to using IFDs in version 3 makernotes.
    774 
    775 		if (parentCode == tcOlympusMakerNote &&
    776 			tagType == ttIFD &&
    777 			tagCount == 1)
    778 			{
    779 
    780 			uint32 olympusMakerParent = 0;
    781 
    782 			switch (tagCode)
    783 				{
    784 
    785 				case 8208:
    786 					olympusMakerParent = tcOlympusMakerNote8208;
    787 					break;
    788 
    789 				case 8224:
    790 					olympusMakerParent = tcOlympusMakerNote8224;
    791 					break;
    792 
    793 				case 8240:
    794 					olympusMakerParent = tcOlympusMakerNote8240;
    795 					break;
    796 
    797 				case 8256:
    798 					olympusMakerParent = tcOlympusMakerNote8256;
    799 					break;
    800 
    801 				case 8272:
    802 					olympusMakerParent = tcOlympusMakerNote8272;
    803 					break;
    804 
    805 				case 12288:
    806 					olympusMakerParent = tcOlympusMakerNote12288;
    807 					break;
    808 
    809 				default:
    810 					break;
    811 
    812 				}
    813 
    814 			if (olympusMakerParent)
    815 				{
    816 
    817 				stream.SetReadPosition (tagOffset);
    818 
    819 				uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
    820 
    821 				if (subMakerNoteOffset >= minOffset &&
    822 					subMakerNoteOffset <  maxOffset)
    823 					{
    824 
    825 					if (ParseMakerNoteIFD (host,
    826 										   stream,
    827 										   maxOffset - subMakerNoteOffset,
    828 										   subMakerNoteOffset,
    829 										   offsetDelta,
    830 										   minOffset,
    831 										   maxOffset,
    832 										   olympusMakerParent))
    833 						{
    834 
    835 						continue;
    836 
    837 						}
    838 
    839 					}
    840 
    841 				}
    842 
    843 			stream.SetReadPosition (tagOffset);
    844 
    845 			}
    846 
    847 		ParseTag (host,
    848 				  stream,
    849 				  fExif.Get (),
    850 				  fShared.Get (),
    851 				  NULL,
    852 				  parentCode,
    853 				  tagCode,
    854 				  tagType,
    855 				  tagCount,
    856 				  tagOffset,
    857 				  offsetDelta);
    858 
    859 		}
    860 
    861 	// Grab next IFD pointer, for possible use.
    862 
    863 	if (ifdSize >= 2 + ifdEntries * 12 + 4)
    864 		{
    865 
    866 		stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
    867 
    868 		fMakerNoteNextIFD = stream.Get_uint32 ();
    869 
    870 		}
    871 
    872 	#if qDNGValidate
    873 
    874 	if (gVerbose)
    875 		{
    876 		printf ("\n");
    877 		}
    878 
    879 	#endif
    880 
    881 	return true;
    882 
    883 	}
    884 
    885 /*****************************************************************************/
    886 
    887 void dng_info::ParseMakerNote (dng_host &host,
    888 							   dng_stream &stream,
    889 							   uint32 makerNoteCount,
    890 							   uint64 makerNoteOffset,
    891 							   int64 offsetDelta,
    892 							   uint64 minOffset,
    893 							   uint64 maxOffset)
    894 	{
    895 
    896 	uint8 firstBytes [16];
    897 
    898 	memset (firstBytes, 0, sizeof (firstBytes));
    899 
    900 	stream.SetReadPosition (makerNoteOffset);
    901 
    902 	stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
    903 												 makerNoteCount));
    904 
    905 	// Epson MakerNote with header.
    906 
    907 	if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
    908 		{
    909 
    910 		if (makerNoteCount > 8)
    911 			{
    912 
    913 			ParseMakerNoteIFD (host,
    914 							   stream,
    915 							   makerNoteCount - 8,
    916 				   	  		   makerNoteOffset + 8,
    917 				   	  		   offsetDelta,
    918 				   	  		   minOffset,
    919 				   	  		   maxOffset,
    920 				   	  		   tcEpsonMakerNote);
    921 
    922 			}
    923 
    924 		return;
    925 
    926 		}
    927 
    928 	// Fujifilm MakerNote.
    929 
    930 	if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
    931 		{
    932 
    933 		stream.SetReadPosition (makerNoteOffset + 8);
    934 
    935 		TempLittleEndian tempEndian (stream);
    936 
    937 		uint32 ifd_offset = stream.Get_uint32 ();
    938 
    939 		if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
    940 			{
    941 
    942 			ParseMakerNoteIFD (host,
    943 							   stream,
    944 							   makerNoteCount - ifd_offset,
    945 							   makerNoteOffset + ifd_offset,
    946 							   makerNoteOffset,
    947 							   minOffset,
    948 							   maxOffset,
    949 							   tcFujiMakerNote);
    950 
    951 			}
    952 
    953 		return;
    954 
    955 		}
    956 
    957 	// Leica MakerNote for models that store entry offsets relative to the start of
    958 	// the MakerNote (e.g., M9).
    959 
    960 	if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
    961 		(memcmp (firstBytes, "LEICA0\003\000",	  8) == 0) ||
    962 		(memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
    963 		(memcmp (firstBytes, "LEICA\000\005\000", 8) == 0))
    964 		{
    965 
    966 		if (makerNoteCount > 8)
    967 			{
    968 
    969 			ParseMakerNoteIFD (host,
    970 							   stream,
    971 							   makerNoteCount - 8,
    972 							   makerNoteOffset + 8,
    973 							   makerNoteOffset,
    974 							   minOffset,
    975 							   maxOffset,
    976 							   tcLeicaMakerNote);
    977 
    978 			}
    979 
    980 		return;
    981 
    982 		}
    983 
    984 	// Leica MakerNote for models that store absolute entry offsets (i.e., relative
    985 	// to the start of the file, e.g., S2).
    986 
    987 	if (memcmp (firstBytes, "LEICA\000\002\377", 8) == 0)
    988 		{
    989 
    990 		if (makerNoteCount > 8)
    991 			{
    992 
    993 			ParseMakerNoteIFD (host,
    994 							   stream,
    995 							   makerNoteCount - 8,
    996 							   makerNoteOffset + 8,
    997 							   offsetDelta,
    998 							   minOffset,
    999 							   maxOffset,
   1000 							   tcLeicaMakerNote);
   1001 
   1002 			}
   1003 
   1004 		return;
   1005 
   1006 		}
   1007 
   1008 	// Nikon version 2 MakerNote with header.
   1009 
   1010 	if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
   1011 		{
   1012 
   1013 		stream.SetReadPosition (makerNoteOffset + 10);
   1014 
   1015 		bool bigEndian = false;
   1016 
   1017 		uint16 endianMark = stream.Get_uint16 ();
   1018 
   1019 		if (endianMark == byteOrderMM)
   1020 			{
   1021 			bigEndian = true;
   1022 			}
   1023 
   1024 		else if (endianMark != byteOrderII)
   1025 			{
   1026 			return;
   1027 			}
   1028 
   1029 		TempBigEndian temp_endian (stream, bigEndian);
   1030 
   1031 		uint16 magic = stream.Get_uint16 ();
   1032 
   1033 		if (magic != 42)
   1034 			{
   1035 			return;
   1036 			}
   1037 
   1038 		uint32 ifd_offset = stream.Get_uint32 ();
   1039 
   1040 		if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
   1041 			{
   1042 
   1043 			ParseMakerNoteIFD (host,
   1044 							   stream,
   1045 							   makerNoteCount - 10 - ifd_offset,
   1046 							   makerNoteOffset + 10 + ifd_offset,
   1047 							   makerNoteOffset + 10,
   1048 							   minOffset,
   1049 							   maxOffset,
   1050 							   tcNikonMakerNote);
   1051 
   1052 			}
   1053 
   1054 		return;
   1055 
   1056 		}
   1057 
   1058 	// Newer version of Olympus MakerNote with byte order mark.
   1059 
   1060 	if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
   1061 		{
   1062 
   1063 		stream.SetReadPosition (makerNoteOffset + 8);
   1064 
   1065 		bool bigEndian = false;
   1066 
   1067 		uint16 endianMark = stream.Get_uint16 ();
   1068 
   1069 		if (endianMark == byteOrderMM)
   1070 			{
   1071 			bigEndian = true;
   1072 			}
   1073 
   1074 		else if (endianMark != byteOrderII)
   1075 			{
   1076 			return;
   1077 			}
   1078 
   1079 		TempBigEndian temp_endian (stream, bigEndian);
   1080 
   1081 		uint16 version = stream.Get_uint16 ();
   1082 
   1083 		if (version != 3)
   1084 			{
   1085 			return;
   1086 			}
   1087 
   1088 		if (makerNoteCount > 12)
   1089 			{
   1090 
   1091 			ParseMakerNoteIFD (host,
   1092 							   stream,
   1093 							   makerNoteCount - 12,
   1094 				   	  		   makerNoteOffset + 12,
   1095 				   	  		   makerNoteOffset,
   1096 				   	  		   minOffset,
   1097 				   	  		   maxOffset,
   1098 				   	  		   tcOlympusMakerNote);
   1099 
   1100 			}
   1101 
   1102 		return;
   1103 
   1104 		}
   1105 
   1106 	// Olympus MakerNote with header.
   1107 
   1108 	if (memcmp (firstBytes, "OLYMP", 5) == 0)
   1109 		{
   1110 
   1111 		if (makerNoteCount > 8)
   1112 			{
   1113 
   1114 			ParseMakerNoteIFD (host,
   1115 							   stream,
   1116 							   makerNoteCount - 8,
   1117 				   	  		   makerNoteOffset + 8,
   1118 				   	  		   offsetDelta,
   1119 				   	  		   minOffset,
   1120 				   	  		   maxOffset,
   1121 				   	  		   tcOlympusMakerNote);
   1122 
   1123 			}
   1124 
   1125 		return;
   1126 
   1127 		}
   1128 
   1129 	// Panasonic MakerNote.
   1130 
   1131 	if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
   1132 		{
   1133 
   1134 		if (makerNoteCount > 12)
   1135 			{
   1136 
   1137 			ParseMakerNoteIFD (host,
   1138 							   stream,
   1139 							   makerNoteCount - 12,
   1140 							   makerNoteOffset + 12,
   1141 							   offsetDelta,
   1142 							   minOffset,
   1143 							   maxOffset,
   1144 							   tcPanasonicMakerNote);
   1145 
   1146 			}
   1147 
   1148 		return;
   1149 
   1150 		}
   1151 
   1152 	// Pentax MakerNote.
   1153 
   1154 	if (memcmp (firstBytes, "AOC", 4) == 0)
   1155 		{
   1156 
   1157 		if (makerNoteCount > 6)
   1158 			{
   1159 
   1160 			stream.SetReadPosition (makerNoteOffset + 4);
   1161 
   1162 			bool bigEndian = stream.BigEndian ();
   1163 
   1164 			uint16 endianMark = stream.Get_uint16 ();
   1165 
   1166 			if (endianMark == byteOrderMM)
   1167 				{
   1168 				bigEndian = true;
   1169 				}
   1170 
   1171 			else if (endianMark == byteOrderII)
   1172 				{
   1173 				bigEndian = false;
   1174 				}
   1175 
   1176 			TempBigEndian temp_endian (stream, bigEndian);
   1177 
   1178 			ParseMakerNoteIFD (host,
   1179 							   stream,
   1180 							   makerNoteCount - 6,
   1181 							   makerNoteOffset + 6,
   1182 							   offsetDelta,
   1183 							   minOffset,
   1184 							   maxOffset,
   1185 							   tcPentaxMakerNote);
   1186 
   1187 			}
   1188 
   1189 		return;
   1190 
   1191 		}
   1192 
   1193 	// Ricoh MakerNote.
   1194 
   1195 	if (memcmp (firstBytes, "RICOH", 5) == 0 ||
   1196 		memcmp (firstBytes, "Ricoh", 5) == 0)
   1197 		{
   1198 
   1199 		if (makerNoteCount > 8)
   1200 			{
   1201 
   1202 			TempBigEndian tempEndian (stream);
   1203 
   1204 			ParseMakerNoteIFD (host,
   1205 							   stream,
   1206 							   makerNoteCount - 8,
   1207 				   	  		   makerNoteOffset + 8,
   1208 				   	  		   offsetDelta,
   1209 				   	  		   minOffset,
   1210 				   	  		   maxOffset,
   1211 				   	  		   tcRicohMakerNote);
   1212 
   1213 			}
   1214 
   1215 		return;
   1216 
   1217 		}
   1218 
   1219 	// Nikon MakerNote without header.
   1220 
   1221 	if (fExif->fMake.StartsWith ("NIKON"))
   1222 		{
   1223 
   1224 		ParseMakerNoteIFD (host,
   1225 						   stream,
   1226 						   makerNoteCount,
   1227 			   	  		   makerNoteOffset,
   1228 			   	  		   offsetDelta,
   1229 			   	  		   minOffset,
   1230 			   	  		   maxOffset,
   1231 			   	  		   tcNikonMakerNote);
   1232 
   1233 		return;
   1234 
   1235 		}
   1236 
   1237 	// Canon MakerNote.
   1238 
   1239 	if (fExif->fMake.StartsWith ("CANON"))
   1240 		{
   1241 
   1242 		ParseMakerNoteIFD (host,
   1243 						   stream,
   1244 						   makerNoteCount,
   1245 			   	  		   makerNoteOffset,
   1246 			   	  		   offsetDelta,
   1247 			   	  		   minOffset,
   1248 			   	  		   maxOffset,
   1249 			   	  		   tcCanonMakerNote);
   1250 
   1251 		return;
   1252 
   1253 		}
   1254 
   1255 	// Minolta MakerNote.
   1256 
   1257 	if (fExif->fMake.StartsWith ("MINOLTA"       ) ||
   1258 		fExif->fMake.StartsWith ("KONICA MINOLTA"))
   1259 		{
   1260 
   1261 		ParseMakerNoteIFD (host,
   1262 						   stream,
   1263 						   makerNoteCount,
   1264 						   makerNoteOffset,
   1265 						   offsetDelta,
   1266 						   minOffset,
   1267 						   maxOffset,
   1268 						   tcMinoltaMakerNote);
   1269 
   1270 		return;
   1271 
   1272 		}
   1273 
   1274 	// Sony MakerNote.
   1275 
   1276 	if (fExif->fMake.StartsWith ("SONY"))
   1277 		{
   1278 
   1279 		ParseMakerNoteIFD (host,
   1280 						   stream,
   1281 						   makerNoteCount,
   1282 						   makerNoteOffset,
   1283 						   offsetDelta,
   1284 						   minOffset,
   1285 						   maxOffset,
   1286 						   tcSonyMakerNote);
   1287 
   1288 		return;
   1289 
   1290 		}
   1291 
   1292 	// Kodak MakerNote.
   1293 
   1294 	if (fExif->fMake.StartsWith ("EASTMAN KODAK"))
   1295 		{
   1296 
   1297 		ParseMakerNoteIFD (host,
   1298 						   stream,
   1299 						   makerNoteCount,
   1300 			   	  		   makerNoteOffset,
   1301 			   	  		   offsetDelta,
   1302 			   	  		   minOffset,
   1303 			   	  		   maxOffset,
   1304 			   	  		   tcKodakMakerNote);
   1305 
   1306 		return;
   1307 
   1308 		}
   1309 
   1310 	// Mamiya MakerNote.
   1311 
   1312 	if (fExif->fMake.StartsWith ("Mamiya"))
   1313 		{
   1314 
   1315 		ParseMakerNoteIFD (host,
   1316 						   stream,
   1317 						   makerNoteCount,
   1318 			   	  		   makerNoteOffset,
   1319 			   	  		   offsetDelta,
   1320 			   	  		   minOffset,
   1321 			   	  		   maxOffset,
   1322 			   	  		   tcMamiyaMakerNote);
   1323 
   1324 		// Mamiya uses a MakerNote chain.
   1325 
   1326 		while (fMakerNoteNextIFD)
   1327 			{
   1328 
   1329 			ParseMakerNoteIFD (host,
   1330 							   stream,
   1331 							   makerNoteCount,
   1332 							   offsetDelta + fMakerNoteNextIFD,
   1333 							   offsetDelta,
   1334 							   minOffset,
   1335 							   maxOffset,
   1336 							   tcMamiyaMakerNote);
   1337 
   1338 			}
   1339 
   1340 		return;
   1341 
   1342 		}
   1343 
   1344 	// Nikon MakerNote without header.
   1345 
   1346 	if (fExif->fMake.StartsWith ("Hasselblad"))
   1347 		{
   1348 
   1349 		ParseMakerNoteIFD (host,
   1350 						   stream,
   1351 						   makerNoteCount,
   1352 			   	  		   makerNoteOffset,
   1353 			   	  		   offsetDelta,
   1354 			   	  		   minOffset,
   1355 			   	  		   maxOffset,
   1356 			   	  		   tcHasselbladMakerNote);
   1357 
   1358 		return;
   1359 
   1360 		}
   1361 
   1362 	// Samsung MakerNote.
   1363 
   1364 	if (fExif->fMake.StartsWith ("Samsung"))
   1365 		{
   1366 
   1367 		ParseMakerNoteIFD (host,
   1368 						   stream,
   1369 						   makerNoteCount,
   1370 						   makerNoteOffset,
   1371 						   makerNoteOffset,
   1372 						   minOffset,
   1373 						   maxOffset,
   1374 						   tcSamsungMakerNote);
   1375 
   1376 		return;
   1377 
   1378 		}
   1379 
   1380 	// Casio MakerNote.
   1381 
   1382 	if (fExif->fMake.StartsWith ("CASIO COMPUTER") &&
   1383 		memcmp (firstBytes, "QVC\000\000\000", 6) == 0)
   1384 		{
   1385 
   1386 		ParseMakerNoteIFD (host,
   1387 						   stream,
   1388 						   makerNoteCount - 6,
   1389 						   makerNoteOffset + 6,
   1390 						   makerNoteOffset,
   1391 						   minOffset,
   1392 						   maxOffset,
   1393 						   tcCasioMakerNote);
   1394 
   1395 		return;
   1396 
   1397 		}
   1398 
   1399 	}
   1400 
   1401 /*****************************************************************************/
   1402 
   1403 void dng_info::ParseSonyPrivateData (dng_host & /* host */,
   1404 									 dng_stream & /* stream */,
   1405 									 uint64 /* count */,
   1406 									 uint64 /* oldOffset */,
   1407 									 uint64 /* newOffset */)
   1408 	{
   1409 
   1410 	// Sony private data is encrypted, sorry.
   1411 
   1412 	}
   1413 
   1414 /*****************************************************************************/
   1415 
   1416 void dng_info::ParseDNGPrivateData (dng_host &host,
   1417 									dng_stream &stream)
   1418 	{
   1419 
   1420 	if (fShared->fDNGPrivateDataCount < 2)
   1421 		{
   1422 		return;
   1423 		}
   1424 
   1425 	// DNG private data should always start with a null-terminated
   1426 	// company name, to define the format of the private data.
   1427 
   1428 	dng_string privateName;
   1429 
   1430 		{
   1431 
   1432 		char buffer [64];
   1433 
   1434 		stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
   1435 
   1436 		uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
   1437 										sizeof (buffer) - 1);
   1438 
   1439 		stream.Get (buffer, readLength);
   1440 
   1441 		buffer [readLength] = 0;
   1442 
   1443 		privateName.Set (buffer);
   1444 
   1445 		}
   1446 
   1447 	// Pentax is storing their MakerNote in the DNGPrivateData data.
   1448 
   1449 	if (privateName.StartsWith ("PENTAX" ) ||
   1450 		privateName.StartsWith ("SAMSUNG"))
   1451 		{
   1452 
   1453 		#if qDNGValidate
   1454 
   1455 		if (gVerbose)
   1456 			{
   1457 			printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
   1458 			}
   1459 
   1460 		#endif
   1461 
   1462 		stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
   1463 
   1464 		bool bigEndian = stream.BigEndian ();
   1465 
   1466 		uint16 endianMark = stream.Get_uint16 ();
   1467 
   1468 		if (endianMark == byteOrderMM)
   1469 			{
   1470 			bigEndian = true;
   1471 			}
   1472 
   1473 		else if (endianMark == byteOrderII)
   1474 			{
   1475 			bigEndian = false;
   1476 			}
   1477 
   1478 		TempBigEndian temp_endian (stream, bigEndian);
   1479 
   1480 		ParseMakerNoteIFD (host,
   1481 						   stream,
   1482 						   fShared->fDNGPrivateDataCount - 10,
   1483 						   fShared->fDNGPrivateDataOffset + 10,
   1484 						   fShared->fDNGPrivateDataOffset,
   1485 						   fShared->fDNGPrivateDataOffset,
   1486 						   fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
   1487 						   tcPentaxMakerNote);
   1488 
   1489 		return;
   1490 
   1491 		}
   1492 
   1493 	// Stop parsing if this is not an Adobe format block.
   1494 
   1495 	if (!privateName.Matches ("Adobe"))
   1496 		{
   1497 		return;
   1498 		}
   1499 
   1500 	TempBigEndian temp_order (stream);
   1501 
   1502 	uint32 section_offset = 6;
   1503 
   1504 	while (SafeUint32Add(section_offset, 8) < fShared->fDNGPrivateDataCount)
   1505 		{
   1506 
   1507 		stream.SetReadPosition (SafeUint64Add(fShared->fDNGPrivateDataOffset,
   1508 												section_offset));
   1509 
   1510 		uint32 section_key   = stream.Get_uint32 ();
   1511 		uint32 section_count = stream.Get_uint32 ();
   1512 
   1513 		if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
   1514 			{
   1515 
   1516 			#if qDNGValidate
   1517 
   1518 			if (gVerbose)
   1519 				{
   1520 				printf ("Found MakerNote inside DNGPrivateData\n\n");
   1521 				}
   1522 
   1523 			#endif
   1524 
   1525 			uint16 order_mark = stream.Get_uint16 ();
   1526 			int64 old_offset = stream.Get_uint32 ();
   1527 
   1528 			uint32 tempSize = SafeUint32Sub(section_count, 6);
   1529 
   1530 			AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
   1531 
   1532 			uint64 positionInOriginalFile = stream.PositionInOriginalFile();
   1533 
   1534 			stream.Get (tempBlock->Buffer (), tempSize);
   1535 
   1536 			dng_stream tempStream (tempBlock->Buffer (),
   1537 								   tempSize,
   1538 								   positionInOriginalFile);
   1539 
   1540 			tempStream.SetBigEndian (order_mark == byteOrderMM);
   1541 
   1542 			ParseMakerNote (host,
   1543 							tempStream,
   1544 							tempSize,
   1545 							0,
   1546 							0 - old_offset,
   1547 							0,
   1548 							tempSize);
   1549 
   1550 			}
   1551 
   1552 		else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
   1553 			{
   1554 
   1555 			#if qDNGValidate
   1556 
   1557 			if (gVerbose)
   1558 				{
   1559 				printf ("Found Sony private data inside DNGPrivateData\n\n");
   1560 				}
   1561 
   1562 			#endif
   1563 
   1564 			uint16 order_mark = stream.Get_uint16 ();
   1565 			uint64 old_offset = stream.Get_uint32 ();
   1566 
   1567 			uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
   1568 
   1569 			TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
   1570 
   1571 			ParseSonyPrivateData (host,
   1572 							  	  stream,
   1573 								  section_count - 6,
   1574 								  old_offset,
   1575 								  new_offset);
   1576 
   1577 			}
   1578 
   1579 		else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
   1580 			{
   1581 
   1582 			#if qDNGValidate
   1583 
   1584 			if (gVerbose)
   1585 				{
   1586 				printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
   1587 				}
   1588 
   1589 			#endif
   1590 
   1591 			uint16 order_mark = stream.Get_uint16 ();
   1592 
   1593 			uint32 tagCount = stream.Get_uint32 ();
   1594 
   1595 			uint64 tagOffset = stream.Position ();
   1596 
   1597 			if (tagCount)
   1598 				{
   1599 
   1600 				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
   1601 
   1602 				ParseTag (host,
   1603 						  stream,
   1604 						  fExif.Get (),
   1605 						  fShared.Get (),
   1606 						  NULL,
   1607 						  tcFujiRAF,
   1608 						  tcFujiHeader,
   1609 						  ttUndefined,
   1610 						  tagCount,
   1611 						  tagOffset,
   1612 						  0);
   1613 
   1614 				stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
   1615 
   1616 				}
   1617 
   1618 			tagCount = stream.Get_uint32 ();
   1619 
   1620 			tagOffset = stream.Position ();
   1621 
   1622 			if (tagCount)
   1623 				{
   1624 
   1625 				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
   1626 
   1627 				ParseTag (host,
   1628 						  stream,
   1629 						  fExif.Get (),
   1630 						  fShared.Get (),
   1631 						  NULL,
   1632 						  tcFujiRAF,
   1633 						  tcFujiRawInfo1,
   1634 						  ttUndefined,
   1635 						  tagCount,
   1636 						  tagOffset,
   1637 						  0);
   1638 
   1639 				stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
   1640 
   1641 				}
   1642 
   1643 			tagCount = stream.Get_uint32 ();
   1644 
   1645 			tagOffset = stream.Position ();
   1646 
   1647 			if (tagCount)
   1648 				{
   1649 
   1650 				TempBigEndian raf_order (stream, order_mark == byteOrderMM);
   1651 
   1652 				ParseTag (host,
   1653 						  stream,
   1654 						  fExif.Get (),
   1655 						  fShared.Get (),
   1656 						  NULL,
   1657 						  tcFujiRAF,
   1658 						  tcFujiRawInfo2,
   1659 						  ttUndefined,
   1660 						  tagCount,
   1661 						  tagOffset,
   1662 						  0);
   1663 
   1664 				stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
   1665 
   1666 				}
   1667 
   1668 			}
   1669 
   1670 		else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
   1671 			{
   1672 
   1673 			#if qDNGValidate
   1674 
   1675 			if (gVerbose)
   1676 				{
   1677 				printf ("Found Contax Raw header inside DNGPrivateData\n\n");
   1678 				}
   1679 
   1680 			#endif
   1681 
   1682 			uint16 order_mark = stream.Get_uint16 ();
   1683 
   1684 			uint32 tagCount  = stream.Get_uint32 ();
   1685 
   1686 			uint64 tagOffset = stream.Position ();
   1687 
   1688 			if (tagCount)
   1689 				{
   1690 
   1691 				TempBigEndian contax_order (stream, order_mark == byteOrderMM);
   1692 
   1693 				ParseTag (host,
   1694 						  stream,
   1695 						  fExif.Get (),
   1696 						  fShared.Get (),
   1697 						  NULL,
   1698 						  tcContaxRAW,
   1699 						  tcContaxHeader,
   1700 						  ttUndefined,
   1701 						  tagCount,
   1702 						  tagOffset,
   1703 						  0);
   1704 
   1705 				}
   1706 
   1707 			}
   1708 
   1709 		else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
   1710 			{
   1711 
   1712 			#if qDNGValidate
   1713 
   1714 			if (gVerbose)
   1715 				{
   1716 				printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
   1717 				}
   1718 
   1719 			#endif
   1720 
   1721 			uint16 order_mark = stream.Get_uint16 ();
   1722 			uint32 entries    = stream.Get_uint16 ();
   1723 
   1724 			uint64 crwTagStart = stream.Position ();
   1725 
   1726 			for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
   1727 				{
   1728 
   1729 				stream.SetReadPosition (crwTagStart);
   1730 
   1731 				for (uint32 index = 0; index < entries; index++)
   1732 					{
   1733 
   1734 					uint32 tagCode = stream.Get_uint16 ();
   1735 
   1736 					uint32 tagCount = stream.Get_uint32 ();
   1737 
   1738 					uint64 tagOffset = stream.Position ();
   1739 
   1740 					// We need to grab the model id tag first, and then all the
   1741 					// other tags.
   1742 
   1743 					if ((parsePass == 1) == (tagCode == 0x5834))
   1744 						{
   1745 
   1746 						TempBigEndian tag_order (stream, order_mark == byteOrderMM);
   1747 
   1748 						ParseTag (host,
   1749 								  stream,
   1750 								  fExif.Get (),
   1751 								  fShared.Get (),
   1752 								  NULL,
   1753 								  tcCanonCRW,
   1754 								  tagCode,
   1755 								  ttUndefined,
   1756 								  tagCount,
   1757 								  tagOffset,
   1758 								  0);
   1759 
   1760 						}
   1761 
   1762 					stream.SetReadPosition (tagOffset + tagCount);
   1763 
   1764 					}
   1765 
   1766 				}
   1767 
   1768 			}
   1769 
   1770 		else if (section_count > 4)
   1771 			{
   1772 
   1773 			uint32 parentCode = 0;
   1774 
   1775 			bool code32  = false;
   1776 			bool hasType = true;
   1777 
   1778 			switch (section_key)
   1779 				{
   1780 
   1781 				case DNG_CHAR4 ('M','R','W',' '):
   1782 					{
   1783 					parentCode = tcMinoltaMRW;
   1784 					code32     = true;
   1785 					hasType    = false;
   1786 					break;
   1787 					}
   1788 
   1789 				case DNG_CHAR4 ('P','a','n','o'):
   1790 					{
   1791 					parentCode = tcPanasonicRAW;
   1792 					break;
   1793 					}
   1794 
   1795 				case DNG_CHAR4 ('L','e','a','f'):
   1796 					{
   1797 					parentCode = tcLeafMOS;
   1798 					break;
   1799 					}
   1800 
   1801 				case DNG_CHAR4 ('K','o','d','a'):
   1802 					{
   1803 					parentCode = tcKodakDCRPrivateIFD;
   1804 					break;
   1805 					}
   1806 
   1807 				case DNG_CHAR4 ('K','D','C',' '):
   1808 					{
   1809 					parentCode = tcKodakKDCPrivateIFD;
   1810 					break;
   1811 					}
   1812 
   1813 				default:
   1814 					break;
   1815 
   1816 				}
   1817 
   1818 			if (parentCode)
   1819 				{
   1820 
   1821 				#if qDNGValidate
   1822 
   1823 				if (gVerbose)
   1824 					{
   1825 					printf ("Found %s tags inside DNGPrivateData\n\n",
   1826 							LookupParentCode (parentCode));
   1827 					}
   1828 
   1829 				#endif
   1830 
   1831 				uint16 order_mark = stream.Get_uint16 ();
   1832 				uint32 entries    = stream.Get_uint16 ();
   1833 
   1834 				for (uint32 index = 0; index < entries; index++)
   1835 					{
   1836 
   1837 					uint32 tagCode = code32 ? stream.Get_uint32 ()
   1838 											: stream.Get_uint16 ();
   1839 
   1840 					uint32 tagType  = hasType ? stream.Get_uint16 ()
   1841 											  : ttUndefined;
   1842 
   1843 					uint32 tagCount = stream.Get_uint32 ();
   1844 
   1845 					uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
   1846 
   1847 					uint64 tagOffset = stream.Position ();
   1848 
   1849 					TempBigEndian tag_order (stream, order_mark == byteOrderMM);
   1850 
   1851 					ParseTag (host,
   1852 							  stream,
   1853 							  fExif.Get (),
   1854 							  fShared.Get (),
   1855 							  NULL,
   1856 							  parentCode,
   1857 							  tagCode,
   1858 							  tagType,
   1859 							  tagCount,
   1860 							  tagOffset,
   1861 							  0);
   1862 
   1863 					stream.SetReadPosition (SafeUint64Add(tagOffset, tagSize));
   1864 
   1865 					}
   1866 
   1867 				}
   1868 
   1869 			}
   1870 
   1871 		section_offset = SafeUint32Add(section_offset, 8);
   1872 		section_offset = SafeUint32Add(section_offset, section_count);
   1873 
   1874 		if (section_offset & 1)
   1875 			{
   1876 			section_offset = SafeUint32Add(section_offset, 1);
   1877 			}
   1878 
   1879 		}
   1880 
   1881 	}
   1882 
   1883 /*****************************************************************************/
   1884 
   1885 void dng_info::Parse (dng_host &host,
   1886 					  dng_stream &stream)
   1887 	{
   1888 
   1889 	fTIFFBlockOffset = stream.Position ();
   1890 
   1891 	fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
   1892 
   1893 	// Check byte order indicator.
   1894 
   1895 	uint16 byteOrder = stream.Get_uint16 ();
   1896 
   1897 	if (byteOrder == byteOrderII)
   1898 		{
   1899 
   1900 		fBigEndian = false;
   1901 
   1902 		#if qDNGValidate
   1903 
   1904 		if (gVerbose)
   1905 			{
   1906 			printf ("\nUses little-endian byte order\n");
   1907 			}
   1908 
   1909 		#endif
   1910 
   1911 		stream.SetLittleEndian ();
   1912 
   1913 		}
   1914 
   1915 	else if (byteOrder == byteOrderMM)
   1916 		{
   1917 
   1918 		fBigEndian = true;
   1919 
   1920 		#if qDNGValidate
   1921 
   1922 		if (gVerbose)
   1923 			{
   1924 			printf ("\nUses big-endian byte order\n");
   1925 			}
   1926 
   1927 		#endif
   1928 
   1929 		stream.SetBigEndian ();
   1930 
   1931 		}
   1932 
   1933 	else
   1934 		{
   1935 
   1936 		#if qDNGValidate
   1937 
   1938 		ReportError ("Unknown byte order");
   1939 
   1940 		#endif
   1941 
   1942 		ThrowBadFormat ();
   1943 
   1944 		}
   1945 
   1946 	// Check "magic number" indicator.
   1947 
   1948 	fMagic = stream.Get_uint16 ();
   1949 
   1950 	#if qDNGValidate
   1951 
   1952 	if (gVerbose)
   1953 		{
   1954 		printf ("Magic number = %u\n\n", (unsigned) fMagic);
   1955 		}
   1956 
   1957 	#endif
   1958 
   1959 	ValidateMagic ();
   1960 
   1961 	// Parse IFD 0.
   1962 
   1963 	uint64 next_offset = stream.Get_uint32 ();
   1964 
   1965 	fExif.Reset (host.Make_dng_exif ());
   1966 
   1967 	fShared.Reset (host.Make_dng_shared ());
   1968 
   1969 	fIFD [0].Reset (host.Make_dng_ifd ());
   1970 
   1971 	ParseIFD (host,
   1972 			  stream,
   1973 			  fExif.Get (),
   1974 			  fShared.Get (),
   1975 			  fIFD [0].Get (),
   1976 			  fTIFFBlockOffset + next_offset,
   1977 			  fTIFFBlockOffset,
   1978 			  0);
   1979 
   1980 	next_offset = fIFD [0]->fNextIFD;
   1981 
   1982 	fIFDCount = 1;
   1983 
   1984 	// Parse chained IFDs.
   1985 
   1986 	while (next_offset)
   1987 		{
   1988 
   1989 		if (next_offset >= stream.Length ())
   1990 			{
   1991 
   1992 			#if qDNGValidate
   1993 
   1994 				{
   1995 
   1996 				ReportWarning ("Chained IFD offset past end of stream");
   1997 
   1998 				}
   1999 
   2000 			#endif
   2001 
   2002 			break;
   2003 
   2004 			}
   2005 
   2006 		// Some TIFF file writers forget about the next IFD offset, so
   2007 		// validate the IFD at that offset before parsing it.
   2008 
   2009 		if (!ValidateIFD (stream,
   2010 						  fTIFFBlockOffset + next_offset,
   2011 						  fTIFFBlockOffset))
   2012 			{
   2013 
   2014 			#if qDNGValidate
   2015 
   2016 				{
   2017 
   2018 				ReportWarning ("Chained IFD is not valid");
   2019 
   2020 				}
   2021 
   2022 			#endif
   2023 
   2024 			break;
   2025 
   2026 			}
   2027 
   2028 		if (fChainedIFDCount == kMaxChainedIFDs)
   2029 			{
   2030 
   2031 			#if qDNGValidate
   2032 
   2033 				{
   2034 
   2035 				ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
   2036 
   2037 				}
   2038 
   2039 			#endif
   2040 
   2041 			break;
   2042 
   2043 			}
   2044 
   2045 		fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
   2046 
   2047 		ParseIFD (host,
   2048 				  stream,
   2049 				  NULL,
   2050 				  NULL,
   2051 				  fChainedIFD [fChainedIFDCount].Get (),
   2052 				  fTIFFBlockOffset + next_offset,
   2053 				  fTIFFBlockOffset,
   2054 				  tcFirstChainedIFD + fChainedIFDCount);
   2055 
   2056 		next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
   2057 
   2058 		fChainedIFDCount++;
   2059 
   2060 		}
   2061 
   2062 	// Parse SubIFDs.
   2063 
   2064 	uint32 searchedIFDs = 0;
   2065 
   2066 	bool tooManySubIFDs = false;
   2067 
   2068 	while (searchedIFDs < fIFDCount && !tooManySubIFDs)
   2069 		{
   2070 
   2071 		uint32 searchLimit = fIFDCount;
   2072 
   2073 		for (uint32 searchIndex = searchedIFDs;
   2074 			 searchIndex < searchLimit && !tooManySubIFDs;
   2075 			 searchIndex++)
   2076 			{
   2077 
   2078 			for (uint32 subIndex = 0;
   2079 			     subIndex < fIFD [searchIndex]->fSubIFDsCount;
   2080 			     subIndex++)
   2081 				{
   2082 
   2083 				if (fIFDCount == kMaxSubIFDs + 1)
   2084 					{
   2085 
   2086 					tooManySubIFDs = true;
   2087 
   2088 					break;
   2089 
   2090 					}
   2091 
   2092 				stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
   2093 							 			subIndex * 4);
   2094 
   2095 				uint32 sub_ifd_offset = stream.Get_uint32 ();
   2096 
   2097 				fIFD [fIFDCount].Reset (host.Make_dng_ifd ());
   2098 
   2099 				ParseIFD (host,
   2100 						  stream,
   2101 						  fExif.Get (),
   2102 						  fShared.Get (),
   2103 						  fIFD [fIFDCount].Get (),
   2104 						  fTIFFBlockOffset + sub_ifd_offset,
   2105 						  fTIFFBlockOffset,
   2106 						  tcFirstSubIFD + fIFDCount - 1);
   2107 
   2108 				fIFDCount++;
   2109 
   2110 				}
   2111 
   2112 			searchedIFDs = searchLimit;
   2113 
   2114 			}
   2115 
   2116 		}
   2117 
   2118 	#if qDNGValidate
   2119 
   2120 		{
   2121 
   2122 		if (tooManySubIFDs)
   2123 			{
   2124 
   2125 			ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
   2126 
   2127 			}
   2128 
   2129 		}
   2130 
   2131 	#endif
   2132 
   2133 	// Parse EXIF IFD.
   2134 
   2135 	if (fShared->fExifIFD)
   2136 		{
   2137 
   2138 		ParseIFD (host,
   2139 				  stream,
   2140 				  fExif.Get (),
   2141 				  fShared.Get (),
   2142 				  NULL,
   2143 				  fTIFFBlockOffset + fShared->fExifIFD,
   2144 				  fTIFFBlockOffset,
   2145 				  tcExifIFD);
   2146 
   2147 		}
   2148 
   2149 	// Parse GPS IFD.
   2150 
   2151 	if (fShared->fGPSInfo)
   2152 		{
   2153 
   2154 		ParseIFD (host,
   2155 				  stream,
   2156 				  fExif.Get (),
   2157 				  fShared.Get (),
   2158 				  NULL,
   2159 				  fTIFFBlockOffset + fShared->fGPSInfo,
   2160 				  fTIFFBlockOffset,
   2161 				  tcGPSInfo);
   2162 
   2163 		}
   2164 
   2165 	// Parse Interoperability IFD.
   2166 
   2167 	if (fShared->fInteroperabilityIFD)
   2168 		{
   2169 
   2170 		// Some Kodak KDC files have bogus Interoperability IFDs, so
   2171 		// validate the IFD before trying to parse it.
   2172 
   2173 		if (ValidateIFD (stream,
   2174 						 fTIFFBlockOffset + fShared->fInteroperabilityIFD,
   2175 						 fTIFFBlockOffset))
   2176 			{
   2177 
   2178 			ParseIFD (host,
   2179 					  stream,
   2180 					  fExif.Get (),
   2181 					  fShared.Get (),
   2182 					  NULL,
   2183 					  fTIFFBlockOffset + fShared->fInteroperabilityIFD,
   2184 					  fTIFFBlockOffset,
   2185 					  tcInteroperabilityIFD);
   2186 
   2187 			}
   2188 
   2189 		#if qDNGValidate
   2190 
   2191 		else
   2192 			{
   2193 
   2194 			ReportWarning ("The Interoperability IFD is not a valid IFD");
   2195 
   2196 			}
   2197 
   2198 		#endif
   2199 
   2200 		}
   2201 
   2202 	// Parse Kodak DCR Private IFD.
   2203 
   2204 	if (fShared->fKodakDCRPrivateIFD)
   2205 		{
   2206 
   2207 		ParseIFD (host,
   2208 				  stream,
   2209 				  fExif.Get (),
   2210 				  fShared.Get (),
   2211 				  NULL,
   2212 				  fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
   2213 				  fTIFFBlockOffset,
   2214 				  tcKodakDCRPrivateIFD);
   2215 
   2216 		}
   2217 
   2218 	// Parse Kodak KDC Private IFD.
   2219 
   2220 	if (fShared->fKodakKDCPrivateIFD)
   2221 		{
   2222 
   2223 		ParseIFD (host,
   2224 				  stream,
   2225 				  fExif.Get (),
   2226 				  fShared.Get (),
   2227 				  NULL,
   2228 				  fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
   2229 				  fTIFFBlockOffset,
   2230 				  tcKodakKDCPrivateIFD);
   2231 
   2232 		}
   2233 
   2234 	// Parse MakerNote tag.
   2235 
   2236 	if (fShared->fMakerNoteCount)
   2237 		{
   2238 
   2239 		ParseMakerNote (host,
   2240 						stream,
   2241 						(uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
   2242 						fShared->fMakerNoteOffset,
   2243 						fTIFFBlockOffset,
   2244 						0,
   2245 						stream.Length ());
   2246 
   2247 		}
   2248 
   2249 	// Parse DNGPrivateData tag.
   2250 
   2251 	if (fShared->fDNGPrivateDataCount &&
   2252 		fShared->fDNGVersion)
   2253 		{
   2254 
   2255 		ParseDNGPrivateData (host, stream);
   2256 
   2257 		}
   2258 
   2259 	#if qDNGValidate
   2260 
   2261 	// If we are running dng_validate on stand-alone camera profile file,
   2262 	// complete the validation of the profile.
   2263 
   2264 	if (fMagic == magicExtendedProfile)
   2265 		{
   2266 
   2267 		dng_camera_profile_info &profileInfo = fShared->fCameraProfile;
   2268 
   2269 		dng_camera_profile profile;
   2270 
   2271 		profile.Parse (stream, profileInfo);
   2272 
   2273 		if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes))
   2274 			{
   2275 
   2276 			ReportError ("Invalid camera profile file");
   2277 
   2278 			}
   2279 
   2280 		}
   2281 
   2282 	#endif
   2283 
   2284 	}
   2285 
   2286 /*****************************************************************************/
   2287 
   2288 void dng_info::PostParse (dng_host &host)
   2289 	{
   2290 
   2291 	uint32 index;
   2292 
   2293 	fExif->PostParse (host, *fShared.Get ());
   2294 
   2295 	fShared->PostParse (host, *fExif.Get ());
   2296 
   2297 	for (index = 0; index < fIFDCount; index++)
   2298 		{
   2299 
   2300 		fIFD [index]->PostParse ();
   2301 
   2302 		}
   2303 
   2304 	for (index = 0; index < fChainedIFDCount; index++)
   2305 		{
   2306 
   2307 		fChainedIFD [index]->PostParse ();
   2308 
   2309 		}
   2310 
   2311 	if (fShared->fDNGVersion != 0)
   2312 		{
   2313 
   2314 		// Find main IFD.
   2315 
   2316 		fMainIndex = -1;
   2317 
   2318 		for (index = 0; index < fIFDCount; index++)
   2319 			{
   2320 
   2321 			if (fIFD [index]->fUsesNewSubFileType &&
   2322 				fIFD [index]->fNewSubFileType == sfMainImage)
   2323 				{
   2324 
   2325 				if (fMainIndex == -1)
   2326 					{
   2327 
   2328 					fMainIndex = index;
   2329 
   2330 					}
   2331 
   2332 				#if qDNGValidate
   2333 
   2334 				else
   2335 					{
   2336 
   2337 					ReportError ("Multiple IFDs marked as main image");
   2338 
   2339 					}
   2340 
   2341 				#endif
   2342 
   2343 				}
   2344 
   2345 			else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
   2346 					 fIFD [index]->fNewSubFileType == sfAltPreviewImage)
   2347 				{
   2348 
   2349 				// Fill in default color space for DNG previews if not included.
   2350 
   2351 				if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
   2352 					{
   2353 
   2354 					if (fIFD [index]->fSamplesPerPixel == 1)
   2355 						{
   2356 
   2357 						fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
   2358 
   2359 						}
   2360 
   2361 					else
   2362 						{
   2363 
   2364 						fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
   2365 
   2366 						}
   2367 
   2368 					}
   2369 
   2370 				}
   2371 
   2372 			}
   2373 
   2374 		// Deal with lossless JPEG bug in early DNG versions.
   2375 
   2376 		if (fShared->fDNGVersion < dngVersion_1_1_0_0)
   2377 			{
   2378 
   2379 			if (fMainIndex != -1)
   2380 				{
   2381 
   2382 				fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
   2383 
   2384 				}
   2385 
   2386 			}
   2387 
   2388 		// Find mask index.
   2389 
   2390 		for (index = 0; index < fIFDCount; index++)
   2391 			{
   2392 
   2393 			if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
   2394 				{
   2395 
   2396 				if (fMaskIndex == -1)
   2397 					{
   2398 
   2399 					fMaskIndex = index;
   2400 
   2401 					}
   2402 
   2403 				#if qDNGValidate
   2404 
   2405 				else
   2406 					{
   2407 
   2408 					ReportError ("Multiple IFDs marked as transparency mask image");
   2409 
   2410 					}
   2411 
   2412 				#endif
   2413 
   2414 				}
   2415 
   2416 			}
   2417 
   2418 		// Warn about Chained IFDs.
   2419 
   2420 		#if qDNGValidate
   2421 
   2422 		if (fChainedIFDCount > 0)
   2423 			{
   2424 
   2425 			ReportWarning ("This file has Chained IFDs, which will be ignored by DNG readers");
   2426 
   2427 			}
   2428 
   2429 		#endif
   2430 
   2431 		}
   2432 
   2433 	}
   2434 
   2435 /*****************************************************************************/
   2436 
   2437 bool dng_info::IsValidDNG ()
   2438 	{
   2439 
   2440 	// Check shared info.
   2441 
   2442 	if (!fShared->IsValidDNG ())
   2443 		{
   2444 
   2445 		return false;
   2446 
   2447 		}
   2448 
   2449 	// Check TIFF magic number.
   2450 
   2451 	if (fMagic != 42)
   2452 		{
   2453 
   2454 		#if qDNGValidate
   2455 
   2456 		ReportError ("Invalid TIFF magic number");
   2457 
   2458 		#endif
   2459 
   2460 		return false;
   2461 
   2462 		}
   2463 
   2464 	// Make sure we have a main image IFD.
   2465 
   2466 	if (fMainIndex == -1)
   2467 		{
   2468 
   2469 		#if qDNGValidate
   2470 
   2471 		ReportError ("Unable to find main image IFD");
   2472 
   2473 		#endif
   2474 
   2475 		return false;
   2476 
   2477 		}
   2478 
   2479 	// Make sure is each IFD is valid.
   2480 
   2481 	for (uint32 index = 0; index < fIFDCount; index++)
   2482 		{
   2483 
   2484 		uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
   2485 
   2486 		if (!fIFD [index]->IsValidDNG (*fShared.Get (),
   2487 								       parentCode))
   2488 			{
   2489 
   2490 			// Only errors in the main and transparency mask IFDs are fatal to parsing.
   2491 
   2492 			if (index == (uint32) fMainIndex ||
   2493 				index == (uint32) fMaskIndex)
   2494 				{
   2495 
   2496 				return false;
   2497 
   2498 				}
   2499 
   2500 			}
   2501 
   2502 		}
   2503 
   2504 	return true;
   2505 
   2506 	}
   2507 
   2508 /*****************************************************************************/
   2509