Coverage Report

Created: 2026-05-23 06:54

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