Coverage Report

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