Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/dng_sdk/source/dng_info.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************/
2
// Copyright 2006-2007 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_info.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_info.h"
17
18
#include "dng_camera_profile.h"
19
#include "dng_exceptions.h"
20
#include "dng_globals.h"
21
#include "dng_host.h"
22
#include "dng_tag_codes.h"
23
#include "dng_parse_utils.h"
24
#include "dng_safe_arithmetic.h"
25
#include "dng_tag_types.h"
26
#include "dng_tag_values.h"
27
#include "dng_utils.h"
28
29
/*****************************************************************************/
30
31
dng_info::dng_info ()
32
33
  : fTIFFBlockOffset         (0)
34
  , fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
35
  , fBigEndian         (false)
36
  , fMagic           (0)
37
  , fExif          ()
38
  , fShared          ()
39
  , fMainIndex         (-1)
40
  , fMaskIndex         (-1)
41
  , fIFDCount        (0)
42
  , fChainedIFDCount     (0)
43
  , fMakerNoteNextIFD    (0)
44
  
45
7.07k
  {
46
  
47
7.07k
  }
48
  
49
/*****************************************************************************/
50
51
dng_info::~dng_info ()
52
7.07k
  {
53
  
54
7.07k
  }
55
56
/*****************************************************************************/
57
58
void dng_info::ValidateMagic ()
59
7.07k
  {
60
  
61
7.07k
  switch (fMagic)
62
7.07k
    {
63
    
64
7.07k
    case magicTIFF:
65
7.07k
    case magicExtendedProfile:
66
7.07k
    case magicRawCache:
67
7.07k
    case magicPanasonic:
68
7.07k
    case magicOlympusA:
69
7.07k
    case magicOlympusB:
70
7.07k
      {
71
      
72
7.07k
      return;
73
      
74
7.07k
      }
75
      
76
0
    default:
77
0
      {
78
      
79
      #if qDNGValidate
80
      
81
      ReportError ("Invalid TIFF magic number");
82
      
83
      #endif
84
      
85
0
      ThrowBadFormat ();
86
      
87
0
      }
88
      
89
7.07k
    }
90
  
91
7.07k
  }
92
93
/*****************************************************************************/
94
95
void dng_info::ParseTag (dng_host &host,
96
             dng_stream &stream,
97
             dng_exif *exif,
98
             dng_shared *shared,
99
             dng_ifd *ifd,
100
             uint32 parentCode,
101
             uint32 tagCode,
102
             uint32 tagType,
103
             uint32 tagCount,
104
             uint64 tagOffset,
105
             int64 offsetDelta)
106
150k
  {
107
  
108
150k
  bool isSubIFD = parentCode >= tcFirstSubIFD &&
109
105k
          parentCode <= tcLastSubIFD;
110
            
111
150k
  bool isMainIFD = (parentCode == 0 || isSubIFD) &&
112
142k
           ifd &&
113
142k
           ifd->fUsesNewSubFileType &&
114
5.60k
           ifd->fNewSubFileType == sfMainImage;
115
           
116
  // Panasonic RAW format stores private tags using tag codes < 254 in
117
  // IFD 0.  Redirect the parsing of these tags into a logical
118
  // "PanasonicRAW" IFD.
119
  
120
  // Panasonic is starting to use some higher numbers also (280..283).
121
           
122
150k
  if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
123
0
                      (tagCode >= 280 && tagCode <= 283)))
124
0
    {
125
    
126
0
    parentCode = tcPanasonicRAW;
127
    
128
0
    ifd = NULL;
129
    
130
0
    }
131
  
132
150k
  stream.SetReadPosition (tagOffset);
133
    
134
150k
  if (ifd && ifd->ParseTag (stream,
135
144k
                parentCode,
136
144k
                tagCode,
137
144k
                tagType,
138
144k
                tagCount,
139
144k
                tagOffset))
140
70.9k
    {
141
    
142
70.9k
    return;
143
    
144
70.9k
    }
145
    
146
79.1k
  stream.SetReadPosition (tagOffset);
147
    
148
79.1k
  if (exif && shared && exif->ParseTag (stream,
149
78.0k
                      *shared,
150
78.0k
                      parentCode,
151
78.0k
                      isMainIFD,
152
78.0k
                      tagCode,
153
78.0k
                      tagType,
154
78.0k
                      tagCount,
155
78.0k
                      tagOffset))
156
12.3k
    {
157
    
158
12.3k
    return;
159
    
160
12.3k
    }
161
    
162
66.7k
  stream.SetReadPosition (tagOffset);
163
    
164
66.7k
  if (shared && exif && shared->ParseTag (stream,
165
65.5k
                      *exif,
166
65.5k
                        parentCode,
167
65.5k
                        isMainIFD,
168
65.5k
                        tagCode,
169
65.5k
                        tagType,
170
65.5k
                        tagCount,
171
65.5k
                        tagOffset,
172
65.5k
                        offsetDelta))
173
6.36k
    {
174
    
175
6.36k
    return;
176
    
177
6.36k
    }
178
179
60.3k
  if (parentCode == tcLeicaMakerNote &&
180
0
    tagType == ttUndefined &&
181
0
    tagCount >= 14)
182
0
    {
183
    
184
0
    if (ParseMakerNoteIFD (host,
185
0
                 stream,
186
0
                 tagCount,
187
0
                 tagOffset,
188
0
                 offsetDelta,
189
0
                 tagOffset,
190
0
                 stream.Length (),
191
0
                 tcLeicaMakerNote))
192
0
      {
193
        
194
0
      return;
195
        
196
0
      }
197
    
198
0
    }
199
    
200
60.3k
  if (parentCode == tcOlympusMakerNote &&
201
0
    tagType == ttUndefined &&
202
0
    tagCount >= 14)
203
0
    {
204
    
205
0
    uint32 olympusMakerParent = 0;
206
    
207
0
    switch (tagCode)
208
0
      {
209
      
210
0
      case 8208:
211
0
        olympusMakerParent = tcOlympusMakerNote8208;
212
0
        break;
213
        
214
0
      case 8224:
215
0
        olympusMakerParent = tcOlympusMakerNote8224;
216
0
        break; 
217
    
218
0
      case 8240:
219
0
        olympusMakerParent = tcOlympusMakerNote8240;
220
0
        break; 
221
    
222
0
      case 8256:
223
0
        olympusMakerParent = tcOlympusMakerNote8256;
224
0
        break; 
225
    
226
0
      case 8272:
227
0
        olympusMakerParent = tcOlympusMakerNote8272;
228
0
        break; 
229
    
230
0
      case 12288:
231
0
        olympusMakerParent = tcOlympusMakerNote12288;
232
0
        break;
233
        
234
0
      default:
235
0
        break;
236
        
237
0
      }
238
      
239
0
    if (olympusMakerParent)
240
0
      {
241
      
242
      // Olympus made a mistake in some camera models in computing
243
      // the size of these sub-tags, so we fudge the count.
244
      
245
0
      if (ParseMakerNoteIFD (host,
246
0
                   stream,
247
0
                     stream.Length () - tagOffset,
248
0
                         tagOffset,
249
0
                         offsetDelta,
250
0
                         tagOffset,
251
0
                         stream.Length (),
252
0
                         olympusMakerParent))
253
0
        {
254
        
255
0
        return;
256
        
257
0
        }
258
      
259
0
      }
260
      
261
0
    }
262
263
60.3k
  if (parentCode == tcRicohMakerNote &&
264
2
    tagCode == 0x2001 &&
265
0
    tagType == ttUndefined &&
266
0
    tagCount > 22)
267
0
    {
268
    
269
0
    char header [20];
270
    
271
0
    stream.SetReadPosition (tagOffset);
272
    
273
0
    stream.Get (header, sizeof (header));
274
    
275
0
    if (memcmp (header, "[Ricoh Camera Info]", 19) == 0)
276
0
      {
277
    
278
0
      ParseMakerNoteIFD (host,
279
0
                 stream,
280
0
                 tagCount - 20,
281
0
                     tagOffset + 20,
282
0
                     offsetDelta,
283
0
                     tagOffset + 20,
284
0
                     tagOffset + tagCount,
285
0
                     tcRicohMakerNoteCameraInfo);
286
287
0
      return;
288
      
289
0
      }
290
      
291
0
    }
292
    
293
  #if qDNGValidate
294
  
295
    {
296
    
297
    stream.SetReadPosition (tagOffset);
298
    
299
    if (gVerbose)
300
      {
301
          
302
      printf ("*");
303
        
304
      DumpTagValues (stream,
305
               LookupTagType (tagType),
306
               parentCode,
307
               tagCode,
308
               tagType,
309
               tagCount);
310
      
311
      }
312
      
313
    // If type is ASCII, then parse anyway so we report any ASCII
314
    // NULL termination or character set errors.
315
      
316
    else if (tagType == ttAscii)
317
      {
318
      
319
      dng_string s;
320
      
321
      ParseStringTag (stream,
322
              parentCode,
323
              tagCode,
324
              tagCount,
325
              s,
326
              false);
327
328
      }
329
      
330
    }
