Coverage Report

Created: 2026-07-16 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_info.cpp
Line
Count
Source
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
111k
  : fTIFFBlockOffset         (0)
34
111k
  , fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
35
111k
  , fBigEndian         (false)
36
111k
  , fMagic           (0)
37
111k
  , fExif          ()
38
111k
  , fShared          ()
39
111k
  , fMainIndex         (-1)
40
111k
  , fMaskIndex         (-1)
41
111k
  , fIFDCount        (0)
42
111k
  , fChainedIFDCount     (0)
43
111k
  , fMakerNoteNextIFD    (0)
44
  
45
111k
  {
46
  
47
111k
  }
48
  
49
/*****************************************************************************/
50
51
dng_info::~dng_info ()
52
111k
  {
53
  
54
111k
  }
55
56
/*****************************************************************************/
57
58
void dng_info::ValidateMagic ()
59
110k
  {
60
  
61
110k
  switch (fMagic)
62
110k
    {
63
    
64
92.5k
    case magicTIFF:
65
98.5k
    case magicExtendedProfile:
66
98.8k
    case magicRawCache:
67
108k
    case magicPanasonic:
68
108k
    case magicOlympusA:
69
110k
    case magicOlympusB:
70
110k
      {
71
      
72
110k
      return;
73
      
74
108k
      }
75
      
76
561
    default:
77
561
      {
78
      
79
      #if qDNGValidate
80
      
81
      ReportError ("Invalid TIFF magic number");
82
      
83
      #endif
84
      
85
561
      ThrowBadFormat ();
86
      
87
561
      }
88
      
89
110k
    }
90
  
91
110k
  }
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
5.66M
  {
107
  
108
5.66M
  bool isSubIFD = parentCode >= tcFirstSubIFD &&
109
3.18M
          parentCode <= tcLastSubIFD;
110
            
111
5.66M
  bool isMainIFD = (parentCode == 0 || isSubIFD) &&
112
4.78M
           ifd &&
113
4.78M
           ifd->fUsesNewSubFileType &&
114
2.62M
           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
5.66M
  if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
123
98.7k
                      (tagCode >= 280 && tagCode <= 283)))
124
8.06k
    {
125
    
126
8.06k
    parentCode = tcPanasonicRAW;
127
    
128
8.06k
    ifd = NULL;
129
    
130
8.06k
    }
131
  
132
5.66M
  stream.SetReadPosition (tagOffset);
133
    
134
5.66M
  if (ifd && ifd->ParseTag (stream,
135
4.79M
                parentCode,
136
4.79M
                tagCode,
137
4.79M
                tagType,
138
4.79M
                tagCount,
139
4.79M
                tagOffset))
140
2.36M
    {
141
    
142
2.36M
    return;
143
    
144
2.36M
    }
145
    
146
3.29M
  stream.SetReadPosition (tagOffset);
147
    
148
3.29M
  if (exif && shared && exif->ParseTag (stream,
149
3.29M
                      *shared,
150
3.29M
                      parentCode,
151
3.29M
                      isMainIFD,
152
3.29M
                      tagCode,
153
3.29M
                      tagType,
154
3.29M
                      tagCount,
155
3.29M
                      tagOffset))
156
465k
    {
157
    
158
465k
    return;
159
    
160
465k
    }
161
    
162
2.83M
  stream.SetReadPosition (tagOffset);
163
    
164
2.83M
  if (shared && exif && shared->ParseTag (stream,
165
2.82M
                      *exif,
166
2.82M
                        parentCode,
167
2.82M
                        isMainIFD,
168
2.82M
                        tagCode,
169
2.82M
                        tagType,
170
2.82M
                        tagCount,
171
2.82M
                        tagOffset,
172
2.82M
                        offsetDelta))
173
592k
    {
174
    
175
592k
    return;
176
    
177
592k
    }
178
179
2.23M
  if (parentCode == tcLeicaMakerNote &&
180
530
    tagType == ttUndefined &&
181
350
    tagCount >= 14)
182
315
    {
183
    
184
315
    if (ParseMakerNoteIFD (host,
185
315
                 stream,
186
315
                 tagCount,
187
315
                 tagOffset,
188
315
                 offsetDelta,
189
315
                 tagOffset,
190
315
                 stream.Length (),
191
315
                 tcLeicaMakerNote))
192
74
      {
193
        
194
74
      return;
195
        
196
74
      }
197
    
198
315
    }
199
    
200
2.23M
  if (parentCode == tcOlympusMakerNote &&
201
2.12k
    tagType == ttUndefined &&
202
963
    tagCount >= 14)
203
896
    {
204
    
205
896
    uint32 olympusMakerParent = 0;
206
    
207
896
    switch (tagCode)
208
896
      {
209
      
210
69
      case 8208:
211
69
        olympusMakerParent = tcOlympusMakerNote8208;
212
69
        break;
213
        
214
78
      case 8224:
215
78
        olympusMakerParent = tcOlympusMakerNote8224;
216
78
        break; 
217
    
218
87
      case 8240:
219
87
        olympusMakerParent = tcOlympusMakerNote8240;
220
87
        break; 
221
    
222
285
      case 8256:
223
285
        olympusMakerParent = tcOlympusMakerNote8256;
224
285
        break; 
225
    
226
58
      case 8272:
227
58
        olympusMakerParent = tcOlympusMakerNote8272;
228
58
        break; 
229
    
230
60
      case 12288:
231
60
        olympusMakerParent = tcOlympusMakerNote12288;
232
60
        break;
233
        
234
259
      default:
235
259
        break;
236
        
237
896
      }
238
      
239
896
    if (olympusMakerParent)
240
637
      {
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
637
      if (ParseMakerNoteIFD (host,
246
637
                   stream,
247
637
                     stream.Length () - tagOffset,
248
637
                         tagOffset,
249
637
                         offsetDelta,
250
637
                         tagOffset,
251
637
                         stream.Length (),
252
637
                         olympusMakerParent))
253
346
        {
254
        
255
346
        return;
256
        
257
346
        }
258
      
259
637
      }
260
      
261
896
    }
262
263
2.23M
  if (parentCode == tcRicohMakerNote &&
264
1.73k
    tagCode == 0x2001 &&
265
8
    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
2.23M
  }
335
336
/*****************************************************************************/
337
338
bool dng_info::ValidateIFD (dng_stream &stream,
339
                uint64 ifdOffset,
340
                int64 offsetDelta)
