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
31dng_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
51dng_info::~dng_info ()
52	{
53
54	}
55
56/*****************************************************************************/
57
58void 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
95void 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
338bool 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
411void 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
656bool 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
887void 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
1403void 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
1416void 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
1885void 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
2288void 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
2437bool 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