Coverage Report

Created: 2025-08-26 06:51

/src/dng_sdk/source/dng_shared.cpp
Line
Count
Source (jump to first uncovered line)
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
31
dng_camera_profile_info::dng_camera_profile_info ()
32
33
11.1M
  : fBigEndian (false)
34
  
35
11.1M
  , fColorPlanes (0)
36
  
37
11.1M
  , fCalibrationIlluminant1 (lsUnknown)
38
11.1M
  , fCalibrationIlluminant2 (lsUnknown)
39
40
11.1M
  , fColorMatrix1 ()
41
11.1M
  , fColorMatrix2 ()
42
    
43
11.1M
  , fForwardMatrix1 ()
44
11.1M
  , fForwardMatrix2 ()
45
    
46
11.1M
  , fReductionMatrix1 ()
47
11.1M
  , fReductionMatrix2 ()
48
    
49
11.1M
  , fProfileCalibrationSignature ()
50
  
51
11.1M
  , fProfileName ()
52
  
53
11.1M
  , fProfileCopyright ()
54
55
11.1M
  , fEmbedPolicy (pepAllowCopying)
56
  
57
11.1M
  , fProfileHues (0)
58
11.1M
  , fProfileSats (0)
59
11.1M
  , fProfileVals (0)
60
61
11.1M
  , fHueSatDeltas1Offset (0)
62
11.1M
  , fHueSatDeltas1Count  (0)
63
64
11.1M
  , fHueSatDeltas2Offset (0)
65
11.1M
  , fHueSatDeltas2Count  (0)
66
67
11.1M
  , fHueSatMapEncoding (encoding_Linear)
68
  
69
11.1M
  , fLookTableHues (0)
70
11.1M
  , fLookTableSats (0)
71
11.1M
  , fLookTableVals (0)
72
    
73
11.1M
  , fLookTableOffset (0)
74
11.1M
  , fLookTableCount  (0)
75
76
11.1M
  , fLookTableEncoding (encoding_Linear)
77
78
11.1M
  , fBaselineExposureOffset (0, 100)
79
  
80
11.1M
  , fDefaultBlackRender (defaultBlackRender_Auto)
81
82
11.1M
  , fToneCurveOffset     (0)
83
11.1M
  , fToneCurveCount      (0)
84
  
85
11.1M
  , fUniqueCameraModel ()
86
87
11.1M
  {
88
  
89
11.1M
  }
90
                   
91
/*****************************************************************************/
92
93
dng_camera_profile_info::~dng_camera_profile_info ()
94
11.5M
  {
95
  
96
11.5M
  }
97
                   
98
/*****************************************************************************/
99
100
bool dng_camera_profile_info::ParseTag (dng_stream &stream,
101
                    uint32 parentCode,
102
                    uint32 tagCode,
103
                    uint32 tagType,
104
                    uint32 tagCount,
105
                    uint64 tagOffset)
