1 /*****************************************************************************/
2 // Copyright 2006-2008 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_2/dng_sdk/source/dng_shared.cpp#2 $ */
10 /* $DateTime: 2008/04/02 14:06:57 $ */
11 /* $Change: 440485 $ */
12 /* $Author: tknoll $ */
13 
14 /*****************************************************************************/
15 
16 #include "dng_shared.h"
17 
18 #include "dng_camera_profile.h"
19 #include "dng_exceptions.h"
20 #include "dng_globals.h"
21 #include "dng_parse_utils.h"
22 #include "dng_tag_codes.h"
23 #include "dng_tag_types.h"
24 #include "dng_tag_values.h"
25 #include "dng_utils.h"
26 
27 /*****************************************************************************/
28 
dng_camera_profile_info()29 dng_camera_profile_info::dng_camera_profile_info ()
30 
31 	:	fBigEndian (false)
32 
33 	,	fColorPlanes (0)
34 
35 	,	fCalibrationIlluminant1 (lsUnknown)
36 	,	fCalibrationIlluminant2 (lsUnknown)
37 
38 	,	fColorMatrix1 ()
39 	,	fColorMatrix2 ()
40 
41 	,	fForwardMatrix1 ()
42 	,	fForwardMatrix2 ()
43 
44 	,	fReductionMatrix1 ()
45 	,	fReductionMatrix2 ()
46 
47 	,	fProfileCalibrationSignature ()
48 
49 	,	fProfileName ()
50 
51 	,	fProfileCopyright ()
52 
53 	,	fEmbedPolicy (pepAllowCopying)
54 
55 	,	fProfileHues (0)
56 	,	fProfileSats (0)
57 	,	fProfileVals (0)
58 
59 	,	fHueSatDeltas1Offset (0)
60 	,	fHueSatDeltas1Count  (0)
61 
62 	,	fHueSatDeltas2Offset (0)
63 	,	fHueSatDeltas2Count  (0)
64 
65 	,	fLookTableHues (0)
66 	,	fLookTableSats (0)
67 	,	fLookTableVals (0)
68 
69 	,	fLookTableOffset (0)
70 	,	fLookTableCount  (0)
71 
72 	,	fToneCurveOffset     (0)
73 	,	fToneCurveCount      (0)
74 
75 	,	fUniqueCameraModel ()
76 
77 	{
78 
79 	}
80 
81 /*****************************************************************************/
82 
~dng_camera_profile_info()83 dng_camera_profile_info::~dng_camera_profile_info ()
84 	{
85 
86 	}
87 
88 /*****************************************************************************/
89 
ParseTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)90 bool dng_camera_profile_info::ParseTag (dng_stream &stream,
91 										uint32 parentCode,
92 										uint32 tagCode,
93 										uint32 tagType,
94 										uint32 tagCount,
95 										uint64 tagOffset)
96 	{
97 
98 	switch (tagCode)
99 		{
100 
101 		case tcCalibrationIlluminant1:
102 			{
103 
104 			CheckTagType (parentCode, tagCode, tagType, ttShort);
105 
106 			CheckTagCount (parentCode, tagCode, tagCount, 1);
107 
108 			fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType);
109 
110 			#if qDNGValidate
111 
112 			if (gVerbose)
113 				{
114 
115 				printf ("CalibrationIlluminant1: %s\n",
116 						LookupLightSource (fCalibrationIlluminant1));
117 
118 				}
119 
120 			#endif
121 
122 			break;
123 
124 			}
125 
126 		case tcCalibrationIlluminant2:
127 			{
128 
129 			CheckTagType (parentCode, tagCode, tagType, ttShort);
130 
131 			CheckTagCount (parentCode, tagCode, tagCount, 1);
132 
133 			fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType);
134 
135 			#if qDNGValidate
136 
137 			if (gVerbose)
138 				{
139 
140 				printf ("CalibrationIlluminant2: %s\n",
141 						LookupLightSource (fCalibrationIlluminant2));
142 
143 				}
144 
145 			#endif
146 
147 			break;
148 
149 			}
150 
151 		case tcColorMatrix1:
152 			{
153 
154 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
155 
156 			if (fColorPlanes == 0)
157 				{
158 
159 				fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
160 
161 				}
162 
163 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
164 				return false;
165 
166 			if (!ParseMatrixTag (stream,
167 								 parentCode,
168 								 tagCode,
169 								 tagType,
170 								 tagCount,
171 								 fColorPlanes,
172 								 3,
173 								 fColorMatrix1))
174 				return false;
175 
176 			#if qDNGValidate
177 
178 			if (gVerbose)
179 				{
180 
181 				printf ("ColorMatrix1:\n");
182 
183 				DumpMatrix (fColorMatrix1);
184 
185 				}
186 
187 			#endif
188 
189 			break;
190 
191 			}
192 
193 		case tcColorMatrix2:
194 			{
195 
196 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
197 
198 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
199 				return false;
200 
201 			if (!ParseMatrixTag (stream,
202 								 parentCode,
203 								 tagCode,
204 								 tagType,
205 								 tagCount,
206 								 fColorPlanes,
207 								 3,
208 								 fColorMatrix2))
209 				return false;
210 
211 			#if qDNGValidate
212 
213 			if (gVerbose)
214 				{
215 
216 				printf ("ColorMatrix2:\n");
217 
218 				DumpMatrix (fColorMatrix2);
219 
220 				}
221 
222 			#endif
223 
224 			break;
225 
226 			}
227 
228 		case tcForwardMatrix1:
229 			{
230 
231 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
232 
233 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
234 				return false;
235 
236 			if (!ParseMatrixTag (stream,
237 								 parentCode,
238 								 tagCode,
239 								 tagType,
240 								 tagCount,
241 								 3,
242 								 fColorPlanes,
243 								 fForwardMatrix1))
244 				return false;
245 
246 			#if qDNGValidate
247 
248 			if (gVerbose)
249 				{
250 
251 				printf ("ForwardMatrix1:\n");
252 
253 				DumpMatrix (fForwardMatrix1);
254 
255 				}
256 
257 			#endif
258 
259 			break;
260 
261 			}
262 
263 		case tcForwardMatrix2:
264 			{
265 
266 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
267 
268 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
269 				return false;
270 
271 			if (!ParseMatrixTag (stream,
272 								 parentCode,
273 								 tagCode,
274 								 tagType,
275 								 tagCount,
276 								 3,
277 								 fColorPlanes,
278 								 fForwardMatrix2))
279 				return false;
280 
281 			#if qDNGValidate
282 
283 			if (gVerbose)
284 				{
285 
286 				printf ("ForwardMatrix2:\n");
287 
288 				DumpMatrix (fForwardMatrix2);
289 
290 				}
291 
292 			#endif
293 
294 			break;
295 
296 			}
297 
298 		case tcReductionMatrix1:
299 			{
300 
301 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
302 
303 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
304 				return false;
305 
306 			if (!ParseMatrixTag (stream,
307 								 parentCode,
308 								 tagCode,
309 								 tagType,
310 								 tagCount,
311 								 3,
312 								 fColorPlanes,
313 								 fReductionMatrix1))
314 				return false;
315 
316 			#if qDNGValidate
317 
318 			if (gVerbose)
319 				{
320 
321 				printf ("ReductionMatrix1:\n");
322 
323 				DumpMatrix (fReductionMatrix1);
324 
325 				}
326 
327 			#endif
328 
329 			break;
330 
331 			}
332 
333 		case tcReductionMatrix2:
334 			{
335 
336 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
337 
338 			if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
339 				return false;
340 
341 			if (!ParseMatrixTag (stream,
342 								 parentCode,
343 								 tagCode,
344 								 tagType,
345 								 tagCount,
346 								 3,
347 								 fColorPlanes,
348 								 fReductionMatrix2))
349 				return false;
350 
351 			#if qDNGValidate
352 
353 			if (gVerbose)
354 				{
355 
356 				printf ("ReductionMatrix2:\n");
357 
358 				DumpMatrix (fReductionMatrix2);
359 
360 				}
361 
362 			#endif
363 
364 			break;
365 
366 			}
367 
368 		case tcProfileCalibrationSignature:
369 			{
370 
371 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
372 
373 			ParseStringTag (stream,
374 							parentCode,
375 							tagCode,
376 							tagCount,
377 							fProfileCalibrationSignature,
378 							false,
379 							false);
380 
381 			#if qDNGValidate
382 
383 			if (gVerbose)
384 				{
385 
386 				printf ("ProfileCalibrationSignature: ");
387 
388 				DumpString (fProfileCalibrationSignature);
389 
390 				printf ("\n");
391 
392 				}
393 
394 			#endif
395 
396 			break;
397 
398 			}
399 
400 		case tcProfileName:
401 			{
402 
403 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
404 
405 			ParseStringTag (stream,
406 							parentCode,
407 							tagCode,
408 							tagCount,
409 							fProfileName,
410 							false,
411 							false);
412 
413 			#if qDNGValidate
414 
415 			if (gVerbose)
416 				{
417 
418 				printf ("ProfileName: ");
419 
420 				DumpString (fProfileName);
421 
422 				printf ("\n");
423 
424 				}
425 
426 			#endif
427 
428 			break;
429 
430 			}
431 
432 		case tcProfileCopyright:
433 			{
434 
435 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
436 
437 			ParseStringTag (stream,
438 							parentCode,
439 							tagCode,
440 							tagCount,
441 							fProfileCopyright,
442 							false,
443 							false);
444 
445 			#if qDNGValidate
446 
447 			if (gVerbose)
448 				{
449 
450 				printf ("ProfileCopyright: ");
451 
452 				DumpString (fProfileCopyright);
453 
454 				printf ("\n");
455 
456 				}
457 
458 			#endif
459 
460 			break;
461 
462 			}
463 
464 		case tcProfileEmbedPolicy:
465 			{
466 
467 			CheckTagType (parentCode, tagCode, tagType, ttLong);
468 
469 			CheckTagCount (parentCode, tagCode, tagCount, 1);
470 
471 			fEmbedPolicy = stream.TagValue_uint32 (tagType);
472 
473 			#if qDNGValidate
474 
475 			if (gVerbose)
476 				{
477 
478 				const char *policy;
479 
480 				switch (fEmbedPolicy)
481 					{
482 
483 					case pepAllowCopying:
484 						policy = "Allow copying";
485 						break;
486 
487 					case pepEmbedIfUsed:
488 						policy = "Embed if used";
489 						break;
490 
491 					case pepEmbedNever:
492 						policy = "Embed never";
493 						break;
494 
495 					case pepNoRestrictions:
496 						policy = "No restrictions";
497 						break;
498 
499 					default:
500 						policy = "INVALID VALUE";
501 
502 					}
503 
504 				printf ("ProfileEmbedPolicy: %s\n", policy);
505 
506 				}
507 
508 			#endif
509 
510 			break;
511 
512 			}
513 
514 		case tcProfileHueSatMapDims:
515 			{
516 
517 			CheckTagType (parentCode, tagCode, tagType, ttLong);
518 
519 			CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
520 
521 			fProfileHues = stream.TagValue_uint32 (tagType);
522 			fProfileSats = stream.TagValue_uint32 (tagType);
523 
524 			if (tagCount > 2)
525 				fProfileVals = stream.TagValue_uint32 (tagType);
526 			else
527 				fProfileVals = 1;
528 
529 			#if qDNGValidate
530 
531 			if (gVerbose)
532 				{
533 
534 				printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n",
535 						(unsigned) fProfileHues,
536 						(unsigned) fProfileSats,
537 						(unsigned) fProfileVals);
538 
539 				}
540 
541 			#endif
542 
543 			break;
544 
545 			}
546 
547 		case tcProfileHueSatMapData1:
548 			{
549 
550 			if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
551 				return false;
552 
553 			bool skipSat0 = (tagCount == fProfileHues *
554 										(fProfileSats - 1) *
555 										 fProfileVals * 3);
556 
557 			if (!skipSat0)
558 				{
559 
560 				if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
561 																   fProfileSats *
562 																   fProfileVals * 3))
563 					return false;
564 
565 				}
566 
567 			fBigEndian = stream.BigEndian ();
568 
569 			fHueSatDeltas1Offset = tagOffset;
570 			fHueSatDeltas1Count  = tagCount;
571 
572 			#if qDNGValidate
573 
574 			if (gVerbose)
575 				{
576 
577 				printf ("ProfileHueSatMapData1:\n");
578 
579 				DumpHueSatMap (stream,
580 							   fProfileHues,
581 							   fProfileSats,
582 							   fProfileVals,
583 							   skipSat0);
584 
585 				}
586 
587 			#endif
588 
589 			break;
590 
591 			}
592 
593 		case tcProfileHueSatMapData2:
594 			{
595 
596 			if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
597 				return false;
598 
599 			bool skipSat0 = (tagCount == fProfileHues *
600 										(fProfileSats - 1) *
601 										 fProfileVals * 3);
602 
603 			if (!skipSat0)
604 				{
605 
606 				if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
607 																   fProfileSats *
608 																   fProfileVals * 3))
609 					return false;
610 
611 				}
612 
613 			fBigEndian = stream.BigEndian ();
614 
615 			fHueSatDeltas2Offset = tagOffset;
616 			fHueSatDeltas2Count  = tagCount;
617 
618 			#if qDNGValidate
619 
620 			if (gVerbose)
621 				{
622 
623 				printf ("ProfileHueSatMapData2:\n");
624 
625 				DumpHueSatMap (stream,
626 							   fProfileHues,
627 							   fProfileSats,
628 							   fProfileVals,
629 							   skipSat0);
630 
631 				}
632 
633 			#endif
634 
635 			break;
636 
637 			}
638 
639 		case tcProfileLookTableDims:
640 			{
641 
642 			CheckTagType (parentCode, tagCode, tagType, ttLong);
643 
644 			CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
645 
646 			fLookTableHues = stream.TagValue_uint32 (tagType);
647 			fLookTableSats = stream.TagValue_uint32 (tagType);
648 
649 			if (tagCount > 2)
650 				fLookTableVals = stream.TagValue_uint32 (tagType);
651 			else
652 				fLookTableVals = 1;
653 
654 			#if qDNGValidate
655 
656 			if (gVerbose)
657 				{
658 
659 				printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n",
660 						(unsigned) fLookTableHues,
661 						(unsigned) fLookTableSats,
662 						(unsigned) fLookTableVals);
663 
664 				}
665 
666 			#endif
667 
668 			break;
669 
670 			}
671 
672 		case tcProfileLookTableData:
673 			{
674 
675 			if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
676 				return false;
677 
678 			bool skipSat0 = (tagCount == fLookTableHues *
679 										(fLookTableSats - 1) *
680 										 fLookTableVals * 3);
681 
682 			if (!skipSat0)
683 				{
684 
685 				if (!CheckTagCount (parentCode, tagCode, tagCount, fLookTableHues *
686 																   fLookTableSats *
687 																   fLookTableVals * 3))
688 					return false;
689 
690 				}
691 
692 			fBigEndian = stream.BigEndian ();
693 
694 			fLookTableOffset = tagOffset;
695 			fLookTableCount  = tagCount;
696 
697 			#if qDNGValidate
698 
699 			if (gVerbose)
700 				{
701 
702 				printf ("ProfileLookTableData:\n");
703 
704 				DumpHueSatMap (stream,
705 							   fLookTableHues,
706 							   fLookTableSats,
707 							   fLookTableVals,
708 							   skipSat0);
709 
710 				}
711 
712 			#endif
713 
714 			break;
715 
716 			}
717 
718 		case tcProfileToneCurve:
719 			{
720 
721 			if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
722 				return false;
723 
724 			if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
725 				return false;
726 
727 			if ((tagCount & 1) != 0)
728 				{
729 
730 				#if qDNGValidate
731 
732 					{
733 
734 					char message [256];
735 
736 					sprintf (message,
737 							 "%s %s has odd count (%u)",
738 							 LookupParentCode (parentCode),
739 							 LookupTagCode (parentCode, tagCode),
740 							 (unsigned) tagCount);
741 
742 					ReportWarning (message);
743 
744 					}
745 
746 				#endif
747 
748 				return false;
749 
750 				}
751 
752 			fBigEndian = stream.BigEndian ();
753 
754 			fToneCurveOffset = tagOffset;
755 			fToneCurveCount  = tagCount;
756 
757 			#if qDNGValidate
758 
759 			if (gVerbose)
760 				{
761 
762 				DumpTagValues (stream,
763 							   "Coord",
764 							   parentCode,
765 							   tagCode,
766 							   tagType,
767 							   tagCount);
768 
769 
770 				}
771 
772 			#endif
773 
774 			break;
775 
776 			}
777 
778 		case tcUniqueCameraModel:
779 			{
780 
781 			// Note: This code is only used when parsing stand-alone
782 			// profiles.  The embedded profiles are assumed to be restricted
783 			// to the model they are embedded in.
784 
785 			CheckTagType (parentCode, tagCode, tagType, ttAscii);
786 
787 			ParseStringTag (stream,
788 							parentCode,
789 							tagCode,
790 							tagCount,
791 							fUniqueCameraModel,
792 							false);
793 
794 			bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
795 
796 			#if qDNGValidate
797 
798 			if (didTrim)
799 				{
800 
801 				ReportWarning ("UniqueCameraModel string has trailing blanks");
802 
803 				}
804 
805 			if (gVerbose)
806 				{
807 
808 				printf ("UniqueCameraModel: ");
809 
810 				DumpString (fUniqueCameraModel);
811 
812 				printf ("\n");
813 
814 				}
815 
816 			#else
817 
818 			(void) didTrim;		// Unused
819 
820 			#endif
821 
822 			break;
823 
824 			}
825 
826 		default:
827 			{
828 
829 			return false;
830 
831 			}
832 
833 		}
834 
835 	return true;
836 
837 	}
838 
839 /*****************************************************************************/
840 
ParseExtended(dng_stream & stream)841 bool dng_camera_profile_info::ParseExtended (dng_stream &stream)
842 	{
843 
844 	try
845 		{
846 
847 		// Offsets are relative to the start of this structure, not the entire file.
848 
849 		uint64 startPosition = stream.Position ();
850 
851 		// Read header. Like a TIFF header, but with different magic number
852 		// Plus all offsets are relative to the start of the IFD, not to the
853 		// stream or file.
854 
855 		uint16 byteOrder = stream.Get_uint16 ();
856 
857 		if (byteOrder == byteOrderMM)
858 			fBigEndian = true;
859 
860 		else if (byteOrder == byteOrderII)
861 			fBigEndian = false;
862 
863 		else
864 			return false;
865 
866 		TempBigEndian setEndianness (stream, fBigEndian);
867 
868 		uint16 magicNumber = stream.Get_uint16 ();
869 
870 		if (magicNumber != magicExtendedProfile)
871 			{
872 			return false;
873 			}
874 
875 		uint32 offset = stream.Get_uint32 ();
876 
877 		stream.Skip (offset - 8);
878 
879 		// Start on IFD entries.
880 
881 		uint32 ifdEntries = stream.Get_uint16 ();
882 
883 		if (ifdEntries < 1)
884 			{
885 			return false;
886 			}
887 
888 		for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
889 			{
890 
891 			stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12);
892 
893 			uint16 tagCode  = stream.Get_uint16 ();
894 			uint32 tagType  = stream.Get_uint16 ();
895 			uint32 tagCount = stream.Get_uint32 ();
896 
897 			uint64 tagOffset = stream.Position ();
898 
899 			if (TagTypeSize (tagType) * tagCount > 4)
900 				{
901 
902 				tagOffset = startPosition + stream.Get_uint32 ();
903 
904 				stream.SetReadPosition (tagOffset);
905 
906 				}
907 
908 			if (!ParseTag (stream,
909 						   0,
910 						   tagCode,
911 						   tagType,
912 						   tagCount,
913 						   tagOffset))
914 				{
915 
916 				#if qDNGValidate
917 
918 				if (gVerbose)
919 					{
920 
921 					stream.SetReadPosition (tagOffset);
922 
923 					printf ("*");
924 
925 					DumpTagValues (stream,
926 								   LookupTagType (tagType),
927 								   0,
928 								   tagCode,
929 								   tagType,
930 								   tagCount);
931 
932 					}
933 
934 				#endif
935 
936 				}
937 
938 			}
939 
940 		return true;
941 
942 		}
943 
944 	catch (...)
945 		{
946 
947 		// Eat parsing errors.
948 
949 		}
950 
951 	return false;
952 
953 	}
954 
955 /*****************************************************************************/
956 
dng_shared()957 dng_shared::dng_shared ()
958 
959 	:	fExifIFD 			 (0)
960 	,	fGPSInfo 			 (0)
961 	,	fInteroperabilityIFD (0)
962 	,	fKodakDCRPrivateIFD  (0)
963 	,	fKodakKDCPrivateIFD  (0)
964 
965 	,	fXMPCount  (0)
966 	,	fXMPOffset (0)
967 
968 	,	fIPTC_NAA_Count  (0)
969 	,	fIPTC_NAA_Offset (0)
970 
971 	,	fMakerNoteCount  (0)
972 	,	fMakerNoteOffset (0)
973 	,	fMakerNoteSafety (0)
974 
975 	,	fDNGVersion         (0)
976 	,	fDNGBackwardVersion (0)
977 
978 	,	fUniqueCameraModel    ()
979 	,	fLocalizedCameraModel ()
980 
981 	,	fCameraProfile ()
982 
983 	,	fExtraCameraProfiles ()
984 
985 	,	fCameraCalibration1 ()
986 	,	fCameraCalibration2 ()
987 
988 	,	fCameraCalibrationSignature  ()
989 
990 	,	fAnalogBalance ()
991 
992 	,	fAsShotNeutral ()
993 
994 	,	fAsShotWhiteXY ()
995 
996 	,	fBaselineExposure      (0, 1)
997 	,	fBaselineNoise         (1, 1)
998 	,	fNoiseReductionApplied (0, 0)
999 	,	fBaselineSharpness     (1, 1)
1000 	,	fLinearResponseLimit   (1, 1)
1001 	,	fShadowScale           (1, 1)
1002 
1003 	,	fDNGPrivateDataCount  (0)
1004 	,	fDNGPrivateDataOffset (0)
1005 
1006 	,	fRawImageDigest ()
1007 
1008 	,	fRawDataUniqueID ()
1009 
1010 	,	fOriginalRawFileName ()
1011 
1012 	,	fOriginalRawFileDataCount  (0)
1013 	,	fOriginalRawFileDataOffset (0)
1014 
1015 	,	fOriginalRawFileDigest ()
1016 
1017 	,	fAsShotICCProfileCount  (0)
1018 	,	fAsShotICCProfileOffset (0)
1019 
1020 	,	fAsShotPreProfileMatrix ()
1021 
1022 	,	fCurrentICCProfileCount  (0)
1023 	,	fCurrentICCProfileOffset (0)
1024 
1025 	,	fCurrentPreProfileMatrix ()
1026 
1027 	,	fColorimetricReference (crSceneReferred)
1028 
1029 	,	fAsShotProfileName ()
1030 
1031 	{
1032 
1033 	}
1034 
1035 /*****************************************************************************/
1036 
~dng_shared()1037 dng_shared::~dng_shared ()
1038 	{
1039 
1040 	}
1041 
1042 /*****************************************************************************/
1043 
ParseTag(dng_stream & stream,dng_exif & exif,uint32 parentCode,bool,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset,int64)1044 bool dng_shared::ParseTag (dng_stream &stream,
1045 						   dng_exif &exif,
1046 						   uint32 parentCode,
1047 						   bool /* isMainIFD */,
1048 						   uint32 tagCode,
1049 						   uint32 tagType,
1050 						   uint32 tagCount,
1051 						   uint64 tagOffset,
1052 						   int64 /* offsetDelta */)
1053 	{
1054 
1055 	if (parentCode == 0)
1056 		{
1057 
1058 		if (Parse_ifd0 (stream,
1059 						exif,
1060 						parentCode,
1061 						tagCode,
1062 						tagType,
1063 						tagCount,
1064 						tagOffset))
1065 			{
1066 
1067 			return true;
1068 
1069 			}
1070 
1071 		}
1072 
1073 	if (parentCode == 0 ||
1074 		parentCode == tcExifIFD)
1075 		{
1076 
1077 		if (Parse_ifd0_exif (stream,
1078 							 exif,
1079 						 	 parentCode,
1080 						 	 tagCode,
1081 						 	 tagType,
1082 						 	 tagCount,
1083 						 	 tagOffset))
1084 			{
1085 
1086 			return true;
1087 
1088 			}
1089 
1090 		}
1091 
1092 	return false;
1093 
1094 	}
1095 
1096 /*****************************************************************************/
1097 
1098 // Parses tags that should only appear in IFD 0.
1099 
Parse_ifd0(dng_stream & stream,dng_exif &,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)1100 bool dng_shared::Parse_ifd0 (dng_stream &stream,
1101 							 dng_exif & /* exif */,
1102 							 uint32 parentCode,
1103 							 uint32 tagCode,
1104 							 uint32 tagType,
1105 							 uint32 tagCount,
1106 							 uint64 tagOffset)
1107 	{
1108 
1109 	switch (tagCode)
1110 		{
1111 
1112 		case tcXMP:
1113 			{
1114 
1115 			CheckTagType (parentCode, tagCode, tagType, ttByte);
1116 
1117 			fXMPCount  = tagCount;
1118 			fXMPOffset = fXMPCount ? tagOffset : 0;
1119 
1120 			#if qDNGValidate
1121 
1122 			if (gVerbose)
1123 				{
1124 
1125 				printf ("XMP: Count = %u, Offset = %u\n",
1126 						(unsigned) fXMPCount,
1127 						(unsigned) fXMPOffset);
1128 
1129 				if (fXMPCount)
1130 					{
1131 
1132 					DumpXMP (stream, fXMPCount);
1133 
1134 					}
1135 
1136 				}
1137 
1138 			#endif
1139 
1140 			break;
1141 
1142 			}
1143 
1144 		case tcIPTC_NAA:
1145 			{
1146 
1147 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii);
1148 
1149 			fIPTC_NAA_Count  = tagCount * TagTypeSize (tagType);
1150 			fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0;
1151 
1152 			#if qDNGValidate
1153 
1154 			if (gVerbose)
1155 				{
1156 
1157 				printf ("IPTC/NAA: Count = %u, Offset = %u\n",
1158 						(unsigned) fIPTC_NAA_Count,
1159 						(unsigned) fIPTC_NAA_Offset);
1160 
1161 				if (fIPTC_NAA_Count)
1162 					{
1163 
1164 					DumpHexAscii (stream, fIPTC_NAA_Count);
1165 
1166 					}
1167 
1168 				}
1169 
1170 			#endif
1171 
1172 			break;
1173 
1174 			}
1175 
1176 		case tcExifIFD:
1177 			{
1178 
1179 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1180 
1181 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1182 
1183 			fExifIFD = stream.TagValue_uint32 (tagType);
1184 
1185 			#if qDNGValidate
1186 
1187 			if (gVerbose)
1188 				{
1189 				printf ("ExifIFD: %u\n", (unsigned) fExifIFD);
1190 				}
1191 
1192 			#endif
1193 
1194 			break;
1195 
1196 			}
1197 
1198 		case tcGPSInfo:
1199 			{
1200 
1201 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1202 
1203 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1204 
1205 			fGPSInfo = stream.TagValue_uint32 (tagType);
1206 
1207 			#if qDNGValidate
1208 
1209 			if (gVerbose)
1210 				{
1211 				printf ("GPSInfo: %u\n", (unsigned) fGPSInfo);
1212 				}
1213 
1214 			#endif
1215 
1216 			break;
1217 
1218 			}
1219 
1220 		case tcKodakDCRPrivateIFD:
1221 			{
1222 
1223 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1224 
1225 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1226 
1227 			fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType);
1228 
1229 			#if qDNGValidate
1230 
1231 			if (gVerbose)
1232 				{
1233 				printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD);
1234 				}
1235 
1236 			#endif
1237 
1238 			break;
1239 
1240 			}
1241 
1242 		case tcKodakKDCPrivateIFD:
1243 			{
1244 
1245 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1246 
1247 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1248 
1249 			fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType);
1250 
1251 			#if qDNGValidate
1252 
1253 			if (gVerbose)
1254 				{
1255 				printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD);
1256 				}
1257 
1258 			#endif
1259 
1260 			break;
1261 
1262 			}
1263 
1264 		case tcDNGVersion:
1265 			{
1266 
1267 			CheckTagType (parentCode, tagCode, tagType, ttByte);
1268 
1269 			CheckTagCount (parentCode, tagCode, tagCount, 4);
1270 
1271 			uint32 b0 = stream.Get_uint8 ();
1272 			uint32 b1 = stream.Get_uint8 ();
1273 			uint32 b2 = stream.Get_uint8 ();
1274 			uint32 b3 = stream.Get_uint8 ();
1275 
1276 			fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1277 
1278 			#if qDNGValidate
1279 
1280 			if (gVerbose)
1281 				{
1282 				printf ("DNGVersion: %u.%u.%u.%u\n",
1283 						(unsigned) b0,
1284 						(unsigned) b1,
1285 						(unsigned) b2,
1286 						(unsigned) b3);
1287 				}
1288 
1289 			#endif
1290 
1291 			break;
1292 
1293 			}
1294 
1295 		case tcDNGBackwardVersion:
1296 			{
1297 
1298 			CheckTagType (parentCode, tagCode, tagType, ttByte);
1299 
1300 			CheckTagCount (parentCode, tagCode, tagCount, 4);
1301 
1302 			uint32 b0 = stream.Get_uint8 ();
1303 			uint32 b1 = stream.Get_uint8 ();
1304 			uint32 b2 = stream.Get_uint8 ();
1305 			uint32 b3 = stream.Get_uint8 ();
1306 
1307 			fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1308 
1309 			#if qDNGValidate
1310 
1311 			if (gVerbose)
1312 				{
1313 				printf ("DNGBackwardVersion: %u.%u.%u.%u\n",
1314 						(unsigned) b0,
1315 						(unsigned) b1,
1316 						(unsigned) b2,
1317 						(unsigned) b3);
1318 				}
1319 
1320 			#endif
1321 
1322 			break;
1323 
1324 			}
1325 
1326 		case tcUniqueCameraModel:
1327 			{
1328 
1329 			CheckTagType (parentCode, tagCode, tagType, ttAscii);
1330 
1331 			ParseStringTag (stream,
1332 							parentCode,
1333 							tagCode,
1334 							tagCount,
1335 							fUniqueCameraModel,
1336 							false);
1337 
1338 			bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
1339 
1340 			#if qDNGValidate
1341 
1342 			if (didTrim)
1343 				{
1344 
1345 				ReportWarning ("UniqueCameraModel string has trailing blanks");
1346 
1347 				}
1348 
1349 			if (gVerbose)
1350 				{
1351 
1352 				printf ("UniqueCameraModel: ");
1353 
1354 				DumpString (fUniqueCameraModel);
1355 
1356 				printf ("\n");
1357 
1358 				}
1359 
1360 			#else
1361 
1362 			(void) didTrim;		// Unused
1363 
1364 			#endif
1365 
1366 			break;
1367 
1368 			}
1369 
1370 		case tcLocalizedCameraModel:
1371 			{
1372 
1373 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1374 
1375 			ParseStringTag (stream,
1376 							parentCode,
1377 							tagCode,
1378 							tagCount,
1379 							fLocalizedCameraModel,
1380 							false,
1381 							false);
1382 
1383 			bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks ();
1384 
1385 			#if qDNGValidate
1386 
1387 			if (didTrim)
1388 				{
1389 
1390 				ReportWarning ("LocalizedCameraModel string has trailing blanks");
1391 
1392 				}
1393 
1394 			if (gVerbose)
1395 				{
1396 
1397 				printf ("LocalizedCameraModel: ");
1398 
1399 				DumpString (fLocalizedCameraModel);
1400 
1401 				printf ("\n");
1402 
1403 				}
1404 
1405 			#else
1406 
1407 			(void) didTrim;		// Unused
1408 
1409 			#endif
1410 
1411 			break;
1412 
1413 			}
1414 
1415 		case tcCameraCalibration1:
1416 			{
1417 
1418 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
1419 
1420 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1421 				return false;
1422 
1423 			if (!ParseMatrixTag (stream,
1424 								 parentCode,
1425 								 tagCode,
1426 								 tagType,
1427 								 tagCount,
1428 								 fCameraProfile.fColorPlanes,
1429 								 fCameraProfile.fColorPlanes,
1430 								 fCameraCalibration1))
1431 				return false;
1432 
1433 			#if qDNGValidate
1434 
1435 			if (gVerbose)
1436 				{
1437 
1438 				printf ("CameraCalibration1:\n");
1439 
1440 				DumpMatrix (fCameraCalibration1);
1441 
1442 				}
1443 
1444 			#endif
1445 
1446 			break;
1447 
1448 			}
1449 
1450 		case tcCameraCalibration2:
1451 			{
1452 
1453 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
1454 
1455 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1456 				return false;
1457 
1458 			if (!ParseMatrixTag (stream,
1459 								 parentCode,
1460 								 tagCode,
1461 								 tagType,
1462 								 tagCount,
1463 								 fCameraProfile.fColorPlanes,
1464 								 fCameraProfile.fColorPlanes,
1465 								 fCameraCalibration2))
1466 				return false;
1467 
1468 			#if qDNGValidate
1469 
1470 			if (gVerbose)
1471 				{
1472 
1473 				printf ("CameraCalibration2:\n");
1474 
1475 				DumpMatrix (fCameraCalibration2);
1476 
1477 				}
1478 
1479 			#endif
1480 
1481 			break;
1482 
1483 			}
1484 
1485 		case tcCameraCalibrationSignature:
1486 			{
1487 
1488 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1489 
1490 			ParseStringTag (stream,
1491 							parentCode,
1492 							tagCode,
1493 							tagCount,
1494 							fCameraCalibrationSignature,
1495 							false,
1496 							false);
1497 
1498 			#if qDNGValidate
1499 
1500 			if (gVerbose)
1501 				{
1502 
1503 				printf ("CameraCalibrationSignature: ");
1504 
1505 				DumpString (fCameraCalibrationSignature);
1506 
1507 				printf ("\n");
1508 
1509 				}
1510 
1511 			#endif
1512 
1513 			break;
1514 
1515 			}
1516 
1517 		case tcAnalogBalance:
1518 			{
1519 
1520 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1521 
1522 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1523 				return false;
1524 
1525 			if (!ParseVectorTag (stream,
1526 								 parentCode,
1527 								 tagCode,
1528 								 tagType,
1529 								 tagCount,
1530 								 fCameraProfile.fColorPlanes,
1531 								 fAnalogBalance))
1532 				return false;
1533 
1534 			#if qDNGValidate
1535 
1536 			if (gVerbose)
1537 				{
1538 
1539 				printf ("AnalogBalance:");
1540 
1541 				DumpVector (fAnalogBalance);
1542 
1543 				}
1544 
1545 			#endif
1546 
1547 			break;
1548 
1549 			}
1550 
1551 		case tcAsShotNeutral:
1552 			{
1553 
1554 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1555 
1556 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1557 				return false;
1558 
1559 			if (!ParseVectorTag (stream,
1560 								 parentCode,
1561 								 tagCode,
1562 								 tagType,
1563 								 tagCount,
1564 								 fCameraProfile.fColorPlanes,
1565 								 fAsShotNeutral))
1566 				return false;
1567 
1568 			#if qDNGValidate
1569 
1570 			if (gVerbose)
1571 				{
1572 
1573 				printf ("AsShotNeutral:");
1574 
1575 				DumpVector (fAsShotNeutral);
1576 
1577 				}
1578 
1579 			#endif
1580 
1581 			break;
1582 
1583 			}
1584 
1585 		case tcAsShotWhiteXY:
1586 			{
1587 
1588 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1589 
1590 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1591 				return false;
1592 
1593 			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1594 				return false;
1595 
1596 			fAsShotWhiteXY.x = stream.TagValue_real64 (tagType);
1597 			fAsShotWhiteXY.y = stream.TagValue_real64 (tagType);
1598 
1599 			#if qDNGValidate
1600 
1601 			if (gVerbose)
1602 				{
1603 
1604 				printf ("AsShotWhiteXY: %0.4f %0.4f\n",
1605 						fAsShotWhiteXY.x,
1606 						fAsShotWhiteXY.y);
1607 
1608 				}
1609 
1610 			#endif
1611 
1612 			break;
1613 
1614 			}
1615 
1616 		case tcBaselineExposure:
1617 			{
1618 
1619 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
1620 
1621 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1622 
1623 			fBaselineExposure = stream.TagValue_srational (tagType);
1624 
1625 			#if qDNGValidate
1626 
1627 			if (gVerbose)
1628 				{
1629 
1630 				printf ("BaselineExposure: %+0.2f\n",
1631 					    fBaselineExposure.As_real64 ());
1632 
1633 				}
1634 
1635 			#endif
1636 
1637 			break;
1638 
1639 			}
1640 
1641 		case tcBaselineNoise:
1642 			{
1643 
1644 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1645 
1646 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1647 
1648 			fBaselineNoise = stream.TagValue_urational (tagType);
1649 
1650 			#if qDNGValidate
1651 
1652 			if (gVerbose)
1653 				{
1654 
1655 				printf ("BaselineNoise: %0.2f\n",
1656 						fBaselineNoise.As_real64 ());
1657 
1658 				}
1659 
1660 			#endif
1661 
1662 			break;
1663 
1664 			}
1665 
1666 		case tcNoiseReductionApplied:
1667 			{
1668 
1669 			if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
1670 				return false;
1671 
1672 			if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
1673 				return false;
1674 
1675 			fNoiseReductionApplied = stream.TagValue_urational (tagType);
1676 
1677 			#if qDNGValidate
1678 
1679 			if (gVerbose)
1680 				{
1681 
1682 				printf ("NoiseReductionApplied: %u/%u\n",
1683 						(unsigned) fNoiseReductionApplied.n,
1684 						(unsigned) fNoiseReductionApplied.d);
1685 
1686 				}
1687 
1688 			#endif
1689 
1690 			break;
1691 
1692 			}
1693 
1694 		case tcBaselineSharpness:
1695 			{
1696 
1697 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1698 
1699 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1700 
1701 			fBaselineSharpness = stream.TagValue_urational (tagType);
1702 
1703 			#if qDNGValidate
1704 
1705 			if (gVerbose)
1706 				{
1707 
1708 				printf ("BaselineSharpness: %0.2f\n",
1709 					    fBaselineSharpness.As_real64 ());
1710 
1711 				}
1712 
1713 			#endif
1714 
1715 			break;
1716 
1717 			}
1718 
1719 		case tcLinearResponseLimit:
1720 			{
1721 
1722 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1723 
1724 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1725 
1726 			fLinearResponseLimit = stream.TagValue_urational (tagType);
1727 
1728 			#if qDNGValidate
1729 
1730 			if (gVerbose)
1731 				{
1732 
1733 				printf ("LinearResponseLimit: %0.2f\n",
1734 						fLinearResponseLimit.As_real64 ());
1735 
1736 				}
1737 
1738 			#endif
1739 
1740 			break;
1741 
1742 			}
1743 
1744 		case tcShadowScale:
1745 			{
1746 
1747 			CheckTagType (parentCode, tagCode, tagType, ttRational);
1748 
1749 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1750 
1751 			fShadowScale = stream.TagValue_urational (tagType);
1752 
1753 			#if qDNGValidate
1754 
1755 			if (gVerbose)
1756 				{
1757 
1758 				printf ("ShadowScale: %0.4f\n",
1759 						fShadowScale.As_real64 ());
1760 
1761 				}
1762 
1763 			#endif
1764 
1765 			break;
1766 
1767 			}
1768 
1769 		case tcDNGPrivateData:
1770 			{
1771 
1772 			CheckTagType (parentCode, tagCode, tagType, ttByte);
1773 
1774 			fDNGPrivateDataCount  = tagCount;
1775 			fDNGPrivateDataOffset = tagOffset;
1776 
1777 			#if qDNGValidate
1778 
1779 			if (gVerbose)
1780 				{
1781 
1782 				printf ("DNGPrivateData: Count = %u, Offset = %u\n",
1783 						(unsigned) fDNGPrivateDataCount,
1784 						(unsigned) fDNGPrivateDataOffset);
1785 
1786 				DumpHexAscii (stream, tagCount);
1787 
1788 				}
1789 
1790 			#endif
1791 
1792 			break;
1793 
1794 			}
1795 
1796 		case tcMakerNoteSafety:
1797 			{
1798 
1799 			CheckTagType (parentCode, tagCode, tagType, ttShort);
1800 
1801 			CheckTagCount (parentCode, tagCode, tagCount, 1);
1802 
1803 			fMakerNoteSafety = stream.TagValue_uint32 (tagType);
1804 
1805 			#if qDNGValidate
1806 
1807 			if (gVerbose)
1808 				{
1809 
1810 				printf ("MakerNoteSafety: %s\n",
1811 						LookupMakerNoteSafety (fMakerNoteSafety));
1812 
1813 				}
1814 
1815 			#endif
1816 
1817 			break;
1818 
1819 			}
1820 
1821 		case tcRawImageDigest:
1822 			{
1823 
1824 			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
1825 				return false;
1826 
1827 			if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
1828 				return false;
1829 
1830 			stream.Get (fRawImageDigest.data, 16);
1831 
1832 			#if qDNGValidate
1833 
1834 			if (gVerbose)
1835 				{
1836 
1837 				printf ("RawImageDigest: ");
1838 
1839 				DumpFingerprint (fRawImageDigest);
1840 
1841 				printf ("\n");
1842 
1843 				}
1844 
1845 			#endif
1846 
1847 			break;
1848 
1849 			}
1850 
1851 		case tcRawDataUniqueID:
1852 			{
1853 
1854 			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
1855 				return false;
1856 
1857 			if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
1858 				return false;
1859 
1860 			stream.Get (fRawDataUniqueID.data, 16);
1861 
1862 			#if qDNGValidate
1863 
1864 			if (gVerbose)
1865 				{
1866 
1867 				printf ("RawDataUniqueID: ");
1868 
1869 				DumpFingerprint (fRawDataUniqueID);
1870 
1871 				printf ("\n");
1872 
1873 				}
1874 
1875 			#endif
1876 
1877 			break;
1878 
1879 			}
1880 
1881 		case tcOriginalRawFileName:
1882 			{
1883 
1884 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1885 
1886 			ParseStringTag (stream,
1887 							parentCode,
1888 							tagCode,
1889 							tagCount,
1890 							fOriginalRawFileName,
1891 							false,
1892 							false);
1893 
1894 			#if qDNGValidate
1895 
1896 			if (gVerbose)
1897 				{
1898 
1899 				printf ("OriginalRawFileName: ");
1900 
1901 				DumpString (fOriginalRawFileName);
1902 
1903 				printf ("\n");
1904 
1905 				}
1906 
1907 			#endif
1908 
1909 			break;
1910 
1911 			}
1912 
1913 		case tcOriginalRawFileData:
1914 			{
1915 
1916 			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1917 
1918 			fOriginalRawFileDataCount  = tagCount;
1919 			fOriginalRawFileDataOffset = tagOffset;
1920 
1921 			#if qDNGValidate
1922 
1923 			if (gVerbose)
1924 				{
1925 
1926 				printf ("OriginalRawFileData: Count = %u, Offset = %u\n",
1927 						(unsigned) fOriginalRawFileDataCount,
1928 						(unsigned) fOriginalRawFileDataOffset);
1929 
1930 				DumpHexAscii (stream, tagCount);
1931 
1932 				}
1933 
1934 			#endif
1935 
1936 			break;
1937 
1938 			}
1939 
1940 		case tcOriginalRawFileDigest:
1941 			{
1942 
1943 			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
1944 				return false;
1945 
1946 			if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
1947 				return false;
1948 
1949 			stream.Get (fOriginalRawFileDigest.data, 16);
1950 
1951 			#if qDNGValidate
1952 
1953 			if (gVerbose)
1954 				{
1955 
1956 				printf ("OriginalRawFileDigest: ");
1957 
1958 				DumpFingerprint (fOriginalRawFileDigest);
1959 
1960 				printf ("\n");
1961 
1962 				}
1963 
1964 			#endif
1965 
1966 			break;
1967 
1968 			}
1969 
1970 		case tcAsShotICCProfile:
1971 			{
1972 
1973 			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1974 
1975 			fAsShotICCProfileCount  = tagCount;
1976 			fAsShotICCProfileOffset = tagOffset;
1977 
1978 			#if qDNGValidate
1979 
1980 			if (gVerbose)
1981 				{
1982 
1983 				printf ("AsShotICCProfile: Count = %u, Offset = %u\n",
1984 						(unsigned) fAsShotICCProfileCount,
1985 						(unsigned) fAsShotICCProfileOffset);
1986 
1987 				DumpHexAscii (stream, tagCount);
1988 
1989 				}
1990 
1991 			#endif
1992 
1993 			break;
1994 
1995 			}
1996 
1997 		case tcAsShotPreProfileMatrix:
1998 			{
1999 
2000 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
2001 
2002 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2003 				return false;
2004 
2005 			uint32 rows = fCameraProfile.fColorPlanes;
2006 
2007 			if (tagCount == fCameraProfile.fColorPlanes * 3)
2008 				{
2009 				rows = 3;
2010 				}
2011 
2012 			if (!ParseMatrixTag (stream,
2013 								 parentCode,
2014 								 tagCode,
2015 								 tagType,
2016 								 tagCount,
2017 								 rows,
2018 								 fCameraProfile.fColorPlanes,
2019 								 fAsShotPreProfileMatrix))
2020 				return false;
2021 
2022 			#if qDNGValidate
2023 
2024 			if (gVerbose)
2025 				{
2026 
2027 				printf ("AsShotPreProfileMatrix:\n");
2028 
2029 				DumpMatrix (fAsShotPreProfileMatrix);
2030 
2031 				}
2032 
2033 			#endif
2034 
2035 			break;
2036 
2037 			}
2038 
2039 		case tcCurrentICCProfile:
2040 			{
2041 
2042 			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2043 
2044 			fCurrentICCProfileCount  = tagCount;
2045 			fCurrentICCProfileOffset = tagOffset;
2046 
2047 			#if qDNGValidate
2048 
2049 			if (gVerbose)
2050 				{
2051 
2052 				printf ("CurrentICCProfile: Count = %u, Offset = %u\n",
2053 						(unsigned) fCurrentICCProfileCount,
2054 						(unsigned) fCurrentICCProfileOffset);
2055 
2056 				DumpHexAscii (stream, tagCount);
2057 
2058 				}
2059 
2060 			#endif
2061 
2062 			break;
2063 
2064 			}
2065 
2066 		case tcCurrentPreProfileMatrix:
2067 			{
2068 
2069 			CheckTagType (parentCode, tagCode, tagType, ttSRational);
2070 
2071 			if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2072 				return false;
2073 
2074 			uint32 rows = fCameraProfile.fColorPlanes;
2075 
2076 			if (tagCount == fCameraProfile.fColorPlanes * 3)
2077 				{
2078 				rows = 3;
2079 				}
2080 
2081 			if (!ParseMatrixTag (stream,
2082 								 parentCode,
2083 								 tagCode,
2084 								 tagType,
2085 								 tagCount,
2086 								 rows,
2087 								 fCameraProfile.fColorPlanes,
2088 								 fCurrentPreProfileMatrix))
2089 				return false;
2090 
2091 			#if qDNGValidate
2092 
2093 			if (gVerbose)
2094 				{
2095 
2096 				printf ("CurrentPreProfileMatrix:\n");
2097 
2098 				DumpMatrix (fCurrentPreProfileMatrix);
2099 
2100 				}
2101 
2102 			#endif
2103 
2104 			break;
2105 
2106 			}
2107 
2108 		case tcColorimetricReference:
2109 			{
2110 
2111 			CheckTagType (parentCode, tagCode, tagType, ttShort);
2112 
2113 			CheckTagCount (parentCode, tagCode, tagCount, 1);
2114 
2115 			fColorimetricReference = stream.TagValue_uint32 (tagType);
2116 
2117 			#if qDNGValidate
2118 
2119 			if (gVerbose)
2120 				{
2121 
2122 				printf ("ColorimetricReference: %s\n",
2123 						LookupColorimetricReference (fColorimetricReference));
2124 
2125 				}
2126 
2127 			#endif
2128 
2129 			break;
2130 
2131 			}
2132 
2133 		case tcExtraCameraProfiles:
2134 			{
2135 
2136 			CheckTagType (parentCode, tagCode, tagType, ttLong);
2137 
2138 			CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount);
2139 
2140 			#if qDNGValidate
2141 
2142 			if (gVerbose)
2143 				{
2144 
2145 				printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount);
2146 
2147 				}
2148 
2149 			#endif
2150 
2151 			fExtraCameraProfiles.reserve (tagCount);
2152 
2153 			for (uint32 index = 0; index < tagCount; index++)
2154 				{
2155 
2156 				#if qDNGValidate
2157 
2158 				if (gVerbose)
2159 					{
2160 
2161 					printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index);
2162 
2163 					}
2164 
2165 				#endif
2166 
2167 				stream.SetReadPosition (tagOffset + index * 4);
2168 
2169 				uint32 profileOffset = stream.TagValue_uint32 (tagType);
2170 
2171 				dng_camera_profile_info profileInfo;
2172 
2173 				stream.SetReadPosition (profileOffset);
2174 
2175 				if (profileInfo.ParseExtended (stream))
2176 					{
2177 
2178 					fExtraCameraProfiles.push_back (profileInfo);
2179 
2180 					}
2181 
2182 				else
2183 					{
2184 
2185 					#if qDNGValidate
2186 
2187 					ReportWarning ("Unable to parse extra camera profile");
2188 
2189 					#endif
2190 
2191 					}
2192 
2193 				}
2194 
2195 			#if qDNGValidate
2196 
2197 			if (gVerbose)
2198 				{
2199 
2200 				printf ("\nDone with ExtraCameraProfiles\n\n");
2201 
2202 				}
2203 
2204 			#endif
2205 
2206 			break;
2207 
2208 			}
2209 
2210 		case tcAsShotProfileName:
2211 			{
2212 
2213 			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2214 
2215 			ParseStringTag (stream,
2216 							parentCode,
2217 							tagCode,
2218 							tagCount,
2219 							fAsShotProfileName,
2220 							false,
2221 							false);
2222 
2223 			#if qDNGValidate
2224 
2225 			if (gVerbose)
2226 				{
2227 
2228 				printf ("AsShotProfileName: ");
2229 
2230 				DumpString (fAsShotProfileName);
2231 
2232 				printf ("\n");
2233 
2234 				}
2235 
2236 			#endif
2237 
2238 			break;
2239 
2240 			}
2241 
2242 		default:
2243 			{
2244 
2245 			// The main camera profile tags also appear in IFD 0
2246 
2247 			return fCameraProfile.ParseTag (stream,
2248 											parentCode,
2249 											tagCode,
2250 											tagType,
2251 											tagCount,
2252 											tagOffset);
2253 
2254 			}
2255 
2256 		}
2257 
2258 	return true;
2259 
2260 	}
2261 
2262 /*****************************************************************************/
2263 
2264 // Parses tags that should only appear in IFD 0 or EXIF IFD.
2265 
Parse_ifd0_exif(dng_stream & stream,dng_exif &,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)2266 bool dng_shared::Parse_ifd0_exif (dng_stream &stream,
2267 								  dng_exif & /* exif */,
2268 						  	   	  uint32 parentCode,
2269 						  	      uint32 tagCode,
2270 						  	      uint32 tagType,
2271 						  	      uint32 tagCount,
2272 						  	      uint64 tagOffset)
2273 	{
2274 
2275 	switch (tagCode)
2276 		{
2277 
2278 		case tcMakerNote:
2279 			{
2280 
2281 			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2282 
2283 			fMakerNoteCount  = tagCount;
2284 			fMakerNoteOffset = tagOffset;
2285 
2286 			#if qDNGValidate
2287 
2288 			if (gVerbose)
2289 				{
2290 
2291 				printf ("MakerNote: Count = %u, Offset = %u\n",
2292 						(unsigned) fMakerNoteCount,
2293 						(unsigned) fMakerNoteOffset);
2294 
2295 				DumpHexAscii (stream, tagCount);
2296 
2297 				}
2298 
2299 			#endif
2300 
2301 			break;
2302 
2303 			}
2304 
2305 		case tcInteroperabilityIFD:
2306 			{
2307 
2308 			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
2309 
2310 			CheckTagCount (parentCode, tagCode, tagCount, 1);
2311 
2312 			fInteroperabilityIFD = stream.TagValue_uint32 (tagType);
2313 
2314 			#if qDNGValidate
2315 
2316 			if (gVerbose)
2317 				{
2318 				printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD);
2319 				}
2320 
2321 			#endif
2322 
2323 			break;
2324 
2325 			}
2326 
2327 		default:
2328 			{
2329 
2330 			return false;
2331 
2332 			}
2333 
2334 		}
2335 
2336 	return true;
2337 
2338 	}
2339 
2340 /*****************************************************************************/
2341 
PostParse(dng_host &,dng_exif &)2342 void dng_shared::PostParse (dng_host & /* host */,
2343 							dng_exif & /* exif */)
2344 	{
2345 
2346 	// Fill in default values for DNG images.
2347 
2348 	if (fDNGVersion != 0)
2349 		{
2350 
2351 		// Support for DNG versions before 1.0.0.0.
2352 
2353 		if (fDNGVersion < 0x01000000)
2354 			{
2355 
2356 			#if qDNGValidate
2357 
2358 			ReportWarning ("DNGVersion less than 1.0.0.0");
2359 
2360 			#endif
2361 
2362 			// The CalibrationIlluminant tags were added just before
2363 			// DNG version 1.0.0.0, and were hardcoded before that.
2364 
2365 			fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA;
2366 			fCameraProfile.fCalibrationIlluminant2 = lsD65;
2367 
2368 			fDNGVersion = 0x01000000;
2369 
2370 			}
2371 
2372 		// Default value for DNGBackwardVersion tag.
2373 
2374 		if (fDNGBackwardVersion == 0)
2375 			{
2376 
2377 			fDNGBackwardVersion = fDNGVersion & 0xFFFF0000;
2378 
2379 			}
2380 
2381 		// Check DNGBackwardVersion value.
2382 
2383 		if (fDNGBackwardVersion < 0x01000000)
2384 			{
2385 
2386 			#if qDNGValidate
2387 
2388 			ReportWarning ("DNGBackwardVersion less than 1.0.0.0");
2389 
2390 			#endif
2391 
2392 			fDNGBackwardVersion = 0x01000000;
2393 
2394 			}
2395 
2396 		if (fDNGBackwardVersion > fDNGVersion)
2397 			{
2398 
2399 			#if qDNGValidate
2400 
2401 			ReportWarning ("DNGBackwardVersion > DNGVersion");
2402 
2403 			#endif
2404 
2405 			fDNGBackwardVersion = fDNGVersion;
2406 
2407 			}
2408 
2409 		// Check UniqueCameraModel.
2410 
2411 		if (fUniqueCameraModel.IsEmpty ())
2412 			{
2413 
2414 			#if qDNGValidate
2415 
2416 			ReportWarning ("Missing or invalid UniqueCameraModel");
2417 
2418 			#endif
2419 
2420 			fUniqueCameraModel.Set ("Digital Negative");
2421 
2422 			}
2423 
2424 		// If we don't know the color depth yet, it must be a monochrome DNG.
2425 
2426 		if (fCameraProfile.fColorPlanes == 0)
2427 			{
2428 
2429 			fCameraProfile.fColorPlanes = 1;
2430 
2431 			}
2432 
2433 		// Check color info.
2434 
2435 		if (fCameraProfile.fColorPlanes > 1)
2436 			{
2437 
2438 			// Check illuminant pair.
2439 
2440 			if (fCameraProfile.fColorMatrix2.NotEmpty ())
2441 				{
2442 
2443 				if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown ||
2444 					(fCameraProfile.fCalibrationIlluminant2 == lsUnknown ||
2445 					(fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2)))
2446 					{
2447 
2448 					#if qDNGValidate
2449 
2450 					ReportWarning ("Invalid CalibrationIlluminant pair");
2451 
2452 					#endif
2453 
2454 					fCameraProfile.fColorMatrix2 = dng_matrix ();
2455 
2456 					}
2457 
2458 				}
2459 
2460 			// If the colorimetric reference is the ICC profile PCS, then the
2461 			// data must already be white balanced.  The "AsShotWhiteXY" is required
2462 			// to be the ICC Profile PCS white point.
2463 
2464 			if (fColorimetricReference == crICCProfilePCS)
2465 				{
2466 
2467 				if (fAsShotNeutral.NotEmpty ())
2468 					{
2469 
2470 					#if qDNGValidate
2471 
2472 					ReportWarning ("AsShotNeutral not allowed for this "
2473 								   "ColorimetricReference value");
2474 
2475 					#endif
2476 
2477 					fAsShotNeutral.Clear ();
2478 
2479 					}
2480 
2481 				dng_xy_coord pcs = PCStoXY ();
2482 
2483 				#if qDNGValidate
2484 
2485 				if (fAsShotWhiteXY.IsValid ())
2486 					{
2487 
2488 					if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 ||
2489 						Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01)
2490 						{
2491 
2492 						ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS");
2493 
2494 						}
2495 
2496 					}
2497 
2498 				#endif
2499 
2500 				fAsShotWhiteXY = pcs;
2501 
2502 				}
2503 
2504 			else
2505 				{
2506 
2507 				// Warn if both AsShotNeutral and AsShotWhiteXY are specified.
2508 
2509 				if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ())
2510 					{
2511 
2512 					#if qDNGValidate
2513 
2514 					ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included");
2515 
2516 					#endif
2517 
2518 					fAsShotWhiteXY = dng_xy_coord ();
2519 
2520 					}
2521 
2522 				// Warn if neither AsShotNeutral nor AsShotWhiteXY are specified.
2523 
2524 				#if qDNGValidate
2525 
2526 				if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ())
2527 					{
2528 
2529 					ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included",
2530 								   "legal but not recommended");
2531 
2532 					}
2533 
2534 				#endif
2535 
2536 				}
2537 
2538 			// Default values of calibration signatures are required for legacy
2539 			// compatiblity.
2540 
2541 			if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
2542 				fCameraProfile.fCalibrationIlluminant2 == lsD65            &&
2543 				fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes &&
2544 				fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes &&
2545 				fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes &&
2546 				fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes &&
2547 				fCameraCalibrationSignature.IsEmpty ()                     &&
2548 				fCameraProfile.fProfileCalibrationSignature.IsEmpty ()     )
2549 				{
2550 
2551 				fCameraCalibrationSignature.Set (kAdobeCalibrationSignature);
2552 
2553 				fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature);
2554 
2555 				}
2556 
2557 			}
2558 
2559 		// Check BaselineNoise.
2560 
2561 		if (fBaselineNoise.As_real64 () <= 0.0)
2562 			{
2563 
2564 			#if qDNGValidate
2565 
2566 			ReportWarning ("Invalid BaselineNoise");
2567 
2568 			#endif
2569 
2570 			fBaselineNoise = dng_urational (1, 1);
2571 
2572 			}
2573 
2574 		// Check BaselineSharpness.
2575 
2576 		if (fBaselineSharpness.As_real64 () <= 0.0)
2577 			{
2578 
2579 			#if qDNGValidate
2580 
2581 			ReportWarning ("Invalid BaselineSharpness");
2582 
2583 			#endif
2584 
2585 			fBaselineSharpness = dng_urational (1, 1);
2586 
2587 			}
2588 
2589 		// Check LinearResponseLimit.
2590 
2591 		if (fLinearResponseLimit.As_real64 () < 0.5 ||
2592 			fLinearResponseLimit.As_real64 () > 1.0)
2593 			{
2594 
2595 			#if qDNGValidate
2596 
2597 			ReportWarning ("Invalid LinearResponseLimit");
2598 
2599 			#endif
2600 
2601 			fLinearResponseLimit = dng_urational (1, 1);
2602 
2603 			}
2604 
2605 		// Check ShadowScale.
2606 
2607 		if (fShadowScale.As_real64 () <= 0.0)
2608 			{
2609 
2610 			#if qDNGValidate
2611 
2612 			ReportWarning ("Invalid ShadowScale");
2613 
2614 			#endif
2615 
2616 			fShadowScale = dng_urational (1, 1);
2617 
2618 			}
2619 
2620 		}
2621 
2622 	}
2623 
2624 /*****************************************************************************/
2625 
IsValidDNG()2626 bool dng_shared::IsValidDNG ()
2627 	{
2628 
2629 	// Check DNGVersion value.
2630 
2631 	if (fDNGVersion < 0x01000000)
2632 		{
2633 
2634 		#if qDNGValidate
2635 
2636 		ReportError ("Missing or invalid DNGVersion");
2637 
2638 		#endif
2639 
2640 		return false;
2641 
2642 		}
2643 
2644 	// Check DNGBackwardVersion value.
2645 
2646 	if (fDNGBackwardVersion > 0x01020000)
2647 		{
2648 
2649 		#if qDNGValidate
2650 
2651 		ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
2652 
2653 		#endif
2654 
2655 		return false;
2656 
2657 		}
2658 
2659 	// Check color transform info.
2660 
2661 	if (fCameraProfile.fColorPlanes > 1)
2662 		{
2663 
2664 		// CameraCalibration1 is optional, but it must be valid if present.
2665 
2666 		if (fCameraCalibration1.Cols () != 0 ||
2667 			fCameraCalibration1.Rows () != 0)
2668 			{
2669 
2670 			if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes ||
2671 				fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes)
2672 				{
2673 
2674 				#if qDNGValidate
2675 
2676 				ReportError ("CameraCalibration1 is wrong size");
2677 
2678 				#endif
2679 
2680 				return false;
2681 
2682 				}
2683 
2684 			// Make sure it is invertable.
2685 
2686 			try
2687 				{
2688 
2689 				(void) Invert (fCameraCalibration1);
2690 
2691 				}
2692 
2693 			catch (...)
2694 				{
2695 
2696 				#if qDNGValidate
2697 
2698 				ReportError ("CameraCalibration1 is not invertable");
2699 
2700 				#endif
2701 
2702 				return false;
2703 
2704 				}
2705 
2706 			}
2707 
2708 		// CameraCalibration2 is optional, but it must be valid if present.
2709 
2710 		if (fCameraCalibration2.Cols () != 0 ||
2711 			fCameraCalibration2.Rows () != 0)
2712 			{
2713 
2714 			if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes ||
2715 				fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes)
2716 				{
2717 
2718 				#if qDNGValidate
2719 
2720 				ReportError ("CameraCalibration2 is wrong size");
2721 
2722 				#endif
2723 
2724 				return false;
2725 
2726 				}
2727 
2728 			// Make sure it is invertable.
2729 
2730 			try
2731 				{
2732 
2733 				(void) Invert (fCameraCalibration2);
2734 
2735 				}
2736 
2737 			catch (...)
2738 				{
2739 
2740 				#if qDNGValidate
2741 
2742 				ReportError ("CameraCalibration2 is not invertable");
2743 
2744 				#endif
2745 
2746 				return false;
2747 
2748 				}
2749 
2750 			}
2751 
2752 		// Check analog balance
2753 
2754 		dng_matrix analogBalance;
2755 
2756 		if (fAnalogBalance.NotEmpty ())
2757 			{
2758 
2759 			analogBalance = fAnalogBalance.AsDiagonal ();
2760 
2761 			try
2762 				{
2763 
2764 				(void) Invert (analogBalance);
2765 
2766 				}
2767 
2768 			catch (...)
2769 				{
2770 
2771 				#if qDNGValidate
2772 
2773 				ReportError ("AnalogBalance is not invertable");
2774 
2775 				#endif
2776 
2777 				return false;
2778 
2779 				}
2780 
2781 			}
2782 
2783 		}
2784 
2785 	return true;
2786 
2787 	}
2788 
2789 /*****************************************************************************/
2790