Coverage Report

Created: 2025-10-10 07:04

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