331
  
332
  #endif
333
  
334
60.3k
  }
335
336
/*****************************************************************************/
337
338
bool dng_info::ValidateIFD (dng_stream &stream,
339
                uint64 ifdOffset,
340
                int64 offsetDelta)
341
492
  {
342
  
343
  // Make sure we have a count.
344
  
345
492
  if (ifdOffset + 2 > stream.Length ())
346
7
    {
347
7
    return false;
348
7
    }
349
    
350
  // Get entry count.
351
    
352
485
  stream.SetReadPosition (ifdOffset);
353
  
354
485
  uint32 ifdEntries = stream.Get_uint16 ();
355
  
356
485
  if (ifdEntries < 1)
357
10
    {
358
10
    return false;
359
10
    }
360
    
361
  // Make sure we have room for all entries and next IFD link.
362
    
363
475
  if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
364
94
    {
365
94
    return false;
366
94
    }
367
    
368
  // Check each entry.
369
  
370
1.84k
  for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
371
1.60k
    {
372
    
373
1.60k
    stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
374
    
375
1.60k
    stream.Skip (2);    // Ignore tag code.
376
    
377
1.60k
    uint32 tagType  = stream.Get_uint16 ();
378
1.60k
    uint32 tagCount = stream.Get_uint32 ();
379
    
380
1.60k
    uint32 tag_type_size = TagTypeSize (tagType);
381
    
382
1.60k
    if (tag_type_size == 0)
383
51
      {
384
51
      return false;
385
51
      }
386
      
387
1.55k
    uint32 tag_data_size = SafeUint32Mult(tagCount, tag_type_size);
388
            
389
1.55k
    if (tag_data_size > 4)
390
421
      {
391
      
392
421
      uint64 tagOffset = stream.Get_uint32 ();
393
              
394
421
      tagOffset += offsetDelta;
395
      
396
421
      if (SafeUint64Add(tagOffset, tag_data_size) > stream.Length())
397
90
        {
398
90
        return false;
399
90
        }
400
      
401
421
      }
402
      
403
1.55k
    }
404
    
405
240
  return true;
406
  
407
381
  }
408
409
/*****************************************************************************/
410
411
void dng_info::ParseIFD (dng_host &host,
412
             dng_stream &stream,
413
             dng_exif *exif,
414
             dng_shared *shared,
415
             dng_ifd *ifd,
416
             uint64 ifdOffset,
417
             int64 offsetDelta,
418
             uint32 parentCode)
419
20.6k
  {
420
  
421
  #if qDNGValidate
422
423
  bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
424
            parentCode <= tcLastMakerNoteIFD);
425
  
426
  #endif
427
428
20.6k
  stream.SetReadPosition (ifdOffset);
429
  
430
20.6k
  if (ifd)
431
19.9k
    {
432
19.9k
    ifd->fThisIFD = ifdOffset;
433
19.9k
    }
434
  
435
20.6k
  uint32 ifdEntries = stream.Get_uint16 ();
436
  
437
  #if qDNGValidate
438
  
439
  if (gVerbose)
440
    {
441
    
442
    printf ("%s: Offset = %u, Entries = %u\n\n",
443
        LookupParentCode (parentCode),
444
          (unsigned) ifdOffset, 
445
          (unsigned) ifdEntries);
446
    
447
    }
448
    
449
  if ((ifdOffset & 1) && !isMakerNote)
450
    {
451
    
452
    char message [256];
453
  
454
    sprintf (message,
455
         "%s has odd offset (%u)",
456
         LookupParentCode (parentCode),
457
         (unsigned) ifdOffset);
458
           
459
    ReportWarning (message);
460
    
461
    }
462
    
463
  #endif
464
    
465
20.6k
  uint32 prev_tag_code = 0;
466
    
467
881k
  for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
468
874k
    {
469
    
470
874k
    stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
471
    
472
874k
    uint32 tagCode  = stream.Get_uint16 ();
473
874k
    uint32 tagType  = stream.Get_uint16 ();
474
    
475
    // Minolta 7D files have a bug in the EXIF block where the count
476
    // is wrong, and we run off into next IFD link.  So if abort parsing
477
    // if we get a zero code/type combinations.
478
    
479
874k
    if (tagCode == 0 && tagType == 0)
480
13.9k
      {
481
      
482
      #if qDNGValidate
483
      
484
      char message [256];
485
  
486
      sprintf (message,
487
           "%s had zero/zero tag code/type entry",
488
           LookupParentCode (parentCode));
489
           
490
      ReportWarning (message);
491
      
492
      #endif
493
      
494
13.9k
      return;
495
      
496
13.9k
      }
497
    
498
860k
    uint32 tagCount = stream.Get_uint32 ();
499
    
500
    #if qDNGValidate
501
502
      {
503
    
504
      if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote)
505
        {
506
        
507
        char message [256];
508
    
509
        sprintf (message,
510
             "%s tags are not sorted in ascending numerical order",
511
             LookupParentCode (parentCode));
512
             
513
        ReportWarning (message);
514
        
515
        }
516
        
517
      }
518
      
519
    #endif
520
      
521
860k
    prev_tag_code = tagCode;
522
    
523
860k
    uint32 tag_type_size = TagTypeSize (tagType);
524
    
525
860k
    if (tag_type_size == 0)
526
708k
      {
527
      
528
      #if qDNGValidate
529
      
530
        {
531
      
532
        char message [256];
533
    
534
        sprintf (message,
535
             "%s %s has unknown type (%u)",
536
             LookupParentCode (parentCode),
537
             LookupTagCode (parentCode, tagCode),
538
             (unsigned) tagType);
539
             
540
        ReportWarning (message);
541
               
542
        }
543
        
544
      #endif
545
           
546
708k
      continue;
547
      
548
708k
      }
549
      
550
152k
    uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
551
    
552
152k
    if (SafeUint32Mult(tagCount, tag_type_size) > 4)
553
37.6k
      {
554
      
555
37.6k
      tagOffset = stream.Get_uint32 ();
556
      
557
      #if qDNGValidate
558
      
559
        {
560
      
561
        if (!(ifdOffset & 1) && 
562
             (tagOffset & 1) &&
563
            !isMakerNote     &&
564
            parentCode != tcKodakDCRPrivateIFD &&
565
          parentCode != tcKodakKDCPrivateIFD)
566
          {
567
          
568
          char message [256];
569
    
570
          sprintf (message,
571
               "%s %s has odd data offset (%u)",
572
               LookupParentCode (parentCode),
573
               LookupTagCode (parentCode, tagCode),
574
               (unsigned) tagOffset);
575
               
576
          ReportWarning (message);
577
             
578
          }
579
          
580
        }
581
        
582
      #endif
583
        
584
37.6k
      tagOffset += offsetDelta;
585
        
586
37.6k
      stream.SetReadPosition (tagOffset);
587
      
588
37.6k
      }
589
      
590
152k
    ParseTag (host,
591
152k
          stream,
592
152k
            exif,
593
152k
          shared,
594
152k
          ifd,
595
152k
          parentCode,
596
152k
          tagCode,
597
152k
          tagType,
598
152k
          tagCount,
599
152k
          tagOffset,
600
152k
          offsetDelta);
601
      
602
152k
    }
603
    
604
6.67k
  stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
605
  
606
6.67k
  uint32 nextIFD = stream.Get_uint32 ();
607
  
608
  #if qDNGValidate
609
    
610
  if (gVerbose)
611
    {
612
    printf ("NextIFD = %u\n", (unsigned) nextIFD);
613
    }
614
    
615
  #endif
616
    
617
6.67k
  if (ifd)
618
2.43k
    {
619
2.43k
    ifd->fNextIFD = nextIFD;
620
2.43k
    }
621
    
622
  #if qDNGValidate
623
624
  if (nextIFD)
625
    {
626
    
627
    if (parentCode != 0 &&
628
        (parentCode < tcFirstChainedIFD ||
629
         parentCode > tcLastChainedIFD  ))
630
      {
631
632
      char message [256];
633
634
      sprintf (message,
635
           "%s has an unexpected non-zero NextIFD (%u)",
636
           LookupParentCode (parentCode),
637
           (unsigned) nextIFD);
638
           
639
      ReportWarning (message);
640
           
641
      }
642
643
    }
644
    
645
  if (gVerbose)
646
    {
647
    printf ("\n");
648
    }
649
650
  #endif
651
    
652
6.67k
  }
653
             
654
/*****************************************************************************/
655
656
bool dng_info::ParseMakerNoteIFD (dng_host &host,
657
                  dng_stream &stream,
658
                  uint64 ifdSize,
659
                  uint64 ifdOffset,
660
                  int64 offsetDelta,
661
                  uint64 minOffset,
662
                  uint64 maxOffset,
663
                  uint32 parentCode)
