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
31dng_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
93dng_camera_profile_info::~dng_camera_profile_info ()
94	{
95
96	}
97
98/*****************************************************************************/
99
100bool 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
1032bool 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
1148dng_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
1240dng_shared::~dng_shared ()
1241	{
1242
1243	}
1244
1245/*****************************************************************************/
1246
1247bool 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
1303bool 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
2743bool 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
2819void 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
3118bool 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