106
61.8M
  {
107
108
61.8M
  switch (tagCode)
109
61.8M
    {
110
      
111
117k
    case tcCalibrationIlluminant1:
112
117k
      {
113
      
114
117k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
115
      
116
117k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
117
      
118
117k
      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
117k
      break;
133
      
134
0
      }
135
      
136
20.5k
    case tcCalibrationIlluminant2:
137
20.5k
      {
138
      
139
20.5k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
140
      
141
20.5k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
142
      
143
20.5k
      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
20.5k
      break;
158
      
159
0
      }
160
161
260k
    case tcColorMatrix1:
162
260k
      {
163
      
164
260k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
165
      
166
260k
      if (fColorPlanes == 0)
167
214k
        {
168
      
169
214k
        fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
170
                  
171
214k
        }
172
        
173
260k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
174
4.66k
        return false;
175
        
176
256k
      if (!ParseMatrixTag (stream,
177
256k
                 parentCode,
178
256k
                 tagCode,
179
256k
                 tagType,
180
256k
                 tagCount,
181
256k
                 fColorPlanes,
182
256k
                 3,
183
256k
                 fColorMatrix1))
184
126k
        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
129k
      break;
200
      
201
256k
      }
202
203
214k
    case tcColorMatrix2:
204
214k
      {
205
      
206
214k
      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
214k
      bool hasselbladHack = (fColorPlanes == 0);
212
      
213
214k
      if (hasselbladHack)
214
37.7k
        {
215
        
216
37.7k
        fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
217
        
218
        #if qDNGValidate
219
        
220
        ReportWarning ("ColorMatrix2 without ColorMatrix1");
221
        
222
        #endif
223
      
224
37.7k
        }
225
      
226
214k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
227
3.86k
        return false;
228
        
229
210k
      if (!ParseMatrixTag (stream,
230
210k
                 parentCode,
231
210k
                 tagCode,
232
210k
                 tagType,
233
210k
                 tagCount,
234
210k
                 fColorPlanes,
235
210k
                 3,
236
210k
                 fColorMatrix2))
237
181k
        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
28.7k
      if (hasselbladHack)
253
5.08k
        {
254
        
255
5.08k
        fColorMatrix1 = fColorMatrix2;
256
        
257
5.08k
        fColorMatrix2 = dng_matrix ();
258
        
259
5.08k
        }
260
        
261
28.7k
      break;
262
      
263
210k
      }
264
265
56.0k
    case tcForwardMatrix1:
266
56.0k
      {
267
      
268
56.0k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
269
      
270
56.0k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
271
2.48k
        return false;
272
        
273
53.5k
      if (!ParseMatrixTag (stream,
274
53.5k
                 parentCode,
275
53.5k
                 tagCode,
276
53.5k
                 tagType,
277
53.5k
                 tagCount,
278
53.5k
                 3,
279
53.5k
                 fColorPlanes,
280
53.5k
                 fForwardMatrix1))
281
3.77k
        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
49.7k
      break;
297
      
298
53.5k
      }
299
300
73.2k
    case tcForwardMatrix2:
301
73.2k
      {
302
      
303
73.2k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
304
      
305
73.2k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
306
58.5k
        return false;
307
        
308
14.6k
      if (!ParseMatrixTag (stream,
309
14.6k
                 parentCode,
310
14.6k
                 tagCode,
311
14.6k
                 tagType,
312
14.6k
                 tagCount,
313
14.6k
                 3,
314
14.6k
                 fColorPlanes,
315
14.6k
                 fForwardMatrix2))
316
4.68k
        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
9.95k
      break;
332
      
333
14.6k
      }
334
335
12.4k
    case tcReductionMatrix1:
336
12.4k
      {
337
      
338
12.4k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
339
      
340
12.4k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
341
5.91k
        return false;
342
        
343
6.50k
      if (!ParseMatrixTag (stream,
344
6.50k
                 parentCode,
345
6.50k
                 tagCode,
346
6.50k
                 tagType,
347
6.50k
                 tagCount,
348
6.50k
                 3,
349
6.50k
                 fColorPlanes,
350
6.50k
                 fReductionMatrix1))
351
4.02k
        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
2.48k
      break;
367
      
368
6.50k
      }
369
370
6.76k
    case tcReductionMatrix2:
371
6.76k
      {
372
      
373
6.76k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
374
      
375
6.76k
      if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
376
2.53k
        return false;
377
        
378
4.23k
      if (!ParseMatrixTag (stream,
379
4.23k
                 parentCode,
380
4.23k
                 tagCode,
381
4.23k
                 tagType,
382
4.23k
                 tagCount,
383
4.23k
                 3,
384
4.23k
                 fColorPlanes,
385
4.23k
                 fReductionMatrix2))
386
1.69k
        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
2.53k
      break;
402
      
403
4.23k
      }
404
405
12.4k
    case tcProfileCalibrationSignature:
406
12.4k
      {
407
408
12.4k
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
409
      
410
12.4k
      ParseStringTag (stream,
411
12.4k
              parentCode,
412
12.4k
              tagCode,
413
12.4k
              tagCount,
414
12.4k
              fProfileCalibrationSignature,
415
12.4k
              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
12.4k
      break;
433
      
434
4.23k
      }
435
      
436
62.9k
    case tcProfileName:
437
62.9k
      {
438
      
439
62.9k
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
440
      
441
62.9k
      ParseStringTag (stream,
442
62.9k
              parentCode,
443
62.9k
              tagCode,
444
62.9k
              tagCount,
445
62.9k
              fProfileName,
446
62.9k
              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
62.9k
      break;
464
      
465
4.23k
      }
466
      
467
6.61k
    case tcProfileCopyright:
468
6.61k
      {
469
470
6.61k
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
471
      
472
6.61k
      ParseStringTag (stream,
473
6.61k
              parentCode,
474
6.61k
              tagCode,
475
6.61k
              tagCount,
476
6.61k
              fProfileCopyright,
477
6.61k
              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
6.61k
      break;
495
      
496
4.23k
      }
497
498
66.1k
    case tcProfileEmbedPolicy:
499
66.1k
      {
500
        
501
66.1k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
502
      
503
66.1k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
504
      
505
66.1k
      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
66.1k
      break;
545
      
546
4.23k
      }
547
548
503k
    case tcProfileHueSatMapDims:
549
503k
      {
550
        
551
503k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
552
      
553
503k
      CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
554
      
555
503k
      fProfileHues = stream.TagValue_uint32 (tagType);
556
503k
      fProfileSats = stream.TagValue_uint32 (tagType);
557
558
503k
      if (tagCount > 2)
559
89.6k
        fProfileVals = stream.TagValue_uint32 (tagType);
560
414k
      else
561
414k
        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
503k
      break;
578
      
579
4.23k
      }
580
581
101k
    case tcProfileHueSatMapData1:
582
101k
      {
583
584
101k
      if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
585
69.7k
        return false;
586
        
587
31.7k
      bool skipSat0 = (tagCount ==
588
31.7k
               SafeUint32Mult(fProfileHues,
589
31.7k
                      SafeUint32Sub(fProfileSats, 1u),
590
31.7k
                      fProfileVals,
591
31.7k
                      3u));
592
      
593
31.7k
      if (!skipSat0)
594
14.5k
        {
595
      
596
14.5k
        if (!CheckTagCount (parentCode, tagCode, tagCount,
597
14.5k
                  SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3)))
598
11.4k
          return false;
599
          
600
14.5k
        }
601
        
602
20.2k
      fBigEndian = stream.BigEndian ();
603
        
604
20.2k
      fHueSatDeltas1Offset = tagOffset;
605
20.2k
      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
20.2k
      break;
625
      
626
31.7k
      }
627
628
252k
    case tcProfileHueSatMapData2:
629
252k
      {
630
631
252k
      if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
632
20.6k
        return false;
633
      
634
232k
      bool skipSat0 = (tagCount ==
635
232k
               SafeUint32Mult(fProfileHues,
636
232k
                      SafeUint32Sub(fProfileSats, 1u),
637
232k
                      fProfileVals,
638
232k
                      3u));
639
      
640
232k
      if (!skipSat0)
641
173k
        {
642
      
643
173k
        if (!CheckTagCount (parentCode, tagCode, tagCount,
644
173k
                  SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3)))
645
170k
          return false;
646
          
647
173k
        }
648
      
649
61.9k
      fBigEndian = stream.BigEndian ();
650
        
651
61.9k
      fHueSatDeltas2Offset = tagOffset;
652
61.9k
      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
61.9k
      break;
672
      
673
232k
      }
674
675
2.05k
    case tcProfileHueSatMapEncoding:
676
2.05k
      {
677
678
2.05k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
679
      
680
2.05k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
681
      
682
2.05k
      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
2.05k
      break;
714
      
715
232k
      }
716
717
163k
    case tcProfileLookTableDims:
718
163k
      {
719
        
720
163k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
721
      
722
163k
      CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
723
      
724
163k
      fLookTableHues = stream.TagValue_uint32 (tagType);
725
163k
      fLookTableSats = stream.TagValue_uint32 (tagType);
726
727
163k
      if (tagCount > 2)
728
60.4k
        fLookTableVals = stream.TagValue_uint32 (tagType);
729
103k
      else
730
103k
        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
163k
      break;
747
      
748
232k
      }
749
750
113k
    case tcProfileLookTableData:
751
113k
      {
752
753
113k
      if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
754
41.6k
        return false;
755
      
756
71.7k
      bool skipSat0 = (tagCount ==
757
71.7k
               SafeUint32Mult(fLookTableHues,
758
71.7k
                      SafeUint32Sub(fLookTableSats, 1u),
759
71.7k
                      fLookTableVals,
760
71.7k
                      3u));
761
      
762
71.7k
      if (!skipSat0)
763
65.5k
        {
764
      
765
65.5k
        if (!CheckTagCount (parentCode, tagCode, tagCount,
766
65.5k
                  SafeUint32Mult(fLookTableHues,
767
65.5k
                          fLookTableSats,
768
65.5k
                          fLookTableVals, 3)))
769
18.8k
          return false;
770
          
771
65.5k
        }
772
      
773
52.9k
      fBigEndian = stream.BigEndian ();
774
        
775
52.9k
      fLookTableOffset = tagOffset;
776
52.9k
      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
52.9k
      break;
796
      
797
71.7k
      }
798
799
6.12k
    case tcProfileLookTableEncoding:
800
6.12k
      {
801
802
6.12k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
803
      
804
6.12k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
805
      
806
6.12k
      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
6.12k
      break;
838
      
839
71.7k
      }
840
841
13.7k
    case tcBaselineExposureOffset:
842
13.7k
      {
843
      
844
13.7k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
845
      
846
13.7k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
847
      
848
13.7k
      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
13.7k
      break;
863
      
864
71.7k
      }
865
      
866
20.0k
    case tcDefaultBlackRender:
867
20.0k
      {
868
869
20.0k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
870
      
871
20.0k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
872
      
873
20.0k
      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
20.0k
      break;
906
      
907
71.7k
      }
908
909
62.3k
    case tcProfileToneCurve:
910
62.3k
      {
911
        
912
62.3k
      if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
913
9.32k
        return false;
914
      
915
53.0k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
916
2.98k
        return false;
917
    
918
50.0k
      if ((tagCount & 1) != 0)
919
2.43k
        {
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
2.43k
        return false;
940
        
941
2.43k
        }
942
      
943
47.6k
      fBigEndian = stream.BigEndian ();
944
        
945
47.6k
      fToneCurveOffset = tagOffset;
946
47.6k
      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
47.6k
      break;
966
      
967
50.0k
      }
968
969
138k
    case tcUniqueCameraModel:
970
138k
      {
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
138k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
977
      
978
138k
      ParseStringTag (stream,
979
138k
              parentCode,
980
138k
              tagCode,
981
138k
              tagCount,
982
138k
              fUniqueCameraModel,
983
138k
              false);
984
              
985
138k
      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
138k
      (void) didTrim;   // Unused
1010
        
1011
138k
      #endif
1012
      
1013
138k
      break;
1014
      
1015
50.0k
      }
1016
1017
59.5M
    default:
1018
59.5M
      {
1019
      
1020
59.5M
      return false;
1021
      
1022
50.0k
      }
1023
      
1024
61.8M
    }
1025
1026
1.50M
  return true;
1027
  
1028
61.8M
  }
1029
1030
/*****************************************************************************/
1031
1032
bool dng_camera_profile_info::ParseExtended (dng_stream &stream)
1033
11.0M
  {
1034
1035
11.0M
  try
1036
11.0M
    {
1037
    
1038
    // Offsets are relative to the start of this structure, not the entire file.
1039
1040
11.0M
    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
11.0M
    uint16 byteOrder = stream.Get_uint16 ();
1047
1048
11.0M
    if (byteOrder == byteOrderMM)
1049
159k
      fBigEndian = true;
1050
      
1051
10.8M
    else if (byteOrder == byteOrderII)
1052
4.07M
      fBigEndian = false;
1053
      
1054
6.77M
    else
1055
6.77M
      return false;
1056
1057
4.23M
    TempBigEndian setEndianness (stream, fBigEndian);
1058
1059
4.23M
    uint16 magicNumber = stream.Get_uint16 ();
1060
1061
4.23M
    if (magicNumber != magicExtendedProfile)
1062
3.75M
      {
1063
3.75M
      return false;
1064
3.75M
      }
1065
1066
475k
    uint32 offset = stream.Get_uint32 ();
1067
1068
475k
    stream.Skip (SafeUint32Sub(offset, 8u));
1069
1070
    // Start on IFD entries.
1071
1072
475k
    uint32 ifdEntries = stream.Get_uint16 ();
1073
  
1074
475k
    if (ifdEntries < 1)
1075
956
      {
1076
956
      return false;
1077
956
      }
1078
    
1079
62.0M
    for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
1080
61.5M
      {
1081
      
1082
61.5M
      stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12);
1083
      
1084
61.5M
      uint16 tagCode  = stream.Get_uint16 ();
1085
61.5M
      uint32 tagType  = stream.Get_uint16 ();
1086
61.5M
      uint32 tagCount = stream.Get_uint32 ();
1087
      
1088
61.5M
      uint64 tagOffset = stream.Position ();
1089
1090
61.5M
      if (SafeUint32Mult(TagTypeSize (tagType), tagCount) > 4)
1091
6.20M
        {
1092
1093
6.20M
        tagOffset = startPosition + stream.Get_uint32 ();
1094
1095
6.20M
        stream.SetReadPosition (tagOffset);
1096
1097
6.20M
        }
1098
        
1099
61.5M
      if (!ParseTag (stream,
1100
61.5M
               0,
1101
61.5M
               tagCode,
1102
61.5M
               tagType,
1103
61.5M
               tagCount,
1104
61.5M
               tagOffset))
1105
59.8M
        {
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
59.8M
        }
1128
1129
61.5M
      }
1130
      
1131
474k
    return true;
1132
1133
475k
    }
1134
    
1135
11.0M
  catch (...)
1136
11.0M
    {
1137
    
1138
    // Eat parsing errors.
1139
    
1140
252k
    }
1141
1142
252k
  return false;
1143
  
1144
11.0M
  }