664
106
  {
665
  
666
106
  uint32 tagIndex;
667
106
  uint32 tagCode;
668
106
  uint32 tagType;
669
106
  uint32 tagCount;
670
  
671
  // Assume there is no next IFD pointer.
672
  
673
106
  fMakerNoteNextIFD = 0;
674
  
675
  // If size is too small to hold a single entry IFD, abort.
676
  
677
106
  if (ifdSize < 14)
678
3
    {
679
3
    return false;
680
3
    }
681
    
682
  // Get entry count.
683
  
684
103
  stream.SetReadPosition (ifdOffset);
685
  
686
103
  uint32 ifdEntries = stream.Get_uint16 ();
687
688
  // Make the entry count if reasonable for the MakerNote size.
689
  
690
103
  if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
691
11
    {
692
11
    return false;
693
11
    }
694
    
695
  // Scan IFD to verify all the tag types are all valid.
696
    
697
987
  for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
698
935
    {
699
    
700
935
    stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
701
    
702
935
    tagType = stream.Get_uint16 ();
703
    
704
    // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we
705
    // need to ignore them.  This was a "firmware 1.0.4" Canon 40D raw file.
706
    
707
935
    if (parentCode == tcCanonMakerNote && tagType == 0)
708
676
      {
709
676
      continue;
710
676
      }
711
    
712
259
    if (TagTypeSize (tagType) == 0)
713
40
      {
714
40
      return false;
715
40
      }
716
    
717
259
    }
718
    
719
  // OK, the IFD looks reasonable enough to parse.
720
  
721
  #if qDNGValidate
722
  
723
  if (gVerbose)
724
    {
725
    
726
    printf ("%s: Offset = %u, Entries = %u\n\n",
727
        LookupParentCode (parentCode),
728
          (unsigned) ifdOffset, 
729
          (unsigned) ifdEntries);
730
    
731
    }
732
    
733
  #endif
734
    
735
539
  for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
736
487
    {
737
    
738
487
    stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
739
    
740
487
    tagCode  = stream.Get_uint16 ();
741
487
    tagType  = stream.Get_uint16 ();
742
487
    tagCount = stream.Get_uint32 ();
743
    
744
487
    if (tagType == 0)
745
306
      {
746
306
      continue;
747
306
      }
748
    
749
181
    uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
750
    
751
181
    uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
752
    
753
181
    if (tagSize > 4)
754
124
      {
755
      
756
124
      tagOffset = stream.Get_uint32 () + offsetDelta;
757
      
758
124
      if (tagOffset           < minOffset ||
759
124
        SafeUint64Add(tagOffset, tagSize) > maxOffset)
760
89
        {
761
        
762
        // Tag data is outside the valid offset range,
763
        // so ignore this tag.
764
        
765
89
        continue;
766
        
767
89
        }
768
      
769
35
      stream.SetReadPosition (tagOffset);
770
      
771
35
      }
772
      
773
    // Olympus switched to using IFDs in version 3 makernotes.
774
    
775
92
    if (parentCode == tcOlympusMakerNote &&
776
0
      tagType == ttIFD &&
777
0
      tagCount == 1)
778
0
      {
779
      
780
0
      uint32 olympusMakerParent = 0;
781
      
782
0
      switch (tagCode)
783
0
        {
784
        
785
0
        case 8208:
786
0
          olympusMakerParent = tcOlympusMakerNote8208;
787
0
          break;
788
          
789
0
        case 8224:
790
0
          olympusMakerParent = tcOlympusMakerNote8224;
791
0
          break; 
792
      
793
0
        case 8240:
794
0
          olympusMakerParent = tcOlympusMakerNote8240;
795
0
          break; 
796
      
797
0
        case 8256:
798
0
          olympusMakerParent = tcOlympusMakerNote8256;
799
0
          break; 
800
      
801
0
        case 8272:
802
0
          olympusMakerParent = tcOlympusMakerNote8272;
803
0
          break; 
804
      
805
0
        case 12288:
806
0
          olympusMakerParent = tcOlympusMakerNote12288;
807
0
          break;
808
          
809
0
        default:
810
0
          break;
811
          
812
0
        }
813
        
814
0
      if (olympusMakerParent)
815
0
        {
816
        
817
0
        stream.SetReadPosition (tagOffset);
818
      
819
0
        uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
820
        
821
0
        if (subMakerNoteOffset >= minOffset &&
822
0
          subMakerNoteOffset <  maxOffset)
823
0
          {
824
        
825
0
          if (ParseMakerNoteIFD (host,
826
0
                       stream,
827
0
                       maxOffset - subMakerNoteOffset,
828
0
                       subMakerNoteOffset,
829
0
                       offsetDelta,
830
0
                       minOffset,
831
0
                       maxOffset,
832
0
                       olympusMakerParent))
833
0
            {
834
            
835
0
            continue;
836
            
837
0
            }
838
            
839
0
          }
840
        
841
0
        }
842
        
843
0
      stream.SetReadPosition (tagOffset);
844
      
845
0
      }
846
    
847
92
    ParseTag (host,
848
92
          stream,
849
92
          fExif.Get (),
850
92
          fShared.Get (),
851
92
          NULL,
852
92
          parentCode,
853
92
          tagCode,
854
92
          tagType,
855
92
          tagCount,
856
92
          tagOffset,
857
92
          offsetDelta);
858
      
859
92
    }
860
    
861
  // Grab next IFD pointer, for possible use.
862
  
863
52
  if (ifdSize >= 2 + ifdEntries * 12 + 4)
864
37
    {
865
    
866
37
    stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
867
    
868
37
    fMakerNoteNextIFD = stream.Get_uint32 ();
869
    
870
37
    }
871
    
872
  #if qDNGValidate
873
    
874
  if (gVerbose)
875
    {
876
    printf ("\n");
877
    }
878
    
879
  #endif
880
    
881
52
  return true;
882
    
883
52
  }
884
             
885
/*****************************************************************************/
886
887
void dng_info::ParseMakerNote (dng_host &host,
888
                 dng_stream &stream,
889
                 uint32 makerNoteCount,
890
                 uint64 makerNoteOffset,
891
                 int64 offsetDelta,
892
                 uint64 minOffset,
893
                 uint64 maxOffset)
894
215
  {
895
  
896
215
  uint8 firstBytes [16];
897
  
898
215
  memset (firstBytes, 0, sizeof (firstBytes));
899
  
900
215
  stream.SetReadPosition (makerNoteOffset);
901
  
902
215
  stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
903
215
                         makerNoteCount));
904
  
905
  // Epson MakerNote with header.
906
  
907
215
  if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
908
1
    {
909
    
910
1
    if (makerNoteCount > 8)
911
1
      {
912
    
913
1
      ParseMakerNoteIFD (host,
914
1
                 stream,
915
1
                 makerNoteCount - 8,
916
1
                     makerNoteOffset + 8,
917
1
                     offsetDelta,
918
1
                     minOffset,
919
1
                     maxOffset,
920
1
                     tcEpsonMakerNote);
921
                     
922
1
      }
923
      
924
1
    return;
925
    
926
1
    }
927
    
928
  // Fujifilm MakerNote.
929
  
930
214
  if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
931
21
    {
932
    
933
21
    stream.SetReadPosition (makerNoteOffset + 8);
934
    
935
21
    TempLittleEndian tempEndian (stream);
936
    
937
21
    uint32 ifd_offset = stream.Get_uint32 ();
938
    
939
21
    if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
940
10
      {
941
      
942
10
      ParseMakerNoteIFD (host,
943
10
                 stream,
944
10
                 makerNoteCount - ifd_offset,
945
10
                 makerNoteOffset + ifd_offset,
946
10
                 makerNoteOffset,
947
10
                 minOffset,
948
10
                 maxOffset,
949
10
                 tcFujiMakerNote);
950
      
951
10
      }
952
      
953
21
    return;
954
          
955
21
    }
956
    
957
  // Leica MakerNote for models that store entry offsets relative to the start of
958
  // the MakerNote (e.g., M9).
959
  
960
193
  if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
961
186
    (memcmp (firstBytes, "LEICA0\003\000",    8) == 0) ||
962
186
    (memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
963
185
    (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0))
964
7
    {
965
966
7
    if (makerNoteCount > 8)
967
7
      {
968
    
969
7
      ParseMakerNoteIFD (host,
970
7
                 stream,
971
7
                 makerNoteCount - 8,
972
7
                 makerNoteOffset + 8,
973
7
                 makerNoteOffset,
974
7
                 minOffset,
975
7
                 maxOffset,
976
7
                 tcLeicaMakerNote);
977
                 
978
7
      }
979
    
980
7
    return;
981
982
7
    }
983
984
  // Leica MakerNote for models that store absolute entry offsets (i.e., relative
985
  // to the start of the file, e.g., S2).
986
987
186
  if (memcmp (firstBytes, "LEICA\000\002\377", 8) == 0)