341
10.7k
  {
342
  
343
  // Make sure we have a count.
344
  
345
10.7k
  if (ifdOffset + 2 > stream.Length ())
346
438
    {
347
438
    return false;
348
438
    }
349
    
350
  // Get entry count.
351
    
352
10.3k
  stream.SetReadPosition (ifdOffset);
353
  
354
10.3k
  uint32 ifdEntries = stream.Get_uint16 ();
355
  
356
10.3k
  if (ifdEntries < 1)
357
844
    {
358
844
    return false;
359
844
    }
360
    
361
  // Make sure we have room for all entries and next IFD link.
362
    
363
9.49k
  if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
364
3.54k
    {
365
3.54k
    return false;
366
3.54k
    }
367
    
368
  // Check each entry.
369
  
370
22.6k
  for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
371
17.6k
    {
372
    
373
17.6k
    stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
374
    
375
17.6k
    stream.Skip (2);    // Ignore tag code.
376
    
377
17.6k
    uint32 tagType  = stream.Get_uint16 ();
378
17.6k
    uint32 tagCount = stream.Get_uint32 ();
379
    
380
17.6k
    uint32 tag_type_size = TagTypeSize (tagType);
381
    
382
17.6k
    if (tag_type_size == 0)
383
551
      {
384
551
      return false;
385
551
      }
386
      
387
17.1k
    uint32 tag_data_size = SafeUint32Mult(tagCount, tag_type_size);
388
            
389
17.1k
    if (tag_data_size > 4)
390
6.96k
      {
391
      
392
6.96k
      uint64 tagOffset = stream.Get_uint32 ();
393
              
394
6.96k
      tagOffset += offsetDelta;
395
      
396
6.96k
      if (SafeUint64Add(tagOffset, tag_data_size) > stream.Length())
397
405
        {
398
405
        return false;
399
405
        }
400
      
401
6.96k
      }
402
      
403
17.1k
    }
404
    
405
4.98k
  return true;
406
  
407
5.94k
  }
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
333k
  {
420
  
421
  #if qDNGValidate
422
423
  bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
424
            parentCode <= tcLastMakerNoteIFD);
425
  
426
  #endif
427
428
333k
  stream.SetReadPosition (ifdOffset);
429
  
430
333k
  if (ifd)
431
317k
    {
432
317k
    ifd->fThisIFD = ifdOffset;
433
317k
    }
434
  
435
333k
  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
333k
  uint32 prev_tag_code = 0;
466
    
467
17.7M
  for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
468
17.6M
    {
469
    
470
17.6M
    stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
471
    
472
17.6M
    uint32 tagCode  = stream.Get_uint16 ();
473
17.6M
    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
17.6M
    if (tagCode == 0 && tagType == 0)
480
229k
      {
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
229k
      return;
495
      
496
229k
      }
497
    
498
17.4M
    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
17.4M
    prev_tag_code = tagCode;
522
    
523
17.4M
    uint32 tag_type_size = TagTypeSize (tagType);
524
    
525
17.4M
    if (tag_type_size == 0)
526
12.3M
      {
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
12.3M
      continue;
547
      
548
12.3M
      }
549
      
550
5.12M
    uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
551
    
552
5.12M
    if (SafeUint32Mult(tagCount, tag_type_size) > 4)
553
2.47M
      {
554
      
555
2.47M
      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
2.47M
      tagOffset += offsetDelta;
585
        
586
2.47M
      stream.SetReadPosition (tagOffset);
587
      
588
2.47M
      }
589
      
590
5.12M
    ParseTag (host,
591
5.12M
          stream,
592
5.12M
            exif,
593
5.12M
          shared,
594
5.12M
          ifd,
595
5.12M
          parentCode,
596
5.12M
          tagCode,
597
5.12M
          tagType,
598
5.12M
          tagCount,
599
5.12M
          tagOffset,
600
5.12M
          offsetDelta);
601
      
602
5.12M
    }
603
    
604
104k
  stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
605
  
606
104k
  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
104k
  if (ifd)
618
74.0k
    {
619
74.0k
    ifd->fNextIFD = nextIFD;
620
74.0k
    }
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
104k
  }
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
15.2k
  {
665
  
666
15.2k
  uint32 tagIndex;
667
15.2k
  uint32 tagCode;
668
15.2k
  uint32 tagType;
669
15.2k
  uint32 tagCount;
670
  
671
  // Assume there is no next IFD pointer.
672
  
673
15.2k
  fMakerNoteNextIFD = 0;
674
  
675
  // If size is too small to hold a single entry IFD, abort.
676
  
677
15.2k
  if (ifdSize < 14)
678
4.32k
    {
679
4.32k
    return false;
680
4.32k
    }
681
    
682
  // Get entry count.
683
  
684
10.9k
  stream.SetReadPosition (ifdOffset);
685
  
686
10.9k
  uint32 ifdEntries = stream.Get_uint16 ();
687
688
  // Make the entry count if reasonable for the MakerNote size.
689
  
690
10.9k
  if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
691
4.98k
    {
692
4.98k
    return false;
693
4.98k
    }
694
    
695
  // Scan IFD to verify all the tag types are all valid.
696
    
697
21.8k
  for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
698
17.2k
    {
699
    
700
17.2k
    stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
701
    
702
17.2k
    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
17.2k
    if (parentCode == tcCanonMakerNote && tagType == 0)
708
1.93k
      {
709
1.93k
      continue;
710
1.93k
      }
711
    
712
15.3k
    if (TagTypeSize (tagType) == 0)
713
1.41k
      {
714
1.41k
      return false;
715
1.41k
      }
716
    
717
15.3k
    }
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
18.7k
  for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
736
14.1k
    {
737
    
738
14.1k
    stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
739
    
740
14.1k
    tagCode  = stream.Get_uint16 ();
741
14.1k
    tagType  = stream.Get_uint16 ();
742
14.1k
    tagCount = stream.Get_uint32 ();
743
    
744
14.1k
    if (tagType == 0)
745
1.39k
      {
746
1.39k
      continue;
747
1.39k
      }
748
    
749
12.7k
    uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
750
    
751
12.7k
    uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
752
    
753
12.7k
    if (tagSize > 4)
754
8.96k
      {
755
      
756
8.96k
      tagOffset = stream.Get_uint32 () + offsetDelta;
757
      
758
8.96k
      if (tagOffset           < minOffset ||
759
8.54k
        SafeUint64Add(tagOffset, tagSize) > maxOffset)
760
6.22k
        {
761
        
762
        // Tag data is outside the valid offset range,
763
        // so ignore this tag.
764
        
765
6.22k
        continue;
766
        
767
6.22k
        }
768
      
769
2.74k
      stream.SetReadPosition (tagOffset);
770
      
771
2.74k
      }
772
      
773
    // Olympus switched to using IFDs in version 3 makernotes.
774
    
775
6.54k
    if (parentCode == tcOlympusMakerNote &&
776
2.18k
      tagType == ttIFD &&
777
684
      tagCount == 1)
778
647
      {
779
      
780
647
      uint32 olympusMakerParent = 0;
781
      
782
647
      switch (tagCode)
783
647
        {
784
        
785
53
        case 8208:
786
53
          olympusMakerParent = tcOlympusMakerNote8208;
787
53
          break;
788
          
789
191
        case 8224:
790
191
          olympusMakerParent = tcOlympusMakerNote8224;
791
191
          break; 
792
      
793
91
        case 8240:
794
91
          olympusMakerParent = tcOlympusMakerNote8240;
795
91
          break; 
796
      
797
71
        case 8256:
798
71
          olympusMakerParent = tcOlympusMakerNote8256;
799
71
          break; 
800
      
801
30
        case 8272:
802
30
          olympusMakerParent = tcOlympusMakerNote8272;
803
30
          break; 
804
      
805
30
        case 12288:
806
30
          olympusMakerParent = tcOlympusMakerNote12288;
807
30
          break;
808
          
809
181
        default:
810
181
          break;
811
          
812
647
        }
813
        
814
647
      if (olympusMakerParent)
815
466
        {
816
        
817
466
        stream.SetReadPosition (tagOffset);
818
      
819
466
        uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
820
        
821
466
        if (subMakerNoteOffset >= minOffset &&
822
458
          subMakerNoteOffset <  maxOffset)
823
130
          {
824
        
825
130
          if (ParseMakerNoteIFD (host,
826
130
                       stream,
827
130
                       maxOffset - subMakerNoteOffset,
828
130
                       subMakerNoteOffset,
829
130
                       offsetDelta,
830
130
                       minOffset,
831
130
                       maxOffset,
832
130
                       olympusMakerParent))
833
50
            {
834
            
835
50
            continue;
836
            
837
50
            }
838
            
839
130
          }
840
        
841
466
        }
842
        
843
597
      stream.SetReadPosition (tagOffset);
844
      
845
597
      }
846
    
847
6.49k
    ParseTag (host,
848
6.49k
          stream,
849
6.49k
          fExif.Get (),
850
6.49k
          fShared.Get (),
851
6.49k
          NULL,
852
6.49k
          parentCode,
853
6.49k
          tagCode,
854
6.49k
          tagType,
855
6.49k
          tagCount,
856
6.49k
          tagOffset,
857
6.49k
          offsetDelta);
858
      
859
6.49k
    }
860
    
861
  // Grab next IFD pointer, for possible use.
862
  
863
4.56k
  if (ifdSize >= 2 + ifdEntries * 12 + 4)
864
1.61k
    {
865
    
866
1.61k
    stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
867
    
868
1.61k
    fMakerNoteNextIFD = stream.Get_uint32 ();
869
    
870
1.61k
    }
871
    
872
  #if qDNGValidate
873
    
874
  if (gVerbose)
875
    {
876
    printf ("\n");
877
    }
878
    
879
  #endif
880
    
881
4.56k
  return true;
882
    
883
4.56k
  }
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
28.6k
  {
895
  
896
28.6k
  uint8 firstBytes [16];
897
  
898
28.6k
  memset (firstBytes, 0, sizeof (firstBytes));
899
  
900
28.6k
  stream.SetReadPosition (makerNoteOffset);
901
  
902
28.6k
  stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
903
28.6k
                         makerNoteCount));