1145
1146
/*****************************************************************************/
1147
1148
dng_shared::dng_shared ()
1149
  
1150
144k
  : fExifIFD       (0)
1151
144k
  , fGPSInfo       (0)
1152
144k
  , fInteroperabilityIFD (0)
1153
144k
  , fKodakDCRPrivateIFD  (0)
1154
144k
  , fKodakKDCPrivateIFD  (0)
1155
    
1156
144k
  , fXMPCount  (0)
1157
144k
  , fXMPOffset (0)
1158
    
1159
144k
  , fIPTC_NAA_Count  (0)
1160
144k
  , fIPTC_NAA_Offset (0)
1161
  
1162
144k
  , fMakerNoteCount  (0)
1163
144k
  , fMakerNoteOffset (0)
1164
144k
  , fMakerNoteSafety (0)
1165
  
1166
144k
  , fDNGVersion         (0)
1167
144k
  , fDNGBackwardVersion (0)
1168
  
1169
144k
  , fUniqueCameraModel    ()
1170
144k
  , fLocalizedCameraModel ()
1171
  
1172
144k
  , fCameraProfile ()
1173
  
1174
144k
  , fExtraCameraProfiles ()
1175
  
1176
144k
  , fCameraCalibration1 ()
1177
144k
  , fCameraCalibration2 ()
1178
    
1179
144k
  , fCameraCalibrationSignature  ()
1180
1181
144k
  , fAnalogBalance ()
1182
    
1183
144k
  , fAsShotNeutral ()
1184
    
1185
144k
  , fAsShotWhiteXY ()
1186
  
1187
144k
  , fBaselineExposure      (0, 1)
1188
144k
  , fBaselineNoise         (1, 1)
1189
144k
  , fNoiseReductionApplied (0, 0)
1190
144k
  , fBaselineSharpness     (1, 1)
1191
144k
  , fLinearResponseLimit   (1, 1)
1192
144k
  , fShadowScale           (1, 1)
1193
  
1194
144k
  , fHasBaselineExposure (false)
1195
144k
  , fHasShadowScale      (false)
1196
  
1197
144k
  , fDNGPrivateDataCount  (0)
1198
144k
  , fDNGPrivateDataOffset (0)
1199
  
1200
144k
  , fRawImageDigest    ()
1201
144k
  , fNewRawImageDigest ()
1202
  
1203
144k
  , fRawDataUniqueID ()
1204
  
1205
144k
  , fOriginalRawFileName ()
1206
    
1207
144k
  , fOriginalRawFileDataCount  (0)
1208
144k
  , fOriginalRawFileDataOffset (0)
1209
  
1210
144k
  , fOriginalRawFileDigest ()
1211
    
1212
144k
  , fAsShotICCProfileCount  (0)
1213
144k
  , fAsShotICCProfileOffset (0)
1214
  
1215
144k
  , fAsShotPreProfileMatrix ()
1216
    
1217
144k
  , fCurrentICCProfileCount  (0)
1218
144k
  , fCurrentICCProfileOffset (0)
1219
  
1220
144k
  , fCurrentPreProfileMatrix ()
1221
  
1222
144k
  , fColorimetricReference (crSceneReferred)
1223
1224
144k
  , fAsShotProfileName ()
1225
1226
144k
  , fNoiseProfile ()
1227
  
1228
144k
  , fOriginalDefaultFinalSize     ()
1229
144k
  , fOriginalBestQualityFinalSize ()
1230
    
1231
144k
  , fOriginalDefaultCropSizeH ()