988
1
    {
989
    
990
1
    if (makerNoteCount > 8)
991
1
      {
992
    
993
1
      ParseMakerNoteIFD (host,
994
1
                 stream,
995
1
                 makerNoteCount - 8,
996
1
                 makerNoteOffset + 8,
997
1
                 offsetDelta,
998
1
                 minOffset,
999
1
                 maxOffset,
1000
1
                 tcLeicaMakerNote);
1001
                 
1002
1
      }
1003
    
1004
1
    return;
1005
    
1006
1
    }
1007
    
1008
  // Nikon version 2 MakerNote with header.
1009
  
1010
185
  if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
1011
14
    {
1012
    
1013
14
    stream.SetReadPosition (makerNoteOffset + 10);
1014
    
1015
14
    bool bigEndian = false;
1016
    
1017
14
    uint16 endianMark = stream.Get_uint16 ();
1018
    
1019
14
    if (endianMark == byteOrderMM)
1020
0
      {
1021
0
      bigEndian = true;
1022
0
      }
1023
      
1024
14
    else if (endianMark != byteOrderII)
1025
6
      {
1026
6
      return;
1027
6
      }
1028
      
1029
8
    TempBigEndian temp_endian (stream, bigEndian);
1030
    
1031
8
    uint16 magic = stream.Get_uint16 ();
1032
    
1033
8
    if (magic != 42)
1034
1
      {
1035
1
      return;
1036
1
      }
1037
      
1038
7
    uint32 ifd_offset = stream.Get_uint32 ();
1039
    
1040
7
    if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
1041
4
      {
1042
      
1043
4
      ParseMakerNoteIFD (host,
1044
4
                 stream,
1045
4
                 makerNoteCount - 10 - ifd_offset,
1046
4
                 makerNoteOffset + 10 + ifd_offset,
1047
4
                 makerNoteOffset + 10,
1048
4
                 minOffset,
1049
4
                 maxOffset,
1050
4
                 tcNikonMakerNote);
1051
      
1052
4
      }
1053
      
1054
7
    return;
1055
          
1056
7
    }
1057
    
1058
  // Newer version of Olympus MakerNote with byte order mark.
1059
  
1060
171
  if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
1061
4
    {
1062
    
1063
4
    stream.SetReadPosition (makerNoteOffset + 8);
1064
    
1065
4
    bool bigEndian = false;
1066
    
1067
4
    uint16 endianMark = stream.Get_uint16 ();
1068
    
1069
4
    if (endianMark == byteOrderMM)
1070
0
      {
1071
0
      bigEndian = true;
1072
0
      }
1073
      
1074
4
    else if (endianMark != byteOrderII)
1075
4
      {
1076
4
      return;
1077
4
      }
1078
      
1079
0
    TempBigEndian temp_endian (stream, bigEndian);
1080
    
1081
0
    uint16 version = stream.Get_uint16 ();
1082
    
1083
0
    if (version != 3)
1084
0
      {
1085
0
      return;
1086
0
      }
1087
    
1088
0
    if (makerNoteCount > 12)
1089
0
      {
1090
    
1091
0
      ParseMakerNoteIFD (host,
1092
0
                 stream,
1093
0
                 makerNoteCount - 12,
1094
0
                     makerNoteOffset + 12,
1095
0
                     makerNoteOffset,
1096
0
                     minOffset,
1097
0
                     maxOffset,
1098
0
                     tcOlympusMakerNote);
1099
                     
1100
0
      }
1101
      
1102
0
    return;
1103
    
1104
0
    }
1105
    
1106
  // Olympus MakerNote with header.
1107
  
1108
167
  if (memcmp (firstBytes, "OLYMP", 5) == 0)
1109
6
    {
1110
    
1111
6
    if (makerNoteCount > 8)
1112
5
      {
1113
    
1114
5
      ParseMakerNoteIFD (host,
1115
5
                 stream,
1116
5
                 makerNoteCount - 8,
1117
5
                     makerNoteOffset + 8,
1118
5
                     offsetDelta,
1119
5
                     minOffset,
1120
5
                     maxOffset,
1121
5
                     tcOlympusMakerNote);
1122
                     
1123
5
      }
1124
      
1125
6
    return;
1126
    
1127
6
    }
1128
    
1129
  // Panasonic MakerNote.
1130
  
1131
161
  if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
1132
1
    {
1133
    
1134
1
    if (makerNoteCount > 12)
1135
1
      {
1136
    
1137
1
      ParseMakerNoteIFD (host,
1138
1
                 stream,
1139
1
                 makerNoteCount - 12,
1140
1
                 makerNoteOffset + 12,
1141
1
                 offsetDelta,
1142
1
                 minOffset,
1143
1
                 maxOffset,
1144
1
                 tcPanasonicMakerNote);
1145
                 
1146
1
      }
1147
    
1148
1
    return;
1149
    
1150
1
    }
1151
    
1152
  // Pentax MakerNote.
1153
  
1154
160
  if (memcmp (firstBytes, "AOC", 4) == 0)
1155
7
    {
1156
    
1157
7
    if (makerNoteCount > 6)
1158
6
      {
1159
          
1160
6
      stream.SetReadPosition (makerNoteOffset + 4);
1161
      
1162
6
      bool bigEndian = stream.BigEndian ();
1163
      
1164
6
      uint16 endianMark = stream.Get_uint16 ();
1165
      
1166
6
      if (endianMark == byteOrderMM)
1167
0
        {
1168
0
        bigEndian = true;
1169
0
        }
1170
        
1171
6
      else if (endianMark == byteOrderII)
1172
0
        {
1173
0
        bigEndian = false;
1174
0
        }
1175
        
1176
6
      TempBigEndian temp_endian (stream, bigEndian);
1177
    
1178
6
      ParseMakerNoteIFD (host,
1179
6
                 stream,
1180
6
                 makerNoteCount - 6,
1181
6
                 makerNoteOffset + 6,
1182
6
                 offsetDelta,
1183
6
                 minOffset,
1184
6
                 maxOffset,
1185
6
                 tcPentaxMakerNote);
1186
      
1187
6
      }
1188
      
1189
7
    return;
1190
    
1191
7
    }
1192
          
1193
  // Ricoh MakerNote.
1194
  
1195
153
  if (memcmp (firstBytes, "RICOH", 5) == 0 ||
1196
141
    memcmp (firstBytes, "Ricoh", 5) == 0)
1197
26
    {
1198
    
1199
26
    if (makerNoteCount > 8)
1200
26
      {
1201
      
1202
26
      TempBigEndian tempEndian (stream);
1203
    
1204
26
      ParseMakerNoteIFD (host,
1205
26
                 stream,
1206
26
                 makerNoteCount - 8,
1207
26
                     makerNoteOffset + 8,
1208
26
                     offsetDelta,
1209
26
                     minOffset,
1210
26
                     maxOffset,
1211
26
                     tcRicohMakerNote);
1212
                     
1213
26
      }
1214
      
1215
26
    return;
1216
    
1217
26
    }
1218
    
1219
  // Nikon MakerNote without header.
1220
  
1221
127
  if (fExif->fMake.StartsWith ("NIKON"))
1222
3
    {
1223
    
1224
3
    ParseMakerNoteIFD (host,
1225
3
               stream,
1226
3
               makerNoteCount,
1227
3
                   makerNoteOffset,
1228
3
                   offsetDelta,
1229
3
                   minOffset,
1230
3
                   maxOffset,
1231
3
                   tcNikonMakerNote);
1232
                   
1233
3
    return;
1234
      
1235
3
    }
1236
  
1237
  // Canon MakerNote.
1238
  
1239
124
  if (fExif->fMake.StartsWith ("CANON"))
1240
39
    {
1241
    
1242
39
    ParseMakerNoteIFD (host,
1243
39
               stream,
1244
39
               makerNoteCount,
1245
39
                   makerNoteOffset,
1246
39
                   offsetDelta,
1247
39
                   minOffset,
1248
39
                   maxOffset,
1249
39
                   tcCanonMakerNote);
1250
      
1251
39
    return;
1252
    
1253
39
    }
1254
    
1255
  // Minolta MakerNote.
1256
  
1257
85
  if (fExif->fMake.StartsWith ("MINOLTA"       ) ||
1258
82
    fExif->fMake.StartsWith ("KONICA MINOLTA"))
1259
0
    {
1260
1261
0
    ParseMakerNoteIFD (host,
1262
0
               stream,
1263
0
               makerNoteCount,
1264
0
               makerNoteOffset,
1265
0
               offsetDelta,
1266
0
               minOffset,
1267
0
               maxOffset,
1268
0
               tcMinoltaMakerNote);
1269
      
1270
0
    return;
1271
    
1272
0
    }
1273
  
1274
  // Sony MakerNote.
1275
  
1276
85
  if (fExif->fMake.StartsWith ("SONY"))
