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