1232
144k
  , fOriginalDefaultCropSizeV ()
1233
    
1234
144k
  {
1235
  
1236
144k
  }
1237
  
1238
/*****************************************************************************/
1239
1240
dng_shared::~dng_shared ()
1241
144k
  {
1242
  
1243
144k
  }
1244
    
1245
/*****************************************************************************/
1246
1247
bool dng_shared::ParseTag (dng_stream &stream,
1248
               dng_exif &exif,
1249
               uint32 parentCode,
1250
               bool /* isMainIFD */,
1251
               uint32 tagCode,
1252
               uint32 tagType,
1253
               uint32 tagCount,
1254
               uint64 tagOffset,
1255
               int64 /* offsetDelta */)
1256
2.75M
  {
1257
  
1258
2.75M
  if (parentCode == 0)
1259
1.08M
    {
1260
    
1261
1.08M
    if (Parse_ifd0 (stream,
1262
1.08M
            exif,
1263
1.08M
            parentCode,
1264
1.08M
            tagCode,
1265
1.08M
            tagType,
1266
1.08M
            tagCount,
1267
1.08M
            tagOffset))
1268
571k
      {
1269
      
1270
571k
      return true;
1271
      
1272
571k
      }
1273
1274
1.08M
    }
1275
    
1276
2.18M
  if (parentCode == 0 ||
1277
2.18M
    parentCode == tcExifIFD)
1278
612k
    {
1279
    
1280
612k
    if (Parse_ifd0_exif (stream,
1281
612k
               exif,
1282
612k
               parentCode,
1283
612k
               tagCode,
1284
612k
               tagType,
1285
612k
               tagCount,
1286
612k
               tagOffset))
1287
18.7k
      {
1288
      
1289
18.7k
      return true;
1290
      
1291
18.7k
      }
1292
1293
612k
    }
1294
    
1295
2.16M
  return false;
1296
    
1297
2.18M
  }
1298
1299
/*****************************************************************************/
1300
1301
// Parses tags that should only appear in IFD 0.
1302
1303
bool dng_shared::Parse_ifd0 (dng_stream &stream,
1304
               dng_exif & /* exif */,
1305
               uint32 parentCode,
1306
               uint32 tagCode,
1307
               uint32 tagType,
1308
               uint32 tagCount,
1309
               uint64 tagOffset)
1310
1.08M
  {
1311
  
1312
1.08M
  switch (tagCode)
1313
1.08M
    {
1314
      
1315
25.4k
    case tcXMP:
1316
25.4k
      {
1317
      
1318
25.4k
      CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined);
1319
      
1320
25.4k
      fXMPCount  = tagCount;
1321
25.4k
      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
25.4k
      break;
1344
      
1345
0
      }
1346
1347
1.57k
    case tcIPTC_NAA:
1348
1.57k
      {
1349
      
1350
1.57k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined);
1351
      
1352
1.57k
      fIPTC_NAA_Count = SafeUint32Mult(tagCount,
1353
1.57k
                              TagTypeSize(tagType));
1354
1.57k
      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
1.57k
      break;
1434
      
1435
0
      }
1436
1437
20.1k
    case tcExifIFD:
1438
20.1k
      {
1439
      
1440
20.1k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1441
      
1442
20.1k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1443
      
1444
20.1k
      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
20.1k
      break;
1456
      
1457
0
      }
1458
    
1459
12.1k
    case tcGPSInfo:
1460
12.1k
      {
1461
      
1462
12.1k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1463
      
1464
12.1k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1465
      
1466
12.1k
      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
12.1k
      break;
1478
      
1479
0
      }
1480
        
1481
1.37k
    case tcKodakDCRPrivateIFD:
1482
1.37k
      {
1483
      
1484
1.37k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1485
      
1486
1.37k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1487
      
1488
1.37k
      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
1.37k
      break;
1500
      
1501
0
      }
1502
    
1503
1.85k
    case tcKodakKDCPrivateIFD:
1504
1.85k
      {
1505
      
1506
1.85k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1507
      
1508
1.85k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1509
      
1510
1.85k
      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
1.85k
      break;
1522
      
1523
0
      }
1524
    
1525
121k
    case tcDNGVersion:
1526
121k
      {
1527
      
1528
121k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
1529
      
1530
121k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1531
      
1532
121k
      uint32 b0 = stream.Get_uint8 ();
1533
121k
      uint32 b1 = stream.Get_uint8 ();
1534
121k
      uint32 b2 = stream.Get_uint8 ();
1535
121k
      uint32 b3 = stream.Get_uint8 ();
1536
      
1537
121k
      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
121k
      break;
1553
      
1554
0
      }
1555
        
1556
39.7k
    case tcDNGBackwardVersion:
1557
39.7k
      {
1558
      
1559
39.7k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
1560
      
1561
39.7k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1562
      
1563
39.7k
      uint32 b0 = stream.Get_uint8 ();
1564
39.7k
      uint32 b1 = stream.Get_uint8 ();
1565
39.7k
      uint32 b2 = stream.Get_uint8 ();
1566
39.7k
      uint32 b3 = stream.Get_uint8 ();
1567
      
1568
39.7k
      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
39.7k
      break;
1584
      
1585
0
      }
1586
        
1587
27.7k
    case tcUniqueCameraModel:
1588
27.7k
      {
1589
      
1590
27.7k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1591
      
1592
27.7k
      ParseStringTag (stream,
1593
27.7k
              parentCode,
1594
27.7k
              tagCode,
1595
27.7k
              tagCount,
1596
27.7k
              fUniqueCameraModel,
1597
27.7k
              false);
1598
              
1599
27.7k
      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
27.7k
      (void) didTrim;   // Unused
1624
        
1625
27.7k
      #endif
1626
      
1627
27.7k
      break;
1628
      
1629
0
      }
1630
1631
2.36k
    case tcLocalizedCameraModel:
1632
2.36k
      {
1633
      
1634
2.36k
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1635
      
1636
2.36k
      ParseStringTag (stream,
1637
2.36k
              parentCode,
1638
2.36k
              tagCode,
1639
2.36k
              tagCount,
1640
2.36k
              fLocalizedCameraModel,
1641
2.36k
              false);
1642
      
1643
2.36k
      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
2.36k
      (void) didTrim;   // Unused
1668
        
1669
2.36k
      #endif
1670
      
1671
2.36k
      break;
1672
      
1673
0
      }
1674
      
1675
7.74k
    case tcCameraCalibration1:
1676
7.74k
      {
1677
      
1678
7.74k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
1679
      
1680
7.74k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1681
3.72k
        return false;
1682
        
1683
4.01k
      if (!ParseMatrixTag (stream,
1684
4.01k
                 parentCode,
1685
4.01k
                 tagCode,
1686
4.01k
                 tagType,
1687
4.01k
                 tagCount,
1688
4.01k
                 fCameraProfile.fColorPlanes,
1689
4.01k
                 fCameraProfile.fColorPlanes,
1690
4.01k
                 fCameraCalibration1))
1691
2.08k
        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
1.92k
      break;
1707
      
1708
4.01k
      }
1709
1710
4.56k
    case tcCameraCalibration2:
1711
4.56k
      {
1712
      
1713
4.56k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
1714
      
1715
4.56k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1716
1.40k
        return false;
1717
        
1718
3.15k
      if (!ParseMatrixTag (stream,
1719
3.15k
                 parentCode,
1720
3.15k
                 tagCode,
1721
3.15k
                 tagType,
1722
3.15k
                 tagCount,
1723
3.15k
                 fCameraProfile.fColorPlanes,
1724
3.15k
                 fCameraProfile.fColorPlanes,
1725
3.15k
                 fCameraCalibration2))
1726
1.32k
        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
1.82k
      break;
1742
      
1743
3.15k
      }
1744
1745
1.82k
    case tcCameraCalibrationSignature:
1746
272
      {
1747
1748
272
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1749
      
1750
272
      ParseStringTag (stream,
1751
272
              parentCode,
1752
272
              tagCode,
1753
272
              tagCount,
1754
272
              fCameraCalibrationSignature,
1755
272
              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
272
      break;
1773
      
1774
3.15k
      }
1775
      
1776
38.2k
    case tcAnalogBalance:
1777
38.2k
      {
1778
      
1779
38.2k
      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
38.2k
      bool hasselbladHack = (fDNGVersion == 0 &&
1785
38.2k
                   fCameraProfile.fColorPlanes == 0);
1786
      
1787
38.2k
      if (hasselbladHack)
1788
1.22k
        {
1789
        
1790
1.22k
        fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1791
        
1792
        #if qDNGValidate
1793
        
1794
        ReportWarning ("AnalogBalance without ColorMatrix1");
1795
        
1796
        #endif
1797
      
1798
1.22k
        }
1799
      
1800
38.2k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1801
7.43k
        return false;
1802
        
1803
30.8k
      if (!ParseVectorTag (stream,
1804
30.8k
                 parentCode,
1805
30.8k
                 tagCode,
1806
30.8k
                 tagType,
1807
30.8k
                 tagCount,
1808
30.8k
                 fCameraProfile.fColorPlanes,
1809
30.8k
                 fAnalogBalance))
1810
19.5k
        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
11.2k
      break;
1826
      
1827
30.8k
      }
1828
      
1829
14.9k
    case tcAsShotNeutral:
1830
14.9k
      {
1831
      
1832
14.9k
      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
14.9k
      bool hasselbladHack = (fDNGVersion == 0 &&
1838
14.9k
                   fCameraProfile.fColorPlanes == 0);
1839
      
1840
14.9k
      if (hasselbladHack)
1841
1.04k
        {
1842
        
1843
1.04k
        fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1844
        
1845
        #if qDNGValidate
1846
        
1847
        ReportWarning ("AsShotNeutral without ColorMatrix1");
1848
        
1849
        #endif
1850
      
1851
1.04k
        }
1852
      
1853
14.9k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1854
6.64k
        return false;
1855
        
1856
8.30k
      if (!ParseVectorTag (stream,
1857
8.30k
                 parentCode,
1858
8.30k
                 tagCode,
1859
8.30k
                 tagType,
1860
8.30k
                 tagCount,
1861
8.30k
                 fCameraProfile.fColorPlanes,
1862
8.30k
                 fAsShotNeutral))
1863
5.41k
        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
2.88k
      break;
1879
      
1880
8.30k
      }
1881
      
1882
20.7k
    case tcAsShotWhiteXY:
1883
20.7k
      {
1884
      
1885
20.7k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1886
      
1887
20.7k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1888
3.13k
        return false;
1889
        
1890
17.5k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1891
4.50k
        return false;
1892
        
1893
13.0k
      fAsShotWhiteXY.x = stream.TagValue_real64 (tagType);
1894
13.0k
      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
13.0k
      break;
1910
      
1911
17.5k
      }
1912
      
1913
28.9k
    case tcBaselineExposure:
1914
28.9k
      {
1915
      
1916
28.9k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
1917
      
1918
28.9k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1919
      
1920
28.9k
      fBaselineExposure = stream.TagValue_srational (tagType);
1921
      
1922
28.9k
      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
28.9k
      break;
1937
      
1938
17.5k
      }
1939
      
1940
21.9k
    case tcBaselineNoise:
1941
21.9k
      {
1942
      
1943
21.9k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1944
      
1945
21.9k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1946
      
1947
21.9k
      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
21.9k
      break;
1962
      
1963
17.5k
      }
1964
      
1965
6.91k
    case tcNoiseReductionApplied:
1966
6.91k
      {
1967
      
1968
6.91k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
1969
491
        return false;
1970
      
1971
6.42k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
1972
549
        return false;
1973
      
1974
5.87k
      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
5.87k
      break;
1990
      
1991
6.42k
      }
1992
1993
4.51k
    case tcNoiseProfile:
1994
4.51k
      {
1995
1996
4.51k
      if (!CheckTagType (parentCode, tagCode, tagType, ttDouble))
1997
84
        return false;
1998
1999
      // Must be an even, positive number of doubles in a noise profile.
2000
      
2001
4.43k
      if (!tagCount || (tagCount & 1))
2002
427
        return false;
2003
2004
      // Determine number of planes (i.e., half the number of doubles).
2005
2006
4.00k
      const uint32 numPlanes = Pin_uint32 (0, 
2007
4.00k
                         tagCount >> 1, 
2008
4.00k
                         kMaxColorPlanes);
2009
2010
      // Parse the noise function parameters.
2011
2012
4.00k
      dng_std_vector<dng_noise_function> noiseFunctions;
2013
2014
18.3k
      for (uint32 i = 0; i < numPlanes; i++)
2015
14.3k
        {
2016
2017
14.3k
        const real64 scale  = stream.TagValue_real64 (tagType);
2018
14.3k
        const real64 offset = stream.TagValue_real64 (tagType);
2019
2020
14.3k
        noiseFunctions.push_back (dng_noise_function (scale, offset));
2021
2022
14.3k
        }
2023
2024
      // Store the noise profile.
2025
2026
4.00k
      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
4.00k
      break;
2054
      
2055
4.43k
      }
2056
      
2057
19.9k
    case tcBaselineSharpness:
2058
19.9k
      {
2059
      
2060
19.9k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2061
      
2062
19.9k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2063
      
2064
19.9k
      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
19.9k
      break;
2079
      
2080
4.43k
      }
2081
      
2082
20.0k
    case tcLinearResponseLimit:
2083
20.0k
      {
2084
      
2085
20.0k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2086
      
2087
20.0k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2088
      
2089
20.0k
      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
20.0k
      break;
2104
      
2105
4.43k
      }
2106
      
2107
6.83k
    case tcShadowScale:
2108
6.83k
      {
2109
      
2110
6.83k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2111
      
2112
6.83k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2113
      
2114
6.83k
      fShadowScale = stream.TagValue_urational (tagType);
2115
      
2116
6.83k
      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
6.83k
      break;
2131
      
2132
4.43k
      }
2133
      
2134
29.5k
    case tcDNGPrivateData:
2135
29.5k
      {
2136
      
2137
29.5k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
2138
      
2139
29.5k
      fDNGPrivateDataCount  = tagCount;
2140
29.5k
      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
29.5k
      break;
2158
      
2159
4.43k
      }
2160
      
2161
3.59k
    case tcMakerNoteSafety:
2162
3.59k
      {
2163
      
2164
3.59k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2165
      
2166
3.59k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2167
      
2168
3.59k
      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
3.59k
      break;
2183
      
2184
4.43k
      }
2185
      
2186
8.62k
    case tcRawImageDigest:
2187
8.62k
      {
2188
      
2189
8.62k
      if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2190
1.15k
        return false;
2191
        
2192
7.47k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2193
972
        return false;
2194
        
2195
6.50k
      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
6.50k
      break;
2213
      
2214
7.47k
      }
2215
      
2216
639
    case tcNewRawImageDigest:
2217
639
      {
2218
      
2219
639
      if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2220
83
        return false;
2221
        
2222
556
      if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2223
147
        return false;
2224
        
2225
409
      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
409
      break;
2243
      
2244
556
      }
2245
      
2246
18.7k
    case tcRawDataUniqueID:
2247
18.7k
      {
2248
      
2249
18.7k
      if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2250
3.14k
        return false;
2251
        
2252
15.5k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2253
7.95k
        return false;
2254
        
2255
7.63k
      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
7.63k
      break;
2273
      
2274
15.5k
      }
2275
      
2276
504
    case tcOriginalRawFileName:
2277
504
      {
2278
      
2279
504
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2280
      
2281
504
      ParseStringTag (stream,
2282
504
              parentCode,
2283
504
              tagCode,
2284
504
              tagCount,
2285
504
              fOriginalRawFileName,
2286
504
              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
504
      break;
2304
      
2305
15.5k
      }
2306
      
2307
434
    case tcOriginalRawFileData:
2308
434
      {
2309
      
2310
434
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2311
      
2312
434
      fOriginalRawFileDataCount  = tagCount;
2313
434
      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
434
      break;
2331
      
2332
15.5k
      }
2333
      
2334
3.19k
    case tcOriginalRawFileDigest:
2335
3.19k
      {
2336
      
2337
3.19k
      if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2338
1.09k
        return false;
2339
        
2340
2.09k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2341
516
        return false;
2342
        
2343
1.58k
      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
1.58k
      break;
2361
      
2362
2.09k
      }
2363
      
2364
174
    case tcAsShotICCProfile:
2365
174
      {
2366
      
2367
174
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2368
      
2369
174
      fAsShotICCProfileCount  = tagCount;
2370
174
      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
174
      break;
2388
      
2389
2.09k
      }
2390
      
2391
7.98k
    case tcAsShotPreProfileMatrix:
2392
7.98k
      {
2393
      
2394
7.98k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2395
      
2396
7.98k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2397
2.94k
        return false;
2398
        
2399
5.03k
      uint32 rows = fCameraProfile.fColorPlanes;
2400
      
2401
5.03k
      if (tagCount == fCameraProfile.fColorPlanes * 3)
2402
490
        {
2403
490
        rows = 3;
2404
490
        }
2405
      
2406
5.03k
      if (!ParseMatrixTag (stream,
2407
5.03k
                 parentCode,
2408
5.03k
                 tagCode,
2409
5.03k
                 tagType,
2410
5.03k
                 tagCount,
2411
5.03k
                 rows,
2412
5.03k
                 fCameraProfile.fColorPlanes,
2413
5.03k
                 fAsShotPreProfileMatrix))
2414
4.09k
        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
940
      break;
2430
      
2431
5.03k
      }
2432
      
2433
940
    case tcCurrentICCProfile:
2434
645
      {
2435
      
2436
645
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2437
      
2438
645
      fCurrentICCProfileCount  = tagCount;
2439
645
      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
645
      break;
2457
      
2458
5.03k
      }
2459
      
2460
32.5k
    case tcCurrentPreProfileMatrix:
2461
32.5k
      {
2462
      
2463
32.5k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2464
      
2465
32.5k
      if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2466
14.8k
        return false;
2467
        
2468
17.6k
      uint32 rows = fCameraProfile.fColorPlanes;
2469
      
2470
17.6k
      if (tagCount == fCameraProfile.fColorPlanes * 3)
2471
1.73k
        {
2472
1.73k
        rows = 3;
2473
1.73k
        }
2474
      
2475
17.6k
      if (!ParseMatrixTag (stream,
2476
17.6k
                 parentCode,
2477
17.6k
                 tagCode,
2478
17.6k
                 tagType,
2479
17.6k
                 tagCount,
2480
17.6k
                 rows,
2481
17.6k
                 fCameraProfile.fColorPlanes,
2482
17.6k
                 fCurrentPreProfileMatrix))
2483
11.6k
        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
5.99k
      break;
2499
      
2500
17.6k
      }
2501
      
2502
22.0k
    case tcColorimetricReference:
2503
22.0k
      {
2504
      
2505
22.0k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2506
      
2507
22.0k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2508
      
2509
22.0k
      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
22.0k
      break;
2524
      
2525
17.6k
      }
2526
2527
13.5k
    case tcExtraCameraProfiles:
2528
13.5k
      {
2529
        
2530
13.5k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
2531
      
2532
13.5k
      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
13.5k
      fExtraCameraProfiles.reserve (tagCount);
2546
      
2547
11.0M
      for (uint32 index = 0; index < tagCount; index++)
2548
11.0M
        {
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
11.0M
        stream.SetReadPosition (tagOffset + index * 4);
2562
        
2563
11.0M
        uint32 profileOffset = stream.TagValue_uint32 (tagType);
2564
        
2565
11.0M
        dng_camera_profile_info profileInfo;
2566
        
2567
11.0M
        stream.SetReadPosition (profileOffset);
2568
        
2569
11.0M
        if (profileInfo.ParseExtended (stream))
2570
224k
          {
2571
          
2572
224k
          fExtraCameraProfiles.push_back (profileInfo);
2573
          
2574
224k
          }
2575
          
2576
10.7M
        else
2577
10.7M
          {
2578
          
2579
          #if qDNGValidate
2580
2581
          ReportWarning ("Unable to parse extra camera profile");
2582
          
2583
          #endif
2584
      
2585
10.7M
          }
2586
        
2587
11.0M
        }
2588
2589
      #if qDNGValidate
2590
2591
      if (gVerbose)
2592
        {
2593
        
2594
        printf ("\nDone with ExtraCameraProfiles\n\n");
2595
        
2596
        }
2597
        
2598
      #endif
2599
      
2600
13.5k
      break;
2601
      
2602
17.6k
      }
2603
      
2604
2.27k
    case tcAsShotProfileName:
2605
2.27k
      {
2606
            
2607
2.27k
      CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2608
      
2609
2.27k
      ParseStringTag (stream,
2610
2.27k
              parentCode,
2611
2.27k
              tagCode,
2612
2.27k
              tagCount,
2613
2.27k
              fAsShotProfileName,
2614
2.27k
              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
2.27k
      break;
2632
      
2633
17.6k
      }
2634
2635
1.55k
    case tcOriginalDefaultFinalSize:
2636
1.55k
      {
2637
      
2638
1.55k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2639
      
2640
1.55k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2641
341
        return false;
2642
        
2643
1.21k
      fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType);
2644
1.21k
      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
1.21k
      break;
2660
      
2661
1.55k
      }
2662
        
2663
1.14k
    case tcOriginalBestQualityFinalSize:
2664
1.14k
      {
2665
      
2666
1.14k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2667
      
2668
1.14k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2669
274
        return false;
2670
        
2671
869
      fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType);
2672
869
      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
869
      break;
2688
      
2689
1.14k
      }
2690
        
2691
2.01k
    case tcOriginalDefaultCropSize:
2692
2.01k
      {
2693
      
2694
2.01k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
2695
      
2696
2.01k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2697
333
        return false;
2698
        
2699
1.68k
      fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType);
2700
1.68k
      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
1.68k
      break;
2716
      
2717
2.01k
      }
