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