1277
1
    {
1278
1279
1
    ParseMakerNoteIFD (host,
1280
1
               stream,
1281
1
               makerNoteCount,
1282
1
               makerNoteOffset,
1283
1
               offsetDelta,
1284
1
               minOffset,
1285
1
               maxOffset,
1286
1
               tcSonyMakerNote);
1287
      
1288
1
    return;
1289
    
1290
1
    }
1291
  
1292
  // Kodak MakerNote.
1293
  
1294
84
  if (fExif->fMake.StartsWith ("EASTMAN KODAK"))
1295
0
    {
1296
    
1297
0
    ParseMakerNoteIFD (host,
1298
0
               stream,
1299
0
               makerNoteCount,
1300
0
                   makerNoteOffset,
1301
0
                   offsetDelta,
1302
0
                   minOffset,
1303
0
                   maxOffset,
1304
0
                   tcKodakMakerNote);
1305
                   
1306
0
    return;
1307
      
1308
0
    }
1309
  
1310
  // Mamiya MakerNote.
1311
  
1312
84
  if (fExif->fMake.StartsWith ("Mamiya"))
1313
0
    {
1314
    
1315
0
    ParseMakerNoteIFD (host,
1316
0
               stream,
1317
0
               makerNoteCount,
1318
0
                   makerNoteOffset,
1319
0
                   offsetDelta,
1320
0
                   minOffset,
1321
0
                   maxOffset,
1322
0
                   tcMamiyaMakerNote);
1323
               
1324
    // Mamiya uses a MakerNote chain.
1325
               
1326
0
    while (fMakerNoteNextIFD)
1327
0
      {
1328
                   
1329
0
      ParseMakerNoteIFD (host,
1330
0
                 stream,
1331
0
                 makerNoteCount,
1332
0
                 offsetDelta + fMakerNoteNextIFD,
1333
0
                 offsetDelta,
1334
0
                 minOffset,
1335
0
                 maxOffset,
1336
0
                 tcMamiyaMakerNote);
1337
                 
1338
0
      }
1339
                   
1340
0
    return;
1341
      
1342
0
    }
1343
  
1344
  // Nikon MakerNote without header.
1345
  
1346
84
  if (fExif->fMake.StartsWith ("Hasselblad"))
1347
0
    {
1348
    
1349
0
    ParseMakerNoteIFD (host,
1350
0
               stream,
1351
0
               makerNoteCount,
1352
0
                   makerNoteOffset,
1353
0
                   offsetDelta,
1354
0
                   minOffset,
1355
0
                   maxOffset,
1356
0
                   tcHasselbladMakerNote);
1357
                   
1358
0
    return;
1359
      
1360
0
    }
1361
1362
  // Samsung MakerNote.
1363
1364
84
  if (fExif->fMake.StartsWith ("Samsung"))
1365
1
    {
1366
    
1367
1
    ParseMakerNoteIFD (host,
1368
1
               stream,
1369
1
               makerNoteCount,
1370
1
               makerNoteOffset,
1371
1
               makerNoteOffset,
1372
1
               minOffset,
1373
1
               maxOffset,
1374
1
               tcSamsungMakerNote);
1375
    
1376
1
    return;
1377
    
1378
1
    }
1379
  
1380
  // Casio MakerNote.
1381
  
1382
83
  if (fExif->fMake.StartsWith ("CASIO COMPUTER") &&
1383
0
    memcmp (firstBytes, "QVC\000\000\000", 6) == 0)
1384
0
    {
1385
    
1386
0
    ParseMakerNoteIFD (host,
1387
0
               stream,
1388
0
               makerNoteCount - 6,
1389
0
               makerNoteOffset + 6,
1390
0
               makerNoteOffset,
1391
0
               minOffset,
1392
0
               maxOffset,
1393
0
               tcCasioMakerNote);
1394
               
1395
0
    return;
1396
      
1397
0
    }
1398
  
1399
83
  }
1400
                     
1401
/*****************************************************************************/
1402
1403
void dng_info::ParseSonyPrivateData (dng_host & /* host */,
1404
                   dng_stream & /* stream */,
1405
                   uint64 /* count */,
1406
                   uint64 /* oldOffset */,
1407
                   uint64 /* newOffset */)
1408
0
  {
1409
  
1410
  // Sony private data is encrypted, sorry.
1411
  
1412
0
  }
1413
                     
1414
/*****************************************************************************/
1415
1416
void dng_info::ParseDNGPrivateData (dng_host &host,
1417
                  dng_stream &stream)
1418
94
  {
1419
  
1420
94
  if (fShared->fDNGPrivateDataCount < 2)
1421
3
    {
1422
3
    return;
1423
3
    }
1424
  
1425
  // DNG private data should always start with a null-terminated 
1426
  // company name, to define the format of the private data.
1427
      
1428
91
  dng_string privateName;
1429
      
1430
91
    {
1431
      
1432
91
    char buffer [64];
1433
    
1434
91
    stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
1435
  
1436
91
    uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
1437
91
                    sizeof (buffer) - 1);
1438
    
1439
91
    stream.Get (buffer, readLength);
1440
    
1441
91
    buffer [readLength] = 0;
1442
    
1443
91
    privateName.Set (buffer);
1444
    
1445
91
    }
1446
    
1447
  // Pentax is storing their MakerNote in the DNGPrivateData data.
1448
  
1449
91
  if (privateName.StartsWith ("PENTAX" ) ||
1450
87
    privateName.StartsWith ("SAMSUNG"))
1451
1
    {
1452
    
1453
    #if qDNGValidate
1454
    
1455
    if (gVerbose)
1456
      {
1457
      printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
1458
      }
1459
      
1460
    #endif
1461
1462
1
    stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
1463
    
1464
1
    bool bigEndian = stream.BigEndian ();
1465
    
1466
1
    uint16 endianMark = stream.Get_uint16 ();
1467
    
1468
1
    if (endianMark == byteOrderMM)
1469
0
      {
1470
0
      bigEndian = true;
1471
0
      }
1472
      
1473
1
    else if (endianMark == byteOrderII)
1474
0
      {
1475
0
      bigEndian = false;
1476
0
      }
1477
      
1478
1
    TempBigEndian temp_endian (stream, bigEndian);
1479
  
1480
1
    ParseMakerNoteIFD (host,
1481
1
               stream,
1482
1
               fShared->fDNGPrivateDataCount - 10,
1483
1
               fShared->fDNGPrivateDataOffset + 10,
1484
1
               fShared->fDNGPrivateDataOffset,
1485
1
               fShared->fDNGPrivateDataOffset,
1486
1
               fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
1487
1
               tcPentaxMakerNote);
1488
               
1489
1
    return;
1490
    
1491
1
    }
1492
        
1493
  // Stop parsing if this is not an Adobe format block.
1494
  
1495
90
  if (!privateName.Matches ("Adobe"))
1496
26
    {
1497
26
    return;
1498
26
    }
1499
  
1500
64
  TempBigEndian temp_order (stream);
1501
  
1502
64
  uint32 section_offset = 6;
1503
  
1504
669
  while (SafeUint32Add(section_offset, 8) < fShared->fDNGPrivateDataCount)