2718
      
2719
489k
    default:
2720
489k
      {
2721
      
2722
      // The main camera profile tags also appear in IFD 0
2723
      
2724
489k
      return fCameraProfile.ParseTag (stream,
2725
489k
                      parentCode,
2726
489k
                      tagCode,
2727
489k
                      tagType,
2728
489k
                      tagCount,
2729
489k
                      tagOffset);
2730
      
2731
2.01k
      }
2732
      
2733
1.08M
    }
2734
2735
485k
  return true;
2736
  
2737
1.08M
  }
2738
  
2739
/*****************************************************************************/
2740
2741
// Parses tags that should only appear in IFD 0 or EXIF IFD.
2742
2743
bool dng_shared::Parse_ifd0_exif (dng_stream &stream,
2744
                  dng_exif & /* exif */,
2745
                      uint32 parentCode,
2746
                      uint32 tagCode,
2747
                      uint32 tagType,
2748
                      uint32 tagCount,
2749
                      uint64 tagOffset)
2750
612k
  {
2751
  
2752
612k
  switch (tagCode)
2753
612k
    {
2754
    
2755
15.0k
    case tcMakerNote:
2756
15.0k
      {
2757
      
2758
15.0k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2759
      
2760
15.0k
      fMakerNoteCount  = tagCount;
2761
15.0k
      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
15.0k
      break;
2779
      
2780
0
      }
2781
      
2782
3.61k
    case tcInteroperabilityIFD:
2783
3.61k
      {
2784
      
2785
3.61k
      CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
2786
      
2787
3.61k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2788
      
2789
3.61k
      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
3.61k
      break;
2801
      
2802
0
      }
2803
      
2804
593k
    default:
2805
593k
      {
2806
      
2807
593k
      return false;
2808
      
2809
0
      }
2810
      
2811
612k
    }
2812
    
2813
18.7k
  return true;
2814
  
2815
612k
  }