904
  
905
  // Epson MakerNote with header.
906
  
907
28.6k
  if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
908
1.55k
    {
909
    
910
1.55k
    if (makerNoteCount > 8)
911
1.45k
      {
912
    
913
1.45k
      ParseMakerNoteIFD (host,
914
1.45k
                 stream,
915
1.45k
                 makerNoteCount - 8,
916
1.45k
                     makerNoteOffset + 8,
917
1.45k
                     offsetDelta,
918
1.45k
                     minOffset,
919
1.45k
                     maxOffset,
920
1.45k
                     tcEpsonMakerNote);
921
                     
922
1.45k
      }
923
      
924
1.55k
    return;
925
    
926
1.55k
    }
927
    
928
  // Fujifilm MakerNote.
929
  
930
27.1k
  if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
931
607
    {
932
    
933
607
    stream.SetReadPosition (makerNoteOffset + 8);
934
    
935
607
    TempLittleEndian tempEndian (stream);
936
    
937
607
    uint32 ifd_offset = stream.Get_uint32 ();
938
    
939
607
    if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
940
313
      {
941
      
942
313
      ParseMakerNoteIFD (host,
943
313
                 stream,
944
313
                 makerNoteCount - ifd_offset,
945
313
                 makerNoteOffset + ifd_offset,
946
313
                 makerNoteOffset,
947
313
                 minOffset,
948
313
                 maxOffset,
949
313
                 tcFujiMakerNote);
950
      
951
313
      }
952
      
953
607
    return;
954
          
955
607
    }
956
    
957
  // Leica MakerNote for models that store entry offsets relative to the start of
958
  // the MakerNote (e.g., M9).
959
  
960
26.5k
  if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
961
26.1k
    (memcmp (firstBytes, "LEICA0\003\000",    8) == 0) ||
962
25.8k
    (memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
963
25.3k
    (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0))
964
2.11k
    {
965
966
2.11k
    if (makerNoteCount > 8)
967
2.04k
      {
968
    
969
2.04k
      ParseMakerNoteIFD (host,
970
2.04k
                 stream,
971
2.04k
                 makerNoteCount - 8,
972
2.04k
                 makerNoteOffset + 8,
973
2.04k
                 makerNoteOffset,
974
2.04k
                 minOffset,
975
2.04k
                 maxOffset,
976
2.04k
                 tcLeicaMakerNote);
977
                 
978
2.04k
      }
979
    
980
2.11k
    return;
981
982
2.11k
    }
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
24.4k
  if (memcmp (firstBytes, "LEICA\000\002\377", 8) == 0)
988
281
    {
989
    
990
281
    if (makerNoteCount > 8)
991
136
      {
992
    
993
136
      ParseMakerNoteIFD (host,
994
136
                 stream,
995
136
                 makerNoteCount - 8,
996
136
                 makerNoteOffset + 8,
997
136
                 offsetDelta,
998
136
                 minOffset,
999
136
                 maxOffset,
1000
136
                 tcLeicaMakerNote);
1001
                 
1002
136
      }
1003
    
1004
281
    return;
1005
    
1006
281
    }
1007
    
1008
  // Nikon version 2 MakerNote with header.
1009
  
1010
24.1k
  if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
1011
3.68k
    {
1012
    
1013
3.68k
    stream.SetReadPosition (makerNoteOffset + 10);
1014
    
1015
3.68k
    bool bigEndian = false;
1016
    
1017
3.68k
    uint16 endianMark = stream.Get_uint16 ();
1018
    
1019
3.68k
    if (endianMark == byteOrderMM)
1020
18
      {
1021
18
      bigEndian = true;
1022
18
      }
1023
      
1024
3.66k
    else if (endianMark != byteOrderII)
1025
517
      {
1026
517
      return;
1027
517
      }
1028
      
1029
3.16k
    TempBigEndian temp_endian (stream, bigEndian);
1030
    
1031
3.16k
    uint16 magic = stream.Get_uint16 ();
1032
    
1033
3.16k
    if (magic != 42)
1034
1.04k
      {
1035
1.04k
      return;
1036
1.04k
      }
1037
      
1038
2.11k
    uint32 ifd_offset = stream.Get_uint32 ();
1039
    
1040
2.11k
    if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
1041
1.43k
      {
1042
      
1043
1.43k
      ParseMakerNoteIFD (host,
1044
1.43k
                 stream,
1045
1.43k
                 makerNoteCount - 10 - ifd_offset,
1046
1.43k
                 makerNoteOffset + 10 + ifd_offset,
1047
1.43k
                 makerNoteOffset + 10,
1048
1.43k
                 minOffset,
1049
1.43k
                 maxOffset,
1050
1.43k
                 tcNikonMakerNote);
1051
      
1052
1.43k
      }
1053
      
1054
2.11k
    return;
1055
          
1056
3.16k
    }
1057
    
1058
  // Newer version of Olympus MakerNote with byte order mark.
1059
  
1060
20.4k
  if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
