Coverage Report

Created: 2026-02-26 06:56

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