2816
                 
2817
/*****************************************************************************/
2818
2819
void dng_shared::PostParse (dng_host & /* host */,
2820
              dng_exif & /* exif */)
2821
103k
  {
2822
  
2823
  // Fill in default values for DNG images.
2824
  
2825
103k
  if (fDNGVersion != 0)
2826
75.5k
    {
2827
    
2828
    // Support for DNG versions before 1.0.0.0.
2829
    
2830
75.5k
    if (fDNGVersion < dngVersion_1_0_0_0)
2831
32.0k
      {
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
32.0k
      fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA;
2843
32.0k
      fCameraProfile.fCalibrationIlluminant2 = lsD65;
2844
      
2845
32.0k
      fDNGVersion = dngVersion_1_0_0_0;
2846
2847
32.0k
      }
2848
    
2849
    // Default value for DNGBackwardVersion tag.
2850
    
2851
75.5k
    if (fDNGBackwardVersion == 0)
2852
60.3k
      {
2853
      
2854
60.3k
      fDNGBackwardVersion = fDNGVersion & 0xFFFF0000;
2855
      
2856
60.3k
      }
2857
  
2858
    // Check DNGBackwardVersion value.
2859
    
2860
75.5k
    if (fDNGBackwardVersion < dngVersion_1_0_0_0)
2861
2.48k
      {
2862
      
2863
      #if qDNGValidate
2864
      
2865
      ReportWarning ("DNGBackwardVersion less than 1.0.0.0");
2866
             
2867
      #endif
2868
      
2869
2.48k
      fDNGBackwardVersion = dngVersion_1_0_0_0;
2870
        
2871
2.48k
      }
2872
2873
75.5k
    if (fDNGBackwardVersion > fDNGVersion)
2874
2.84k
      {
2875
      
2876
      #if qDNGValidate
2877
      
2878
      ReportWarning ("DNGBackwardVersion > DNGVersion");
2879
             
2880
      #endif
2881
      
2882
2.84k
      fDNGBackwardVersion = fDNGVersion;
2883
          
2884
2.84k
      }
2885
2886
    // Check UniqueCameraModel.
2887
    
2888
75.5k
    if (fUniqueCameraModel.IsEmpty ())
2889
70.7k
      {
2890
      
2891
      #if qDNGValidate
2892
      
2893
      ReportWarning ("Missing or invalid UniqueCameraModel");
2894
             
2895
      #endif
2896
      
2897
70.7k
      fUniqueCameraModel.Set ("Digital Negative");
2898
      
2899
70.7k
      }
2900
    
2901
    // If we don't know the color depth yet, it must be a monochrome DNG.
2902
    
2903
75.5k
    if (fCameraProfile.fColorPlanes == 0)
2904
56.2k
      {
2905
      
2906
56.2k
      fCameraProfile.fColorPlanes = 1;
2907
      
2908
56.2k
      }
2909
      
2910
    // Check color info.
2911
    
2912
75.5k
    if (fCameraProfile.fColorPlanes > 1)
2913
19.2k
      {
2914
      
2915
      // Check illuminant pair.
2916
      
2917
19.2k
      if (fCameraProfile.fColorMatrix2.NotEmpty ())
2918
710
        {
2919
        
2920
710
        if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown ||
2921
710
          (fCameraProfile.fCalibrationIlluminant2 == lsUnknown ||
2922
639
          (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2)))
2923
290
          {
2924
            
2925
          #if qDNGValidate
2926
      
2927
          ReportWarning ("Invalid CalibrationIlluminant pair");
2928
                 
2929
          #endif
2930
                 
2931
290
          fCameraProfile.fColorMatrix2 = dng_matrix ();
2932
        
2933
290
          }
2934
2935
710
        }
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
19.2k
      if (fColorimetricReference == crICCProfilePCS)
2942
5.22k
        {
2943
        
2944
5.22k
        if (fAsShotNeutral.NotEmpty ())
2945
47
          {
2946
          
2947
          #if qDNGValidate
2948
        
2949
          ReportWarning ("AsShotNeutral not allowed for this "
2950
                   "ColorimetricReference value");
2951
                 
2952
          #endif
2953
          
2954
47
          fAsShotNeutral.Clear ();
2955
          
2956
47
          }
2957
          
2958
5.22k
        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
5.22k
        fAsShotWhiteXY = pcs;
2978
2979
5.22k
        }
2980
        
2981
14.0k
      else
2982
14.0k
        {
2983
        
2984
        // Warn if both AsShotNeutral and AsShotWhiteXY are specified.
2985
          
2986
14.0k
        if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ())
2987
75
          {
2988
            
2989
          #if qDNGValidate
2990
        
2991
          ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included");
2992
                 
2993
          #endif
2994
          
2995
75
          fAsShotWhiteXY = dng_xy_coord ();
2996
                   
2997
75
          }
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
14.0k
        }
3014
        
3015
      // Default values of calibration signatures are required for legacy
3016
      // compatiblity.
3017
3018
19.2k
      if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
3019
19.2k
        fCameraProfile.fCalibrationIlluminant2 == lsD65            &&
3020
19.2k
        fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes &&
3021
19.2k
        fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes &&
3022
19.2k
        fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes &&
3023
19.2k
        fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes &&
3024
19.2k
        fCameraCalibrationSignature.IsEmpty ()                     &&
3025
19.2k
        fCameraProfile.fProfileCalibrationSignature.IsEmpty ()     )