1061
518
    {
1062
    
1063
518
    stream.SetReadPosition (makerNoteOffset + 8);
1064
    
1065
518
    bool bigEndian = false;
1066
    
1067
518
    uint16 endianMark = stream.Get_uint16 ();
1068
    
1069
518
    if (endianMark == byteOrderMM)
1070
9
      {
1071
9
      bigEndian = true;
1072
9
      }
1073
      
1074
509
    else if (endianMark != byteOrderII)
1075
425
      {
1076
425
      return;
1077
425
      }
1078
      
1079
93
    TempBigEndian temp_endian (stream, bigEndian);
1080
    
1081
93
    uint16 version = stream.Get_uint16 ();
1082
    
1083
93
    if (version != 3)
1084
52
      {
1085
52
      return;
1086
52
      }
1087
    
1088
41
    if (makerNoteCount > 12)
1089
32
      {
1090
    
1091
32
      ParseMakerNoteIFD (host,
1092
32
                 stream,
1093
32
                 makerNoteCount - 12,
1094
32
                     makerNoteOffset + 12,
1095
32
                     makerNoteOffset,
1096
32
                     minOffset,
1097
32
                     maxOffset,
1098
32
                     tcOlympusMakerNote);
1099
                     
1100
32
      }
1101
      
1102
41
    return;
1103
    
1104
93
    }
1105
    
1106
  // Olympus MakerNote with header.
1107
  
1108
19.9k
  if (memcmp (firstBytes, "OLYMP", 5) == 0)
1109
2.72k
    {
1110
    
1111
2.72k
    if (makerNoteCount > 8)
1112
2.46k
      {
1113
    
1114
2.46k
      ParseMakerNoteIFD (host,
1115
2.46k
                 stream,
1116
2.46k
                 makerNoteCount - 8,
1117
2.46k
                     makerNoteOffset + 8,
1118
2.46k
                     offsetDelta,
1119
2.46k
                     minOffset,
1120
2.46k
                     maxOffset,
1121
2.46k
                     tcOlympusMakerNote);
1122
                     
1123
2.46k
      }
1124
      
1125
2.72k
    return;
1126
    
1127
2.72k
    }
1128
    
1129
  // Panasonic MakerNote.
1130
  
1131
17.2k
  if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
1132
295
    {
1133
    
1134
295
    if (makerNoteCount > 12)
1135
206
      {
1136
    
1137
206
      ParseMakerNoteIFD (host,
1138
206
                 stream,
1139
206
                 makerNoteCount - 12,
1140
206
                 makerNoteOffset + 12,
1141
206
                 offsetDelta,
1142
206
                 minOffset,
1143
206
                 maxOffset,
1144
206
                 tcPanasonicMakerNote);
1145
                 
1146
206
      }
1147
    
1148
295
    return;
1149
    
1150
295
    }
1151
    
1152
  // Pentax MakerNote.
1153
  
1154
16.9k
  if (memcmp (firstBytes, "AOC", 4) == 0)
1155
808
    {
1156
    
1157
808
    if (makerNoteCount > 6)
1158
791
      {
1159
          
1160
791
      stream.SetReadPosition (makerNoteOffset + 4);
1161
      
1162
791
      bool bigEndian = stream.BigEndian ();
1163
      
1164
791
      uint16 endianMark = stream.Get_uint16 ();
1165
      
1166
791
      if (endianMark == byteOrderMM)
1167
21
        {
1168
21
        bigEndian = true;
1169
21
        }
1170
        
1171
770
      else if (endianMark == byteOrderII)
1172
326
        {
1173
326
        bigEndian = false;
1174
326
        }
1175
        
1176
791
      TempBigEndian temp_endian (stream, bigEndian);
1177
    
1178
791
      ParseMakerNoteIFD (host,
1179
791
                 stream,
1180
791
                 makerNoteCount - 6,
1181
791
                 makerNoteOffset + 6,
1182
791
                 offsetDelta,
1183
791
                 minOffset,
1184
791
                 maxOffset,
1185
791
                 tcPentaxMakerNote);
1186
      
1187
791
      }
1188
      
1189
808
    return;
1190
    
1191
808
    }
1192
          
1193
  // Ricoh MakerNote.
1194
  
1195
16.1k
  if (memcmp (firstBytes, "RICOH", 5) == 0 ||
1196
15.2k
    memcmp (firstBytes, "Ricoh", 5) == 0)
1197
9.16k
    {
1198
    
1199
9.16k
    if (makerNoteCount > 8)
1200
4.91k
      {
1201
      
1202
4.91k
      TempBigEndian tempEndian (stream);
1203
    
1204
4.91k
      ParseMakerNoteIFD (host,
1205
4.91k
                 stream,
1206
4.91k
                 makerNoteCount - 8,
1207
4.91k
                     makerNoteOffset + 8,
1208
4.91k
                     offsetDelta,
1209
4.91k
                     minOffset,
1210
4.91k
                     maxOffset,
1211
4.91k
                     tcRicohMakerNote);
1212
                     
1213
4.91k
      }
1214
      
1215
9.16k
    return;
1216
    
1217
9.16k
    }
1218
    
1219
  // Nikon MakerNote without header.
1220
  
1221
6.95k
  if (fExif->fMake.StartsWith ("NIKON"))
1222
130
    {
1223
    
1224
130
    ParseMakerNoteIFD (host,
1225
130
               stream,
1226
130
               makerNoteCount,
1227
130
                   makerNoteOffset,
1228
130
                   offsetDelta,
1229
130
                   minOffset,
1230
130
                   maxOffset,
1231
130
                   tcNikonMakerNote);
1232
                   
1233
130
    return;
1234
      
1235
130
    }
1236
  
1237
  // Canon MakerNote.
1238
  
1239
6.82k
  if (fExif->fMake.StartsWith ("CANON"))
1240
190
    {
1241
    
1242
190
    ParseMakerNoteIFD (host,
1243
190
               stream,
1244
190
               makerNoteCount,
1245
190
                   makerNoteOffset,
1246
190
                   offsetDelta,
1247
190
                   minOffset,
1248
190
                   maxOffset,
1249
190
                   tcCanonMakerNote);
1250
      
1251
190
    return;
1252
    
1253
190
    }
1254
    
1255
  // Minolta MakerNote.
1256
  
1257
6.63k
  if (fExif->fMake.StartsWith ("MINOLTA"       ) ||
1258
6.56k
    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
6.63k
  if (fExif->fMake.StartsWith ("SONY"))
1277
0
    {
1278
1279
0
    ParseMakerNoteIFD (host,
1280
0
               stream,
1281
0
               makerNoteCount,
1282
0
               makerNoteOffset,
1283
0
               offsetDelta,
1284
0
               minOffset,
1285
0
               maxOffset,
1286
0
               tcSonyMakerNote);
1287
      
1288
0
    return;
1289
    
1290
0
    }
1291
  
1292
  // Kodak MakerNote.
1293
  
1294
6.63k
  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
6.63k
  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
6.63k
  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
6.63k
  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
6.63k
  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
6.63k
  }
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
1.47k
  {
1409
  
1410
  // Sony private data is encrypted, sorry.
1411
  
1412
1.47k
  }
1413
                     
1414
/*****************************************************************************/
1415
1416
void dng_info::ParseDNGPrivateData (dng_host &host,
1417
                  dng_stream &stream)
