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