3026
21
        {
3027
3028
21
        fCameraCalibrationSignature.Set (kAdobeCalibrationSignature);
3029
          
3030
21
        fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature);
3031
3032
21
        }
3033
3034
19.2k
      }
3035
      
3036
    // Check BaselineNoise.
3037
3038
75.5k
    if (fBaselineNoise.As_real64 () <= 0.0)
3039
421
      {
3040
      
3041
      #if qDNGValidate
3042
      
3043
      ReportWarning ("Invalid BaselineNoise");
3044
             
3045
      #endif
3046
      
3047
421
      fBaselineNoise = dng_urational (1, 1);
3048
               
3049
421
      }
3050
      
3051
    // Check BaselineSharpness.
3052
    
3053
75.5k
    if (fBaselineSharpness.As_real64 () <= 0.0)
3054
1.02k
      {
3055
      
3056
      #if qDNGValidate
3057
      
3058
      ReportWarning ("Invalid BaselineSharpness");
3059
             
3060
      #endif
3061
      
3062
1.02k
      fBaselineSharpness = dng_urational (1, 1);
3063
               
3064
1.02k
      }
3065
3066
    // Check NoiseProfile.
3067
3068
75.5k
    if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0)
3069
149
      {
3070
      
3071
      #if qDNGValidate
3072
      
3073
      ReportWarning ("Invalid NoiseProfile");
3074
             
3075
      #endif
3076
      
3077
149
      fNoiseProfile = dng_noise_profile ();
3078
               
3079
149
      }
3080
      
3081
    // Check LinearResponseLimit.
3082
    
3083
75.5k
    if (fLinearResponseLimit.As_real64 () < 0.5 ||
3084
75.5k
      fLinearResponseLimit.As_real64 () > 1.0)
3085
4.71k
      {
3086
      
3087
      #if qDNGValidate
3088
      
3089
      ReportWarning ("Invalid LinearResponseLimit");
3090
             
3091
      #endif
3092
      
3093
4.71k
      fLinearResponseLimit = dng_urational (1, 1);
3094
               
3095
4.71k
      }
3096
      
3097
    // Check ShadowScale.
3098
    
3099
75.5k
    if (fShadowScale.As_real64 () <= 0.0)
3100
1.05k
      {
3101
      
3102
      #if qDNGValidate
3103
      
3104
      ReportWarning ("Invalid ShadowScale");
3105
             
3106
      #endif
3107
               
3108
1.05k
      fShadowScale = dng_urational (1, 1);
3109
               
3110
1.05k
      }
3111
    
3112
75.5k
    }
3113
  
3114
103k
  }
3115
                 
3116
/*****************************************************************************/
3117
3118
bool dng_shared::IsValidDNG ()
3119
99.5k
  {
3120
  
3121
  // Check DNGVersion value.
3122
  
3123
99.5k
  if (fDNGVersion < dngVersion_1_0_0_0)
3124
27.1k
    {
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
27.1k
    return false;
3149
      
3150
27.1k
    }
3151
    
3152
  // Check DNGBackwardVersion value.
3153
  
3154
72.3k
  if (fDNGBackwardVersion > dngVersion_Current)
3155
5.88k
    {
3156
    
3157
    #if qDNGValidate
3158
    
3159
    ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
3160
    
3161
    #endif
3162
    
3163
5.88k
    ThrowUnsupportedDNG ();
3164
      
3165
5.88k
    }
3166
    
3167
  // Check color transform info.
3168
  
3169
72.3k
  if (fCameraProfile.fColorPlanes > 1)
3170
17.5k
    {
3171
    
3172
    // CameraCalibration1 is optional, but it must be valid if present.
3173
    
3174
17.5k
    if (fCameraCalibration1.Cols () != 0 ||
3175
17.5k
      fCameraCalibration1.Rows () != 0)
3176
223
      {
3177
      
3178
223
      if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes ||
3179
223
        fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes)
3180
0
        {
3181
        
3182
        #if qDNGValidate
3183
    
3184
        ReportError ("CameraCalibration1 is wrong size");
3185
               
3186
        #endif
3187
3188
0
        return false;
3189
        
3190
0
        }
3191
        
3192
      // Make sure it is invertable.
3193
      
3194
223
      try
3195
223
        {
3196
        
3197
223
        (void) Invert (fCameraCalibration1);
3198
        
3199
223
        }
3200
        
3201
223
      catch (...)
3202
223
        {
3203
        
3204
        #if qDNGValidate
3205
    
3206
        ReportError ("CameraCalibration1 is not invertable");
3207
               
3208
        #endif
3209
               
3210
16
        return false;
3211
      
3212
16
        }
3213
        
3214
223
      }
3215
    
3216
    // CameraCalibration2 is optional, but it must be valid if present.
3217
    
3218
17.4k
    if (fCameraCalibration2.Cols () != 0 ||
3219
17.4k
      fCameraCalibration2.Rows () != 0)
3220
130
      {
3221
      
3222
130
      if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes ||
3223
130
        fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes)
3224
0
        {
3225
        
3226
        #if qDNGValidate
3227
    
3228
        ReportError ("CameraCalibration2 is wrong size");
3229
               
3230
        #endif
3231
3232
0
        return false;
3233
        
3234
0
        }
3235
      
3236
      // Make sure it is invertable.
3237
      
3238
130
      try
3239
130
        {
3240
        
3241
130
        (void) Invert (fCameraCalibration2);
3242
        
3243
130
        }
3244
        
3245
130
      catch (...)
3246
130
        {
3247
        
3248
        #if qDNGValidate
3249
  
3250
        ReportError ("CameraCalibration2 is not invertable");
3251
               
3252
        #endif
3253
               
3254
30
        return false;
3255
      
3256
30
        }
3257
          
3258
130
      }
3259
      
3260
    // Check analog balance
3261
    
3262
17.4k
    dng_matrix analogBalance;
3263
    
3264
17.4k
    if (fAnalogBalance.NotEmpty ())
3265
7.11k
      {
3266
      
3267
7.11k
      analogBalance = fAnalogBalance.AsDiagonal ();
3268
      
3269
7.11k
      try
3270
7.11k
        {
3271
        
3272
7.11k
        (void) Invert (analogBalance);
3273
        
3274
7.11k
        }
3275
        
3276
7.11k
      catch (...)
3277
7.11k
        {
3278
        
3279
        #if qDNGValidate
3280
    
3281
        ReportError ("AnalogBalance is not invertable");
3282
               
3283
        #endif
3284
               
3285
78
        return false;
3286
      
3287
78
        }
3288
        
3289
7.11k
      }
3290
        
3291
17.4k
    }
3292
      
3293
72.2k
  return true;
3294
  
3295
72.3k
  }
3296
  
3297
/*****************************************************************************/