1418
21.0k
  {
1419
  
1420
21.0k
  if (fShared->fDNGPrivateDataCount < 2)
1421
419
    {
1422
419
    return;
1423
419
    }
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
20.6k
  dng_string privateName;
1429
      
1430
20.6k
    {
1431
      
1432
20.6k
    char buffer [64];
1433
    
1434
20.6k
    stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
1435
  
1436
20.6k
    uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
1437
20.6k
                    sizeof (buffer) - 1);
1438
    
1439
20.6k
    stream.Get (buffer, readLength);
1440
    
1441
20.6k
    buffer [readLength] = 0;
1442
    
1443
20.6k
    privateName.Set (buffer);
1444
    
1445
20.6k
    }
1446
    
1447
  // Pentax is storing their MakerNote in the DNGPrivateData data.
1448
  
1449
20.6k
  if (privateName.StartsWith ("PENTAX" ) ||
1450
20.5k
    privateName.StartsWith ("SAMSUNG"))
1451
81
    {
1452
    
1453
    #if qDNGValidate
1454
    
1455
    if (gVerbose)
1456
      {
1457
      printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
1458
      }
1459
      
1460
    #endif
1461
1462
81
    stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
1463
    
1464
81
    bool bigEndian = stream.BigEndian ();
1465
    
1466
81
    uint16 endianMark = stream.Get_uint16 ();
1467
    
1468
81
    if (endianMark == byteOrderMM)
1469
2
      {
1470
2
      bigEndian = true;
1471
2
      }
1472
      
1473
79
    else if (endianMark == byteOrderII)
1474
8
      {
1475
8
      bigEndian = false;
1476
8
      }
1477
      
1478
81
    TempBigEndian temp_endian (stream, bigEndian);
1479
  
1480
81
    ParseMakerNoteIFD (host,
1481
81
               stream,
1482
81
               fShared->fDNGPrivateDataCount - 10,
1483
81
               fShared->fDNGPrivateDataOffset + 10,
1484
81
               fShared->fDNGPrivateDataOffset,
1485
81
               fShared->fDNGPrivateDataOffset,
1486
81
               fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
1487
81
               tcPentaxMakerNote);
1488
               
1489
81
    return;
1490
    
1491
81
    }
1492
        
1493
  // Stop parsing if this is not an Adobe format block.
1494
  
1495
20.5k
  if (!privateName.Matches ("Adobe"))
1496
16.7k
    {
1497
16.7k
    return;
1498
16.7k
    }
1499
  
1500
3.82k
  TempBigEndian temp_order (stream);
1501
  
1502
3.82k
  uint32 section_offset = 6;
1503
  
1504
1.43M
  while (SafeUint32Add(section_offset, 8) < fShared->fDNGPrivateDataCount)
