Coverage Report

Created: 2026-09-03 06:57

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