1505
605
    {
1506
    
1507
605
    stream.SetReadPosition (SafeUint64Add(fShared->fDNGPrivateDataOffset,
1508
605
                        section_offset));
1509
    
1510
605
    uint32 section_key   = stream.Get_uint32 ();
1511
605
    uint32 section_count = stream.Get_uint32 ();
1512
    
1513
605
    if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
1514
0
      {
1515
      
1516
      #if qDNGValidate
1517
      
1518
      if (gVerbose)
1519
        {
1520
        printf ("Found MakerNote inside DNGPrivateData\n\n");
1521
        }
1522
        
1523
      #endif
1524
        
1525
0
      uint16 order_mark = stream.Get_uint16 ();
1526
0
      int64 old_offset = stream.Get_uint32 ();
1527
1528
0
      uint32 tempSize = SafeUint32Sub(section_count, 6);
1529
      
1530
0
      AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
1531
      
1532
0
      uint64 positionInOriginalFile = stream.PositionInOriginalFile();
1533
      
1534
0
      stream.Get (tempBlock->Buffer (), tempSize);
1535
      
1536
0
      dng_stream tempStream (tempBlock->Buffer (),
1537
0
                   tempSize,
1538
0
                   positionInOriginalFile);
1539
                   
1540
0
      tempStream.SetBigEndian (order_mark == byteOrderMM);
1541
      
1542
0
      ParseMakerNote (host,
1543
0
              tempStream,
1544
0
              tempSize,
1545
0
              0,
1546
0
              0 - old_offset,
1547
0
              0,
1548
0
              tempSize);
1549
  
1550
0
      }
1551
      
1552
605
    else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
1553
0
      {
1554
      
1555
      #if qDNGValidate
1556
      
1557
      if (gVerbose)
1558
        {
1559
        printf ("Found Sony private data inside DNGPrivateData\n\n");
1560
        }
1561
        
1562
      #endif
1563
      
1564
0
      uint16 order_mark = stream.Get_uint16 ();
1565
0
      uint64 old_offset = stream.Get_uint32 ();
1566
1567
0
      uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
1568
      
1569
0
      TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
1570
      
1571
0
      ParseSonyPrivateData (host,
1572
0
                    stream,
1573
0
                  section_count - 6,
1574
0
                  old_offset,
1575
0
                  new_offset);
1576
        
1577
0
      }
1578
1579
605
    else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
1580
0
      {
1581
      
1582
      #if qDNGValidate
1583
      
1584
      if (gVerbose)
1585
        {
1586
        printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
1587
        }
1588
        
1589
      #endif
1590
      
1591
0
      uint16 order_mark = stream.Get_uint16 ();
1592
      
1593
0
      uint32 tagCount = stream.Get_uint32 ();
1594
      
1595
0
      uint64 tagOffset = stream.Position ();
1596
        
1597
0
      if (tagCount)
1598
0
        {
1599
        
1600
0
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1601
        
1602
0
        ParseTag (host,
1603
0
              stream,
1604
0
              fExif.Get (),
1605
0
              fShared.Get (),
1606
0
              NULL,
1607
0
              tcFujiRAF,
1608
0
              tcFujiHeader,
1609
0
              ttUndefined,
1610
0
              tagCount,
1611
0
              tagOffset,
1612
0
              0);
1613
              
1614
0
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1615
        
1616
0
        }
1617
      
1618
0
      tagCount = stream.Get_uint32 ();
1619
      
1620
0
      tagOffset = stream.Position ();
1621
        
1622
0
      if (tagCount)
1623
0
        {
1624
        
1625
0
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1626
        
1627
0
        ParseTag (host,
1628
0
              stream,
1629
0
              fExif.Get (),
1630
0
              fShared.Get (),
1631
0
              NULL,
1632
0
              tcFujiRAF,
1633
0
              tcFujiRawInfo1,
1634
0
              ttUndefined,
1635
0
              tagCount,
1636
0
              tagOffset,
1637
0
              0);
1638
              
1639
0
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1640
        
1641
0
        }
1642
      
1643
0
      tagCount = stream.Get_uint32 ();
1644
      
1645
0
      tagOffset = stream.Position ();
1646
        
1647
0
      if (tagCount)
1648
0
        {
1649
        
1650
0
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1651
        
1652
0
        ParseTag (host,
1653
0
              stream,
1654
0
              fExif.Get (),
1655
0
              fShared.Get (),
1656
0
              NULL,
1657
0
              tcFujiRAF,
1658
0
              tcFujiRawInfo2,
1659
0
              ttUndefined,
1660
0
              tagCount,
1661
0
              tagOffset,
1662
0
              0);
1663
              
1664
0
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1665
        
1666
0
        }
1667
      
1668
0
      }
1669
1670
605
    else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
1671
0
      {
1672
      
1673
      #if qDNGValidate
1674
      
1675
      if (gVerbose)
1676
        {
1677
        printf ("Found Contax Raw header inside DNGPrivateData\n\n");
1678
        }
1679
        
1680
      #endif
1681
      
1682
0
      uint16 order_mark = stream.Get_uint16 ();
1683
      
1684
0
      uint32 tagCount  = stream.Get_uint32 ();
1685
      
1686
0
      uint64 tagOffset = stream.Position ();
1687
        
1688
0
      if (tagCount)
1689
0
        {
1690
        
1691
0
        TempBigEndian contax_order (stream, order_mark == byteOrderMM);
1692
        
1693
0
        ParseTag (host,
1694
0
              stream,
1695
0
              fExif.Get (),
1696
0
              fShared.Get (),
1697
0
              NULL,
1698
0
              tcContaxRAW,
1699
0
              tcContaxHeader,
1700
0
              ttUndefined,
1701
0
              tagCount,
1702
0
              tagOffset,
1703
0
              0);
1704
              
1705
0
        }
1706
      
1707
0
      }
1708
      
1709
605
    else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
1710
1
      {
1711
      
1712
      #if qDNGValidate
1713
      
1714
      if (gVerbose)
1715
        {
1716
        printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
1717
        }
1718
        
1719
      #endif
1720
        
1721
1
      uint16 order_mark = stream.Get_uint16 ();
1722
1
      uint32 entries    = stream.Get_uint16 ();
1723
      
1724
1
      uint64 crwTagStart = stream.Position ();
1725
      
1726
3
      for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
1727
2
        {
1728
        
1729
2
        stream.SetReadPosition (crwTagStart);
1730
      
1731
2
        for (uint32 index = 0; index < entries; index++)
1732
0
          {
1733
          
1734
0
          uint32 tagCode = stream.Get_uint16 ();
1735
                       
1736
0
          uint32 tagCount = stream.Get_uint32 ();
1737
          
1738
0
          uint64 tagOffset = stream.Position ();
1739
          
1740
          // We need to grab the model id tag first, and then all the
1741
          // other tags.
1742
          
1743
0
          if ((parsePass == 1) == (tagCode == 0x5834))
1744
0
            {
1745
        
1746
0
            TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1747
          
1748
0
            ParseTag (host,
1749
0
                  stream,
1750
0
                  fExif.Get (),
1751
0
                  fShared.Get (),
1752
0
                  NULL,
1753
0
                  tcCanonCRW,
1754
0
                  tagCode,
1755
0
                  ttUndefined,
1756
0
                  tagCount,
1757
0
                  tagOffset,
1758
0
                  0);
1759
                  
1760
0
            }
1761
          
1762
0
          stream.SetReadPosition (tagOffset + tagCount);
1763
          
1764
0
          }
1765
          
1766
2
        }
1767
      
1768
1
      }
1769
1770
604
    else if (section_count > 4)
1771
123
      {
1772
      
1773
123
      uint32 parentCode = 0;
1774
      
1775
123
      bool code32  = false;
1776
123
      bool hasType = true;
1777
      
1778
123
      switch (section_key)
1779
123
        {
1780
        
1781
0
        case DNG_CHAR4 ('M','R','W',' '):
1782
0
          {
1783
0
          parentCode = tcMinoltaMRW;
1784
0
          code32     = true;
1785
0
          hasType    = false;
1786
0
          break;
1787
0
          }
1788
        
1789
8
        case DNG_CHAR4 ('P','a','n','o'):
1790
8
          {
1791
8
          parentCode = tcPanasonicRAW;
1792
8
          break;
1793
0
          }
1794
          
1795
0
        case DNG_CHAR4 ('L','e','a','f'):
1796
0
          {
1797
0
          parentCode = tcLeafMOS;
1798
0
          break;
1799
0
          }
1800
          
1801
0
        case DNG_CHAR4 ('K','o','d','a'):
1802
0
          {
1803
0
          parentCode = tcKodakDCRPrivateIFD;
1804
0
          break;
1805
0
          }
1806
          
1807
0
        case DNG_CHAR4 ('K','D','C',' '):
1808
0
          {
1809
0
          parentCode = tcKodakKDCPrivateIFD;
1810
0
          break;
1811
0
          }
1812
          
1813
115
        default:
1814
115
          break;
1815
          
1816
123
        }
1817
1818
123
      if (parentCode)
1819
8
        {
1820
      
1821
        #if qDNGValidate
1822
        
1823
        if (gVerbose)
1824
          {
1825
          printf ("Found %s tags inside DNGPrivateData\n\n",
1826
              LookupParentCode (parentCode));
1827
          }
1828
          
1829
        #endif
1830
        
1831
8
        uint16 order_mark = stream.Get_uint16 ();
1832
8
        uint32 entries    = stream.Get_uint16 ();
1833
        
1834
750
        for (uint32 index = 0; index < entries; index++)
1835
742
          {
1836
          
1837
0
          uint32 tagCode = code32 ? stream.Get_uint32 ()
1838
742
                      : stream.Get_uint16 ();
1839
                       
1840
740
          uint32 tagType  = hasType ? stream.Get_uint16 () 
1841
2
                        : ttUndefined;
1842
          
1843
742
          uint32 tagCount = stream.Get_uint32 ();
1844
          
1845
742
          uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
1846
          
1847
742
          uint64 tagOffset = stream.Position ();
1848
          
1849
742
          TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1850
        
1851
742
          ParseTag (host,
1852
742
                stream,
1853
742
                fExif.Get (),
1854
742
                fShared.Get (),
1855
742
                NULL,
1856
742
                parentCode,
1857
742
                tagCode,
1858
742
                tagType,
1859
742
                tagCount,
1860
742
                tagOffset,
1861
742
                0);
1862
          
1863
742
          stream.SetReadPosition (SafeUint64Add(tagOffset, tagSize));
1864
          
1865
742
          }
1866
          
1867
8
        }
1868
      
1869
123
      }
1870
    
1871
605
    section_offset = SafeUint32Add(section_offset, 8);
1872
605
    section_offset = SafeUint32Add(section_offset, section_count);
1873
    
1874
605
    if (section_offset & 1)
1875
68
      {
1876
68
      section_offset = SafeUint32Add(section_offset, 1);
1877
68
      }
1878
    
1879
605
    }