1505
1.42M
    {
1506
    
1507
1.42M
    stream.SetReadPosition (SafeUint64Add(fShared->fDNGPrivateDataOffset,
1508
1.42M
                        section_offset));
1509
    
1510
1.42M
    uint32 section_key   = stream.Get_uint32 ();
1511
1.42M
    uint32 section_count = stream.Get_uint32 ();
1512
    
1513
1.42M
    if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
1514
24.2k
      {
1515
      
1516
      #if qDNGValidate
1517
      
1518
      if (gVerbose)
1519
        {
1520
        printf ("Found MakerNote inside DNGPrivateData\n\n");
1521
        }
1522
        
1523
      #endif
1524
        
1525
24.2k
      uint16 order_mark = stream.Get_uint16 ();
1526
24.2k
      int64 old_offset = stream.Get_uint32 ();
1527
1528
24.2k
      uint32 tempSize = SafeUint32Sub(section_count, 6);
1529
      
1530
24.2k
      AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
1531
      
1532
24.2k
      uint64 positionInOriginalFile = stream.PositionInOriginalFile();
1533
      
1534
24.2k
      stream.Get (tempBlock->Buffer (), tempSize);
1535
      
1536
24.2k
      dng_stream tempStream (tempBlock->Buffer (),
1537
24.2k
                   tempSize,
1538
24.2k
                   positionInOriginalFile);
1539
                   
1540
24.2k
      tempStream.SetBigEndian (order_mark == byteOrderMM);
1541
      
1542
24.2k
      ParseMakerNote (host,
1543
24.2k
              tempStream,
1544
24.2k
              tempSize,
1545
24.2k
              0,
1546
24.2k
              0 - old_offset,
1547
24.2k
              0,
1548
24.2k
              tempSize);
1549
  
1550
24.2k
      }
1551
      
1552
1.40M
    else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
1553
1.49k
      {
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
1.49k
      uint16 order_mark = stream.Get_uint16 ();
1565
1.49k
      uint64 old_offset = stream.Get_uint32 ();
1566
1567
1.49k
      uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
1568
      
1569
1.49k
      TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
1570
      
1571
1.49k
      ParseSonyPrivateData (host,
1572
1.49k
                    stream,
1573
1.49k
                  section_count - 6,
1574
1.49k
                  old_offset,
1575
1.49k
                  new_offset);
1576
        
1577
1.49k
      }
1578
1579
1.40M
    else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
1580
639
      {
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
639
      uint16 order_mark = stream.Get_uint16 ();
1592
      
1593
639
      uint32 tagCount = stream.Get_uint32 ();
1594
      
1595
639
      uint64 tagOffset = stream.Position ();
1596
        
1597
639
      if (tagCount)
1598
462
        {
1599
        
1600
462
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1601
        
1602
462
        ParseTag (host,
1603
462
              stream,
1604
462
              fExif.Get (),
1605
462
              fShared.Get (),
1606
462
              NULL,
1607
462
              tcFujiRAF,
1608
462
              tcFujiHeader,
1609
462
              ttUndefined,
1610
462
              tagCount,
1611
462
              tagOffset,
1612
462
              0);
1613
              
1614
462
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1615
        
1616
462
        }
1617
      
1618
639
      tagCount = stream.Get_uint32 ();
1619
      
1620
639
      tagOffset = stream.Position ();
1621
        
1622
639
      if (tagCount)
1623
318
        {
1624
        
1625
318
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1626
        
1627
318
        ParseTag (host,
1628
318
              stream,
1629
318
              fExif.Get (),
1630
318
              fShared.Get (),
1631
318
              NULL,
1632
318
              tcFujiRAF,
1633
318
              tcFujiRawInfo1,
1634
318
              ttUndefined,
1635
318
              tagCount,
1636
318
              tagOffset,
1637
318
              0);
1638
              
1639
318
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1640
        
1641
318
        }
1642
      
1643
639
      tagCount = stream.Get_uint32 ();
1644
      
1645
639
      tagOffset = stream.Position ();
1646
        
1647
639
      if (tagCount)
1648
206
        {
1649
        
1650
206
        TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1651
        
1652
206
        ParseTag (host,
1653
206
              stream,
1654
206
              fExif.Get (),
1655
206
              fShared.Get (),
1656
206
              NULL,
1657
206
              tcFujiRAF,
1658
206
              tcFujiRawInfo2,
1659
206
              ttUndefined,
1660
206
              tagCount,
1661
206
              tagOffset,
1662
206
              0);
1663
              
1664
206
        stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1665
        
1666
206
        }
1667
      
1668
639
      }
1669
1670
1.40M
    else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
1671
2.29k
      {
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
2.29k
      uint16 order_mark = stream.Get_uint16 ();
1683
      
1684
2.29k
      uint32 tagCount  = stream.Get_uint32 ();
1685
      
1686
2.29k
      uint64 tagOffset = stream.Position ();
1687
        
1688
2.29k
      if (tagCount)
1689
514
        {
1690
        
1691
514
        TempBigEndian contax_order (stream, order_mark == byteOrderMM);
1692
        
1693
514
        ParseTag (host,
1694
514
              stream,
1695
514
              fExif.Get (),
1696
514
              fShared.Get (),
1697
514
              NULL,
1698
514
              tcContaxRAW,
1699
514
              tcContaxHeader,
1700
514
              ttUndefined,
1701
514
              tagCount,
1702
514
              tagOffset,
1703
514
              0);
1704
              
1705
514
        }
1706
      
1707
2.29k
      }
1708
      
1709
1.39M
    else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
1710
863
      {
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
863
      uint16 order_mark = stream.Get_uint16 ();
1722
863
      uint32 entries    = stream.Get_uint16 ();
1723
      
1724
863
      uint64 crwTagStart = stream.Position ();
1725
      
1726
2.37k
      for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
1727
1.51k
        {
1728
        
1729
1.51k
        stream.SetReadPosition (crwTagStart);
1730
      
1731
1.09M
        for (uint32 index = 0; index < entries; index++)
1732
1.08M
          {
1733
          
1734
1.08M
          uint32 tagCode = stream.Get_uint16 ();
1735
                       
1736
1.08M
          uint32 tagCount = stream.Get_uint32 ();
1737
          
1738
1.08M
          uint64 tagOffset = stream.Position ();
1739
          
1740
          // We need to grab the model id tag first, and then all the
1741
          // other tags.
1742
          
1743
1.08M
          if ((parsePass == 1) == (tagCode == 0x5834))
1744
543k
            {
1745
        
1746
543k
            TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1747
          
1748
543k
            ParseTag (host,
1749
543k
                  stream,
1750
543k
                  fExif.Get (),
1751
543k
                  fShared.Get (),
1752
543k
                  NULL,
1753
543k
                  tcCanonCRW,
1754
543k
                  tagCode,
1755
543k
                  ttUndefined,
1756
543k
                  tagCount,
1757
543k
                  tagOffset,
1758
543k
                  0);
1759
                  
1760
543k
            }
1761
          
1762
1.08M
          stream.SetReadPosition (tagOffset + tagCount);
1763
          
1764
1.08M
          }
1765
          
1766
1.51k
        }
1767
      
1768
863
      }
1769
1770
1.39M
    else if (section_count > 4)
1771
7.54k
      {
1772
      
1773
7.54k
      uint32 parentCode = 0;
1774
      
1775
7.54k
      bool code32  = false;
1776
7.54k
      bool hasType = true;
1777
      
1778
7.54k
      switch (section_key)
1779
7.54k
        {
1780
        
1781
91
        case DNG_CHAR4 ('M','R','W',' '):
1782
91
          {
1783
91
          parentCode = tcMinoltaMRW;
1784
91
          code32     = true;
1785
91
          hasType    = false;
1786
91
          break;
1787
0
          }
1788
        
1789
31
        case DNG_CHAR4 ('P','a','n','o'):
1790
31
          {
1791
31
          parentCode = tcPanasonicRAW;
1792
31
          break;
1793
0
          }
1794
          
1795
50
        case DNG_CHAR4 ('L','e','a','f'):
1796
50
          {
1797
50
          parentCode = tcLeafMOS;
1798
50
          break;
1799
0
          }
1800
          
1801
10
        case DNG_CHAR4 ('K','o','d','a'):
1802
10
          {
1803
10
          parentCode = tcKodakDCRPrivateIFD;
1804
10
          break;
1805
0
          }
1806
          
1807
75
        case DNG_CHAR4 ('K','D','C',' '):
1808
75
          {
1809
75
          parentCode = tcKodakKDCPrivateIFD;
1810
75
          break;
1811
0
          }
1812
          
1813
7.28k
        default:
1814
7.28k
          break;
1815
          
1816
7.54k
        }
1817
1818
7.54k
      if (parentCode)
1819
257
        {
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
257
        uint16 order_mark = stream.Get_uint16 ();
1832
257
        uint32 entries    = stream.Get_uint16 ();
1833
        
1834
2.15k
        for (uint32 index = 0; index < entries; index++)
1835
1.90k
          {
1836
          
1837
1.90k
          uint32 tagCode = code32 ? stream.Get_uint32 ()
1838
1.90k
                      : stream.Get_uint16 ();
1839
                       
1840
1.90k
          uint32 tagType  = hasType ? stream.Get_uint16 () 
1841
1.90k
                        : ttUndefined;
1842
          
1843
1.90k
          uint32 tagCount = stream.Get_uint32 ();
1844
          
1845
1.90k
          uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
1846
          
1847
1.90k
          uint64 tagOffset = stream.Position ();
1848
          
1849
1.90k
          TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1850
        
1851
1.90k
          ParseTag (host,
1852
1.90k
                stream,
1853
1.90k
                fExif.Get (),
1854
1.90k
                fShared.Get (),
1855
1.90k
                NULL,
1856
1.90k
                parentCode,
1857
1.90k
                tagCode,
1858
1.90k
                tagType,
1859
1.90k
                tagCount,
1860
1.90k
                tagOffset,
1861
1.90k
                0);
1862
          
1863
1.90k
          stream.SetReadPosition (SafeUint64Add(tagOffset, tagSize));
1864
          
1865
1.90k
          }
1866
          
1867
257
        }
1868
      
1869
7.54k
      }
1870
    
1871
1.42M
    section_offset = SafeUint32Add(section_offset, 8);
1872
1.42M
    section_offset = SafeUint32Add(section_offset, section_count);
1873
    
1874
1.42M
    if (section_offset & 1)
1875
23.4k
      {
1876
23.4k
      section_offset = SafeUint32Add(section_offset, 1);
1877
23.4k
      }
1878
    
1879
1.42M
    }
1880
    
1881
3.82k
  }
1882
  
1883
/*****************************************************************************/
1884
1885
void dng_info::Parse (dng_host &host,
1886
            dng_stream &stream)
