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 
dng_info()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 
~dng_info()51 dng_info::~dng_info ()
52 	{
53 
54 	}
55 
56 /*****************************************************************************/
57 
ValidateMagic()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 
ParseTag(dng_host & host,dng_stream & stream,dng_exif * exif,dng_shared * shared,dng_ifd * ifd,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset,int64 offsetDelta)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 
ValidateIFD(dng_stream & stream,uint64 ifdOffset,int64 offsetDelta)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 
ParseIFD(dng_host & host,dng_stream & stream,dng_exif * exif,dng_shared * shared,dng_ifd * ifd,uint64 ifdOffset,int64 offsetDelta,uint32 parentCode)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 
ParseMakerNoteIFD(dng_host & host,dng_stream & stream,uint64 ifdSize,uint64 ifdOffset,int64 offsetDelta,uint64 minOffset,uint64 maxOffset,uint32 parentCode)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 
ParseMakerNote(dng_host & host,dng_stream & stream,uint32 makerNoteCount,uint64 makerNoteOffset,int64 offsetDelta,uint64 minOffset,uint64 maxOffset)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 
ParseSonyPrivateData(dng_host &,dng_stream &,uint64,uint64,uint64)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 
ParseDNGPrivateData(dng_host & host,dng_stream & stream)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 
Parse(dng_host & host,dng_stream & stream)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 
PostParse(dng_host & host)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 
IsValidDNG()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