1880
    
1881
64
  }
1882
  
1883
/*****************************************************************************/
1884
1885
void dng_info::Parse (dng_host &host,
1886
            dng_stream &stream)
1887
7.07k
  {
1888
  
1889
7.07k
  fTIFFBlockOffset = stream.Position ();
1890
  
1891
7.07k
  fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
1892
  
1893
  // Check byte order indicator.
1894
  
1895
7.07k
  uint16 byteOrder = stream.Get_uint16 ();
1896
  
1897
7.07k
  if (byteOrder == byteOrderII)
1898
6.34k
    {
1899
    
1900
6.34k
    fBigEndian = false;
1901
    
1902
    #if qDNGValidate
1903
    
1904
    if (gVerbose)
1905
      {
1906
      printf ("\nUses little-endian byte order\n");
1907
      }
1908
      
1909
    #endif
1910
      
1911
6.34k
    stream.SetLittleEndian ();
1912
    
1913
6.34k
    }
1914
    
1915
728
  else if (byteOrder == byteOrderMM)
1916
728
    {
1917
1918
728
    fBigEndian = true;
1919
    
1920
    #if qDNGValidate
1921
    
1922
    if (gVerbose)
1923
      {
1924
      printf ("\nUses big-endian byte order\n");
1925
      }
1926
      
1927
    #endif
1928
      
1929
728
    stream.SetBigEndian ();
1930
    
1931
728
    }
1932
    
1933
0
  else
1934
0
    {
1935
    
1936
    #if qDNGValidate
1937
    
1938
    ReportError ("Unknown byte order");
1939
           
1940
    #endif
1941
           
1942
0
    ThrowBadFormat ();
1943
1944
0
    }
1945
    
1946
  // Check "magic number" indicator.
1947
    
1948
7.07k
  fMagic = stream.Get_uint16 ();
1949
  
1950
  #if qDNGValidate
1951
  
1952
  if (gVerbose)
1953
    {
1954
    printf ("Magic number = %u\n\n", (unsigned) fMagic);
1955
    }
1956
    
1957
  #endif
1958
  
1959
7.07k
  ValidateMagic ();
1960
  
1961
  // Parse IFD 0.
1962
  
1963
7.07k
  uint64 next_offset = stream.Get_uint32 ();
1964
  
1965
7.07k
  fExif.Reset (host.Make_dng_exif ());
1966
  
1967
7.07k
  fShared.Reset (host.Make_dng_shared ());
1968
  
1969
7.07k
  fIFD [0].Reset (host.Make_dng_ifd ());
1970
  
1971
7.07k
  ParseIFD (host,
1972
7.07k
        stream,
1973
7.07k
        fExif.Get (),
1974
7.07k
        fShared.Get (),
1975
7.07k
        fIFD [0].Get (),
1976
7.07k
        fTIFFBlockOffset + next_offset,
1977
7.07k
        fTIFFBlockOffset,
1978
7.07k
        0);
1979
          
1980
7.07k
  next_offset = fIFD [0]->fNextIFD;
1981
  
1982
7.07k
  fIFDCount = 1;
1983
  
1984
  // Parse chained IFDs.
1985
  
1986
7.29k
  while (next_offset)
1987
1.23k
    {
1988
    
1989
1.23k
    if (next_offset >= stream.Length ())
1990
765
      {
1991
      
1992
      #if qDNGValidate
1993
      
1994
        {
1995
        
1996
        ReportWarning ("Chained IFD offset past end of stream");
1997
1998
        }
1999
        
2000
      #endif
2001
      
2002
765
      break;
2003
      
2004
765
      }
2005
    
2006
    // Some TIFF file writers forget about the next IFD offset, so
2007
    // validate the IFD at that offset before parsing it.
2008
    
2009
471
    if (!ValidateIFD (stream,
2010
471
              fTIFFBlockOffset + next_offset,
2011
471
              fTIFFBlockOffset))
2012
233
      {
2013
      
2014
      #if qDNGValidate
2015
      
2016
        {
2017
        
2018
        ReportWarning ("Chained IFD is not valid");
2019
2020
        }
2021
        
2022
      #endif
2023
      
2024
233
      break;
2025
      
2026
233
      }
2027
2028
238
    if (fChainedIFDCount == kMaxChainedIFDs)
2029
19
      {
2030
      
2031
      #if qDNGValidate
2032
      
2033
        {
2034
        
2035
        ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
2036
2037
        }
2038
        
2039
      #endif
2040
      
2041
19
      break;
2042
      
2043
19
      }
2044
      
2045
219
    fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
2046
    
2047
219
    ParseIFD (host,
2048
219
          stream,
2049
219
          NULL,
2050
219
          NULL,
2051
219
          fChainedIFD [fChainedIFDCount].Get (),
2052
219
          fTIFFBlockOffset + next_offset,
2053
219
          fTIFFBlockOffset,
2054
219
          tcFirstChainedIFD + fChainedIFDCount);
2055
                         
2056
219
    next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
2057
    
2058
219
    fChainedIFDCount++;
2059
    
2060
219
    }
2061
    
2062
  // Parse SubIFDs.
2063
  
2064
7.07k
  uint32 searchedIFDs = 0;
2065
  
2066
7.07k
  bool tooManySubIFDs = false;
2067
  
2068
19.9k
  while (searchedIFDs < fIFDCount && !tooManySubIFDs)
2069
12.9k
    {
2070
    
2071
12.9k
    uint32 searchLimit = fIFDCount;
2072
    
2073
12.9k
    for (uint32 searchIndex = searchedIFDs;
2074
27.2k
       searchIndex < searchLimit && !tooManySubIFDs;
2075
14.3k
       searchIndex++)
2076
14.3k
      {
2077
      
2078
14.3k
      for (uint32 subIndex = 0;
2079
27.1k
           subIndex < fIFD [searchIndex]->fSubIFDsCount;
2080
12.8k
           subIndex++)
2081
13.3k
        {
2082
        
2083
13.3k
        if (fIFDCount == kMaxSubIFDs + 1)
2084
566
          {
2085
          
2086
566
          tooManySubIFDs = true;
2087
          
2088
566
          break;
2089
          
2090
566
          }
2091
        
2092
12.8k
        stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
2093
12.8k
                    subIndex * 4);
2094
        
2095
12.8k
        uint32 sub_ifd_offset = stream.Get_uint32 ();
2096
        
2097
12.8k
        fIFD [fIFDCount].Reset (host.Make_dng_ifd ());
2098
        
2099
12.8k
        ParseIFD (host,
2100
12.8k
              stream,
2101
12.8k
              fExif.Get (),
2102
12.8k
              fShared.Get (),
2103
12.8k
              fIFD [fIFDCount].Get (),
2104
12.8k
              fTIFFBlockOffset + sub_ifd_offset,
2105
12.8k
              fTIFFBlockOffset,
2106
12.8k
              tcFirstSubIFD + fIFDCount - 1);
2107
        
2108
12.8k
        fIFDCount++;
2109
          
2110
12.8k
        }
2111
                  
2112
14.3k
      searchedIFDs = searchLimit;
2113
      
2114
14.3k
      }
2115
    
2116
12.9k
    }
2117
    
2118
  #if qDNGValidate
2119
2120
    {
2121
    
2122
    if (tooManySubIFDs)
2123
      {
2124
      
2125
      ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
2126
2127
      }
2128
    
2129
    }
2130
    
2131
  #endif
2132
    
2133
  // Parse EXIF IFD.
2134
    
2135
7.07k
  if (fShared->fExifIFD)
2136
110
    {
2137
    
2138
110
    ParseIFD (host,
2139
110
          stream,
2140
110
          fExif.Get (),
2141
110
          fShared.Get (),
2142
110
          NULL,
2143
110
          fTIFFBlockOffset + fShared->fExifIFD,
2144
110
          fTIFFBlockOffset,
2145
110
          tcExifIFD);
2146
    
2147
110
    }
2148
2149
  // Parse GPS IFD.
2150
    
2151
7.07k
  if (fShared->fGPSInfo)
2152
426
    {
2153
    
2154
426
    ParseIFD (host,
2155
426
          stream,
2156
426
          fExif.Get (),
2157
426
          fShared.Get (),
2158
426
          NULL,
2159
426
          fTIFFBlockOffset + fShared->fGPSInfo,
2160
426
          fTIFFBlockOffset,
2161
426
          tcGPSInfo);
2162
    
2163
426
    }
2164
2165
  // Parse Interoperability IFD.
2166
    
2167
7.07k
  if (fShared->fInteroperabilityIFD)