1887
111k
  {
1888
  
1889
111k
  fTIFFBlockOffset = stream.Position ();
1890
  
1891
111k
  fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
1892
  
1893
  // Check byte order indicator.
1894
  
1895
111k
  uint16 byteOrder = stream.Get_uint16 ();
1896
  
1897
111k
  if (byteOrder == byteOrderII)
1898
105k
    {
1899
    
1900
105k
    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
105k
    stream.SetLittleEndian ();
1912
    
1913
105k
    }
1914
    
1915
5.72k
  else if (byteOrder == byteOrderMM)
1916
5.39k
    {
1917
1918
5.39k
    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
5.39k
    stream.SetBigEndian ();
1930
    
1931
5.39k
    }
1932
    
1933
321
  else
1934
321
    {
1935
    
1936
    #if qDNGValidate
1937
    
1938
    ReportError ("Unknown byte order");
1939
           
1940
    #endif
1941
           
1942
321
    ThrowBadFormat ();
1943
1944
321
    }
1945
    
1946
  // Check "magic number" indicator.
1947
    
1948
111k
  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
111k
  ValidateMagic ();
1960
  
1961
  // Parse IFD 0.
1962
  
1963
111k
  uint64 next_offset = stream.Get_uint32 ();
1964
  
1965
111k
  fExif.Reset (host.Make_dng_exif ());
1966
  
1967
111k
  fShared.Reset (host.Make_dng_shared ());
1968
  
1969
111k
  fIFD [0].Reset (host.Make_dng_ifd ());
1970
  
1971
111k
  ParseIFD (host,
1972
111k
        stream,
1973
111k
        fExif.Get (),
1974
111k
        fShared.Get (),
1975
111k
        fIFD [0].Get (),
1976
111k
        fTIFFBlockOffset + next_offset,
1977
111k
        fTIFFBlockOffset,
1978
111k
        0);
1979
          
1980
111k
  next_offset = fIFD [0]->fNextIFD;
1981
  
1982
111k
  fIFDCount = 1;
1983
  
1984
  // Parse chained IFDs.
1985
  
1986
115k
  while (next_offset)
1987
22.5k
    {
1988
    
1989
22.5k
    if (next_offset >= stream.Length ())
1990
12.8k
      {
1991
      
1992
      #if qDNGValidate
1993
      
1994
        {
1995
        
1996
        ReportWarning ("Chained IFD offset past end of stream");
1997
1998
        }
1999
        
2000
      #endif
2001
      
2002
12.8k
      break;
2003
      
2004
12.8k
      }
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
9.64k
    if (!ValidateIFD (stream,
2010
9.64k
              fTIFFBlockOffset + next_offset,
2011
9.64k
              fTIFFBlockOffset))
2012
4.97k
      {
2013
      
2014
      #if qDNGValidate
2015
      
2016
        {
2017
        
2018
        ReportWarning ("Chained IFD is not valid");
2019
2020
        }
2021
        
2022
      #endif
2023
      
2024
4.97k
      break;
2025
      
2026
4.97k
      }
2027
2028
4.66k
    if (fChainedIFDCount == kMaxChainedIFDs)
2029
387
      {
2030
      
2031
      #if qDNGValidate
2032
      
2033
        {
2034
        
2035
        ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
2036
2037
        }
2038
        
2039
      #endif
2040
      
2041
387
      break;
2042
      
2043
387
      }
2044
      
2045
4.27k
    fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
2046
    
2047
4.27k
    ParseIFD (host,
2048
4.27k
          stream,
2049
4.27k
          NULL,
2050
4.27k
          NULL,
2051
4.27k
          fChainedIFD [fChainedIFDCount].Get (),
2052
4.27k
          fTIFFBlockOffset + next_offset,
2053
4.27k
          fTIFFBlockOffset,
2054
4.27k
          tcFirstChainedIFD + fChainedIFDCount);
2055
                         
2056
4.27k
    next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
2057
    
2058
4.27k
    fChainedIFDCount++;
2059
    
2060
4.27k
    }
2061
    
2062
  // Parse SubIFDs.
2063
  
2064
111k
  uint32 searchedIFDs = 0;
2065
  
2066
111k
  bool tooManySubIFDs = false;
2067
  
2068
276k
  while (searchedIFDs < fIFDCount && !tooManySubIFDs)
2069
165k
    {
2070
    
2071
165k
    uint32 searchLimit = fIFDCount;
2072
    
2073
165k
    for (uint32 searchIndex = searchedIFDs;
2074
427k
       searchIndex < searchLimit && !tooManySubIFDs;
2075
262k
       searchIndex++)
2076
262k
      {
2077
      
2078
262k
      for (uint32 subIndex = 0;
2079
466k
           subIndex < fIFD [searchIndex]->fSubIFDsCount;
2080
262k
           subIndex++)
2081
209k
        {
2082
        
2083
209k
        if (fIFDCount == kMaxSubIFDs + 1)
2084
5.85k
          {
2085
          
2086
5.85k
          tooManySubIFDs = true;
2087
          
2088
5.85k
          break;
2089
          
2090
5.85k
          }
2091
        
2092
204k
        stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
2093
204k
                    subIndex * 4);
2094
        
2095
204k
        uint32 sub_ifd_offset = stream.Get_uint32 ();
2096
        
2097
204k
        fIFD [fIFDCount].Reset (host.Make_dng_ifd ());
2098
        
2099
204k
        ParseIFD (host,
2100
204k
              stream,
2101
204k
              fExif.Get (),
2102
204k
              fShared.Get (),
2103
204k
              fIFD [fIFDCount].Get (),
2104
204k
              fTIFFBlockOffset + sub_ifd_offset,
2105
204k
              fTIFFBlockOffset,
2106
204k
              tcFirstSubIFD + fIFDCount - 1);
2107
        
2108
204k
        fIFDCount++;
2109
          
2110
204k
        }
2111
                  
2112
262k
      searchedIFDs = searchLimit;
2113
      
2114
262k
      }
2115
    
2116
165k
    }
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
111k
  if (fShared->fExifIFD)
2136
9.10k
    {
2137
    
2138
9.10k
    ParseIFD (host,
2139
9.10k
          stream,
2140
9.10k
          fExif.Get (),
2141
9.10k
          fShared.Get (),
2142
9.10k
          NULL,
2143
9.10k
          fTIFFBlockOffset + fShared->fExifIFD,
2144
9.10k
          fTIFFBlockOffset,
2145
9.10k
          tcExifIFD);
2146
    
2147
9.10k
    }
2148
2149
  // Parse GPS IFD.
2150
    
2151
111k
  if (fShared->fGPSInfo)
2152
5.17k
    {
2153
    
2154
5.17k
    ParseIFD (host,
2155
5.17k
          stream,
2156
5.17k
          fExif.Get (),
2157
5.17k
          fShared.Get (),
2158
5.17k
          NULL,
2159
5.17k
          fTIFFBlockOffset + fShared->fGPSInfo,
2160
5.17k
          fTIFFBlockOffset,
2161
5.17k
          tcGPSInfo);
2162
    
2163
5.17k
    }
2164
2165
  // Parse Interoperability IFD.
2166
    
2167
111k
  if (fShared->fInteroperabilityIFD)
2168
1.13k
    {
2169
    
2170
    // Some Kodak KDC files have bogus Interoperability IFDs, so
2171
    // validate the IFD before trying to parse it.
2172
    
2173
1.13k
    if (ValidateIFD (stream,
2174
1.13k
             fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2175
1.13k
             fTIFFBlockOffset))
2176
320
      {
2177
    
2178
320
      ParseIFD (host,
2179
320
            stream,
2180
320
            fExif.Get (),
2181
320
            fShared.Get (),
2182
320
            NULL,
2183
320
            fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2184
320
            fTIFFBlockOffset,
2185
320
            tcInteroperabilityIFD);
2186
            
2187
320
      }
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
1.13k
    }
2201
2202
  // Parse Kodak DCR Private IFD.
2203
    