2168
21
    {
2169
    
2170
    // Some Kodak KDC files have bogus Interoperability IFDs, so
2171
    // validate the IFD before trying to parse it.
2172
    
2173
21
    if (ValidateIFD (stream,
2174
21
             fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2175
21
             fTIFFBlockOffset))
2176
2
      {
2177
    
2178
2
      ParseIFD (host,
2179
2
            stream,
2180
2
            fExif.Get (),
2181
2
            fShared.Get (),
2182
2
            NULL,
2183
2
            fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2184
2
            fTIFFBlockOffset,
2185
2
            tcInteroperabilityIFD);
2186
            
2187
2
      }
2188
      
2189
    #if qDNGValidate
2190
    
2191
    else
2192
      {
2193
      
2194
      ReportWarning ("The Interoperability IFD is not a valid IFD");
2195
    
2196
      }
2197
      
2198
    #endif
2199
               
2200
21
    }
2201
2202
  // Parse Kodak DCR Private IFD.
2203
    
2204
7.07k
  if (fShared->fKodakDCRPrivateIFD)
2205
5
    {
2206
    
2207
5
    ParseIFD (host,
2208
5
          stream,
2209
5
          fExif.Get (),
2210
5
          fShared.Get (),
2211
5
          NULL,
2212
5
          fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
2213
5
          fTIFFBlockOffset,
2214
5
          tcKodakDCRPrivateIFD);
2215
    
2216
5
    }
2217
2218
  // Parse Kodak KDC Private IFD.
2219
    
2220
7.07k
  if (fShared->fKodakKDCPrivateIFD)
2221
14
    {
2222
    
2223
14
    ParseIFD (host,
2224
14
          stream,
2225
14
          fExif.Get (),
2226
14
          fShared.Get (),
2227
14
          NULL,
2228
14
          fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
2229
14
          fTIFFBlockOffset,
2230
14
          tcKodakKDCPrivateIFD);
2231
    
2232
14
    }
2233
2234
  // Parse MakerNote tag.
2235
  
2236
7.07k
  if (fShared->fMakerNoteCount)
2237
215
    {
2238
    
2239
215
    ParseMakerNote (host,
2240
215
            stream,
2241
215
            (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
2242
215
            fShared->fMakerNoteOffset,
2243
215
            fTIFFBlockOffset,
2244
215
            0,
2245
215
            stream.Length ());
2246
    
2247
215
    }
2248
2249
  // Parse DNGPrivateData tag.
2250
  
2251
7.07k
  if (fShared->fDNGPrivateDataCount &&
2252
137
    fShared->fDNGVersion)
2253
94
    {
2254
    
2255
94
    ParseDNGPrivateData (host, stream);
2256
        
2257
94
    }
2258
2259
  #if qDNGValidate
2260
  
2261
  // If we are running dng_validate on stand-alone camera profile file,
2262
  // complete the validation of the profile.
2263
  
2264
  if (fMagic == magicExtendedProfile)
2265
    {
2266
    
2267
    dng_camera_profile_info &profileInfo = fShared->fCameraProfile;
2268
    
2269
    dng_camera_profile profile;
2270
    
2271
    profile.Parse (stream, profileInfo);
2272
    
2273
    if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes))
2274
      {
2275
      
2276
      ReportError ("Invalid camera profile file");
2277
    
2278
      }
2279
      
2280
    }
2281
    
2282
  #endif
2283
    
2284
7.07k
  }
2285
  
2286
/*****************************************************************************/
2287
2288
void dng_info::PostParse (dng_host &host)
2289
2.83k
  {
2290
  
2291
2.83k
  uint32 index;
2292
  
2293
2.83k
  fExif->PostParse (host, *fShared.Get ());
2294
  
2295
2.83k
  fShared->PostParse (host, *fExif.Get ());
2296
  
2297
17.6k
  for (index = 0; index < fIFDCount; index++)
2298
14.7k
    {
2299
    
2300
14.7k
    fIFD [index]->PostParse ();
2301
    
2302
14.7k
    }
2303
    
2304
2.99k
  for (index = 0; index < fChainedIFDCount; index++)
2305
162
    {
2306
    
2307
162
    fChainedIFD [index]->PostParse ();
2308
    
2309
162
    }
2310
    
2311
2.83k
  if (fShared->fDNGVersion != 0)
2312
386
    {
2313
  
2314
    // Find main IFD.
2315
    
2316
386
    fMainIndex = -1;
2317
    
2318
1.32k
    for (index = 0; index < fIFDCount; index++)
2319
939
      {
2320
      
2321
939
      if (fIFD [index]->fUsesNewSubFileType &&
2322
208
        fIFD [index]->fNewSubFileType == sfMainImage)
2323
85
        {
2324
        
2325
85
        if (fMainIndex == -1)
2326
16
          {
2327
          
2328
16
          fMainIndex = index;
2329
          
2330
16
          }
2331
          
2332
        #if qDNGValidate
2333
          
2334
        else
2335
          {
2336
2337
          ReportError ("Multiple IFDs marked as main image");
2338
          
2339
          }
2340
          
2341
        #endif
2342
            
2343
85
        }
2344
        
2345
854
      else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
2346
850
           fIFD [index]->fNewSubFileType == sfAltPreviewImage)
2347
4
        {
2348
        
2349
        // Fill in default color space for DNG previews if not included.
2350
        
2351
4
        if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
2352
4
          {
2353
          
2354
4
          if (fIFD [index]->fSamplesPerPixel == 1)
2355
4
            {
2356
            
2357
4
            fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
2358
            
2359
4
            }
2360
            
2361
0
          else
2362
0
            {
2363
            
2364
0
            fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
2365
            
2366
0
            }
2367
          
2368
4
          }
2369
          
2370
4
        }
2371
        
2372
939
      }
2373
      
2374
    // Deal with lossless JPEG bug in early DNG versions.
2375
    
2376
386
    if (fShared->fDNGVersion < dngVersion_1_1_0_0)
2377
118
      {
2378
      
2379
118
      if (fMainIndex != -1)
2380
9
        {
2381
        
2382
9
        fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
2383
        
2384
9
        }
2385
        
2386
118
      }
2387
      
2388
    // Find mask index.
2389
    
2390
1.32k
    for (index = 0; index < fIFDCount; index++)
2391
939
      {
2392
      
2393
939
      if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
2394
52
        {
2395
        
2396
52
        if (fMaskIndex == -1)
2397
5
          {
2398
          
2399
5
          fMaskIndex = index;
2400
          
2401
5
          }
2402
          
2403
        #if qDNGValidate
2404
          
2405
        else
2406
          {
2407
2408
          ReportError ("Multiple IFDs marked as transparency mask image");
2409
          
2410
          }
2411
          
2412
        #endif
2413
            
2414
52
        }
2415
        
2416
939
      }
2417
      
2418
    // Warn about Chained IFDs.
2419
      
2420
    #if qDNGValidate
2421
          
2422
    if (fChainedIFDCount > 0)
2423
      {
2424
      
2425
      ReportWarning ("This file has Chained IFDs, which will be ignored by DNG readers");
2426
      
2427
      }
2428
      
2429
    #endif
2430
    
2431
386
    }
2432
    
2433
2.83k
  }
2434
  
2435
/*****************************************************************************/
2436
2437
bool dng_info::IsValidDNG ()
2438
2.81k
  {
2439
  
2440
  // Check shared info.
2441
  
2442
2.81k
  if (!fShared->IsValidDNG ())
2443
2.44k
    {
2444
    
2445
2.44k
    return false;
2446
    
2447
2.44k
    }
2448
  
2449
  // Check TIFF magic number.
2450
    
2451
376
  if (fMagic != 42)
2452
0
    {
2453
    
2454
    #if qDNGValidate
2455
    
2456
    ReportError ("Invalid TIFF magic number");
2457
           
2458
    #endif
2459
           
2460
0
    return false;
2461
      
2462
0
    }
2463
2464
  // Make sure we have a main image IFD.
2465
    
2466
376
  if (fMainIndex == -1)
2467
116
    {
2468
    
2469
    #if qDNGValidate
2470
    
2471
    ReportError ("Unable to find main image IFD");
2472
           
2473
    #endif
2474
           
2475
116
    return false;
2476
           
2477
116
    }
2478
    
2479
  // Make sure is each IFD is valid.
2480
  
2481
261
  for (uint32 index = 0; index < fIFDCount; index++)
2482
12
    {
2483
    
2484
11
    uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
2485
    
2486
12
    if (!fIFD [index]->IsValidDNG (*fShared.Get (),
2487
12
                       parentCode))
2488
12
      {
2489
      
2490
      // Only errors in the main and transparency mask IFDs are fatal to parsing.
2491
      
2492
12
      if (index == (uint32) fMainIndex ||
2493
1
        index == (uint32) fMaskIndex)
2494
11
        {
2495
        
2496
11
        return false;
2497
        
2498
11
        }
2499
      
2500
12
      }
2501
    
2502
12
    }
2503
      
2504
249
  return true;
2505
  
2506
260
  }
2507
2508
/*****************************************************************************/