2204
111k
  if (fShared->fKodakDCRPrivateIFD)
2205
93
    {
2206
    
2207
93
    ParseIFD (host,
2208
93
          stream,
2209
93
          fExif.Get (),
2210
93
          fShared.Get (),
2211
93
          NULL,
2212
93
          fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
2213
93
          fTIFFBlockOffset,
2214
93
          tcKodakDCRPrivateIFD);
2215
    
2216
93
    }
2217
2218
  // Parse Kodak KDC Private IFD.
2219
    
2220
111k
  if (fShared->fKodakKDCPrivateIFD)
2221
534
    {
2222
    
2223
534
    ParseIFD (host,
2224
534
          stream,
2225
534
          fExif.Get (),
2226
534
          fShared.Get (),
2227
534
          NULL,
2228
534
          fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
2229
534
          fTIFFBlockOffset,
2230
534
          tcKodakKDCPrivateIFD);
2231
    
2232
534
    }
2233
2234
  // Parse MakerNote tag.
2235
  
2236
111k
  if (fShared->fMakerNoteCount)
2237
4.71k
    {
2238
    
2239
4.71k
    ParseMakerNote (host,
2240
4.71k
            stream,
2241
4.71k
            (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
2242
4.71k
            fShared->fMakerNoteOffset,
2243
4.71k
            fTIFFBlockOffset,
2244
4.71k
            0,
2245
4.71k
            stream.Length ());
2246
    
2247
4.71k
    }
2248
2249
  // Parse DNGPrivateData tag.
2250
  
2251
111k
  if (fShared->fDNGPrivateDataCount &&
2252
21.3k
    fShared->fDNGVersion)
2253
21.0k
    {
2254
    
2255
21.0k
    ParseDNGPrivateData (host, stream);
2256
        
2257
21.0k
    }
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
111k
  }
2285
  
2286
/*****************************************************************************/
2287
2288
void dng_info::PostParse (dng_host &host)
2289
81.3k
  {
2290
  
2291
81.3k
  uint32 index;
2292
  
2293
81.3k
  fExif->PostParse (host, *fShared.Get ());
2294
  
2295
81.3k
  fShared->PostParse (host, *fExif.Get ());
2296
  
2297
361k
  for (index = 0; index < fIFDCount; index++)
2298
280k
    {
2299
    
2300
280k
    fIFD [index]->PostParse ();
2301
    
2302
280k
    }
2303
    
2304
85.4k
  for (index = 0; index < fChainedIFDCount; index++)
2305
4.15k
    {
2306
    
2307
4.15k
    fChainedIFD [index]->PostParse ();
2308
    
2309
4.15k
    }
2310
    
2311
81.3k
  if (fShared->fDNGVersion != 0)
2312
66.0k
    {
2313
  
2314
    // Find main IFD.
2315
    
2316
66.0k
    fMainIndex = -1;
2317
    
2318
306k
    for (index = 0; index < fIFDCount; index++)
2319
240k
      {
2320
      
2321
240k
      if (fIFD [index]->fUsesNewSubFileType &&
2322
148k
        fIFD [index]->fNewSubFileType == sfMainImage)
2323
107k
        {
2324
        
2325
107k
        if (fMainIndex == -1)
2326
60.9k
          {
2327
          
2328
60.9k
          fMainIndex = index;
2329
          
2330
60.9k
          }
2331
          
2332
        #if qDNGValidate
2333
          
2334
        else
2335
          {
2336
2337
          ReportError ("Multiple IFDs marked as main image");
2338
          
2339
          }
2340
          
2341
        #endif
2342
            
2343
107k
        }
2344
        
2345
132k
      else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
2346
114k
           fIFD [index]->fNewSubFileType == sfAltPreviewImage)
2347
20.1k
        {
2348
        
2349
        // Fill in default color space for DNG previews if not included.
2350
        
2351
20.1k
        if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
2352
16.6k
          {
2353
          
2354
16.6k
          if (fIFD [index]->fSamplesPerPixel == 1)
2355
14.7k
            {
2356
            
2357
14.7k
            fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
2358
            
2359
14.7k
            }
2360
            
2361
1.91k
          else
2362
1.91k
            {
2363
            
2364
1.91k
            fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
2365
            
2366
1.91k
            }
2367
          
2368
16.6k
          }
2369
          
2370
20.1k
        }
2371
        
2372
240k
      }
2373
      
2374
    // Deal with lossless JPEG bug in early DNG versions.
2375
    
2376
66.0k
    if (fShared->fDNGVersion < dngVersion_1_1_0_0)
2377
32.6k
      {
2378
      
2379
32.6k
      if (fMainIndex != -1)
2380
31.6k
        {
2381
        
2382
31.6k
        fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
2383
        
2384
31.6k
        }
2385
        
2386
32.6k
      }
2387
      
2388
    // Find mask index.
2389
    
2390
306k
    for (index = 0; index < fIFDCount; index++)
2391
240k
      {
2392
      
2393
240k
      if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
2394
404
        {
2395
        
2396
404
        if (fMaskIndex == -1)
2397
75
          {
2398
          
2399
75
          fMaskIndex = index;
2400
          
2401
75
          }
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
404
        }
2415
        
2416
240k
      }
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
66.0k
    }
2432
    
2433
81.3k
  }
2434
  
2435
/*****************************************************************************/
2436
2437
bool dng_info::IsValidDNG ()
2438
77.8k
  {
2439
  
2440
  // Check shared info.
2441
  
2442
77.8k
  if (!fShared->IsValidDNG ())
2443
15.1k
    {
2444
    
2445
15.1k
    return false;
2446
    
2447
15.1k
    }
2448
  
2449
  // Check TIFF magic number.
2450
    
2451
62.6k
  if (fMagic != 42)
2452
206
    {
2453
    
2454
    #if qDNGValidate
2455
    
2456
    ReportError ("Invalid TIFF magic number");
2457
           
2458
    #endif
2459
           
2460
206
    return false;
2461
      
2462
206
    }
2463
2464
  // Make sure we have a main image IFD.
2465
    
2466
62.4k
  if (fMainIndex == -1)
2467
1.24k
    {
2468
    
2469
    #if qDNGValidate
2470
    
2471
    ReportError ("Unable to find main image IFD");
2472
           
2473
    #endif
2474
           
2475
1.24k
    return false;
2476
           
2477
1.24k
    }
2478
    
2479
  // Make sure is each IFD is valid.
2480
  
2481
255k
  for (uint32 index = 0; index < fIFDCount; index++)
2482
199k
    {
2483
    
2484
199k
    uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
2485
    
2486
199k
    if (!fIFD [index]->IsValidDNG (*fShared.Get (),
2487
199k
                       parentCode))
2488
126k
      {
2489
      
2490
      // Only errors in the main and transparency mask IFDs are fatal to parsing.
2491
      
2492
126k
      if (index == (uint32) fMainIndex ||
2493
121k
        index == (uint32) fMaskIndex)
2494
5.46k
        {
2495
        
2496
5.46k
        return false;
2497
        
2498
5.46k
        }
2499
      
2500
126k
      }
2501
    
2502
199k
    }
2503
      
2504
55.7k
  return true;
2505
  
2506
61.2k
  }
2507
2508
/*****************************************************************************/