File indexing completed on 2025-01-19 03:55:03

0001 /*****************************************************************************/
0002 // Copyright 2006-2019 Adobe Systems Incorporated
0003 // All Rights Reserved.
0004 //
0005 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
0006 // accordance with the terms of the Adobe license agreement accompanying it.
0007 /*****************************************************************************/
0008 
0009 #include "dng_info.h"
0010 
0011 #include "dng_camera_profile.h"
0012 #include "dng_exceptions.h"
0013 #include "dng_globals.h"
0014 #include "dng_host.h"
0015 #include "dng_tag_codes.h"
0016 #include "dng_parse_utils.h"
0017 #include "dng_tag_types.h"
0018 #include "dng_tag_values.h"
0019 #include "dng_utils.h"
0020 
0021 /*****************************************************************************/
0022 
0023 dng_info::dng_info ()
0024 
0025     :   fTIFFBlockOffset         (0)
0026     ,   fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
0027     ,   fBigEndian               (false)
0028     ,   fMagic                   (0)
0029     ,   fExif                    ()
0030     ,   fShared                  ()
0031     ,   fMainIndex               (-1)
0032     ,   fMaskIndex               (-1)
0033     ,   fDepthIndex              (-1)
0034     ,   fEnhancedIndex           (-1)
0035     ,   fIFD                     ()
0036     ,   fChainedIFD              ()
0037     ,   fChainedSubIFD           ()
0038     ,   fMakerNoteNextIFD        (0)
0039 
0040     {
0041 
0042     }
0043 
0044 /*****************************************************************************/
0045 
0046 dng_info::~dng_info ()
0047     {
0048 
0049     for (size_t index = 0; index < fIFD.size (); index++)
0050         {
0051 
0052         if (fIFD [index])
0053             {
0054             delete fIFD [index];
0055             fIFD [index] = NULL;
0056             }
0057 
0058         }
0059 
0060     for (size_t index2 = 0; index2 < fChainedIFD.size (); index2++)
0061         {
0062 
0063         if (fChainedIFD [index2])
0064             {
0065             delete fChainedIFD [index2];
0066             fChainedIFD [index2] = NULL;
0067             }
0068 
0069         }
0070 
0071     for (size_t index3 = 0; index3 < fChainedSubIFD.size (); index3++)
0072         {
0073 
0074         for (size_t index4 = 0; index4 < fChainedSubIFD [index3].size (); index4++)
0075             {
0076 
0077             if (fChainedSubIFD [index3] [index4])
0078                 {
0079                 delete fChainedSubIFD [index3] [index4];
0080                 fChainedSubIFD [index3] [index4] = NULL;
0081                 }
0082 
0083             }
0084 
0085         }
0086 
0087     }
0088 
0089 /*****************************************************************************/
0090 
0091 void dng_info::ValidateMagic ()
0092     {
0093 
0094     switch (fMagic)
0095         {
0096 
0097         case magicTIFF:
0098         case magicExtendedProfile:
0099         case magicRawCache:
0100         case magicPanasonic:
0101         case magicOlympusA:
0102         case magicOlympusB:
0103             {
0104 
0105             return;
0106 
0107             }
0108 
0109         default:
0110             {
0111 
0112             #if qDNGValidate
0113 
0114             ReportError ("Invalid TIFF magic number");
0115 
0116             #endif
0117 
0118             ThrowBadFormat ();
0119 
0120             }
0121 
0122         }
0123 
0124     }
0125 
0126 /*****************************************************************************/
0127 
0128 void dng_info::ParseTag (dng_host &host,
0129                          dng_stream &stream,
0130                          dng_exif *exif,
0131                          dng_shared *shared,
0132                          dng_ifd *ifd,
0133                          uint32 parentCode,
0134                          uint32 tagCode,
0135                          uint32 tagType,
0136                          uint32 tagCount,
0137                          uint64 tagOffset,
0138                          int64 offsetDelta)
0139     {
0140 
0141     bool isSubIFD = parentCode >= tcFirstSubIFD &&
0142                     parentCode <= tcLastSubIFD;
0143 
0144     bool isMainIFD = (parentCode == 0 || isSubIFD) &&
0145                      ifd &&
0146                      ifd->fUsesNewSubFileType &&
0147                      ifd->fNewSubFileType == sfMainImage;
0148 
0149     // Panasonic RAW format stores private tags using tag codes < 254 in
0150     // IFD 0.  Redirect the parsing of these tags into a logical
0151     // "PanasonicRAW" IFD.
0152 
0153     // Panasonic is starting to use some higher numbers also (280..283).
0154 
0155     if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
0156                                             (tagCode >= 280 && tagCode <= 283)))
0157         {
0158 
0159         parentCode = tcPanasonicRAW;
0160 
0161         ifd = NULL;
0162 
0163         }
0164 
0165     stream.SetReadPosition (tagOffset);
0166 
0167     if (ifd && ifd->ParseTag (stream,
0168                               parentCode,
0169                               tagCode,
0170                               tagType,
0171                               tagCount,
0172                               tagOffset))
0173         {
0174 
0175         return;
0176 
0177         }
0178 
0179     stream.SetReadPosition (tagOffset);
0180 
0181     if (exif && shared && exif->ParseTag (stream,
0182                                           *shared,
0183                                           parentCode,
0184                                           isMainIFD,
0185                                           tagCode,
0186                                           tagType,
0187                                           tagCount,
0188                                           tagOffset))
0189         {
0190 
0191         return;
0192 
0193         }
0194 
0195     stream.SetReadPosition (tagOffset);
0196 
0197     if (shared && exif && shared->ParseTag (stream,
0198                                             *exif,
0199                                             parentCode,
0200                                             isMainIFD,
0201                                             tagCode,
0202                                             tagType,
0203                                             tagCount,
0204                                             tagOffset,
0205                                             offsetDelta))
0206         {
0207 
0208         return;
0209 
0210         }
0211 
0212     if (parentCode == tcLeicaMakerNote &&
0213         tagType == ttUndefined &&
0214         tagCount >= 14)
0215         {
0216 
0217         if (ParseMakerNoteIFD (host,
0218                                stream,
0219                                tagCount,
0220                                tagOffset,
0221                                offsetDelta,
0222                                tagOffset,
0223                                stream.Length (),
0224                                tcLeicaMakerNote))
0225             {
0226 
0227             return;
0228 
0229             }
0230 
0231         }
0232 
0233     if (parentCode == tcOlympusMakerNote &&
0234         tagType == ttUndefined &&
0235         tagCount >= 14)
0236         {
0237 
0238         uint32 olympusMakerParent = 0;
0239 
0240         switch (tagCode)
0241             {
0242 
0243             case 8208:
0244                 olympusMakerParent = tcOlympusMakerNote8208;
0245                 break;
0246 
0247             case 8224:
0248                 olympusMakerParent = tcOlympusMakerNote8224;
0249                 break;
0250 
0251             case 8240:
0252                 olympusMakerParent = tcOlympusMakerNote8240;
0253                 break;
0254 
0255             case 8256:
0256                 olympusMakerParent = tcOlympusMakerNote8256;
0257                 break;
0258 
0259             case 8272:
0260                 olympusMakerParent = tcOlympusMakerNote8272;
0261                 break;
0262 
0263             case 12288:
0264                 olympusMakerParent = tcOlympusMakerNote12288;
0265                 break;
0266 
0267             default:
0268                 break;
0269 
0270             }
0271 
0272         if (olympusMakerParent)
0273             {
0274 
0275             // Olympus made a mistake in some camera models in computing
0276             // the size of these sub-tags, so we fudge the count.
0277 
0278             if (ParseMakerNoteIFD (host,
0279                                    stream,
0280                                    stream.Length () - tagOffset,
0281                                    tagOffset,
0282                                    offsetDelta,
0283                                    tagOffset,
0284                                    stream.Length (),
0285                                    olympusMakerParent))
0286                 {
0287 
0288                 return;
0289 
0290                 }
0291 
0292             }
0293 
0294         }
0295 
0296     if (parentCode == tcRicohMakerNote &&
0297         tagCode == 0x2001 &&
0298         tagType == ttUndefined &&
0299         tagCount > 22)
0300         {
0301 
0302         char header [20];
0303 
0304         stream.SetReadPosition (tagOffset);
0305 
0306         stream.Get (header, sizeof (header));
0307 
0308         if (memcmp (header, "[Ricoh Camera Info]", 19) == 0)
0309             {
0310 
0311             ParseMakerNoteIFD (host,
0312                                stream,
0313                                tagCount - 20,
0314                                tagOffset + 20,
0315                                offsetDelta,
0316                                tagOffset + 20,
0317                                tagOffset + tagCount,
0318                                tcRicohMakerNoteCameraInfo);
0319 
0320             return;
0321 
0322             }
0323 
0324         }
0325 
0326     #if qDNGValidate
0327 
0328         {
0329 
0330         stream.SetReadPosition (tagOffset);
0331 
0332         if (gVerbose)
0333             {
0334 
0335             printf ("*");
0336 
0337             DumpTagValues (stream,
0338                            LookupTagType (tagType),
0339                            parentCode,
0340                            tagCode,
0341                            tagType,
0342                            tagCount);
0343 
0344             }
0345 
0346         // If type is ASCII, then parse anyway so we report any ASCII
0347         // NULL termination or character set errors.
0348 
0349         else if (tagType == ttAscii)
0350             {
0351 
0352             dng_string s;
0353 
0354             ParseStringTag (stream,
0355                             parentCode,
0356                             tagCode,
0357                             tagCount,
0358                             s,
0359                             false);
0360 
0361             }
0362 
0363         }
0364 
0365     #endif
0366 
0367     }
0368 
0369 /*****************************************************************************/
0370 
0371 bool dng_info::ValidateIFD (dng_stream &stream,
0372                             uint64 ifdOffset,
0373                             int64 offsetDelta)
0374     {
0375 
0376     // Make sure we have a count.
0377 
0378     if (ifdOffset + 2 > stream.Length ())
0379         {
0380         return false;
0381         }
0382 
0383     // Get entry count.
0384 
0385     stream.SetReadPosition (ifdOffset);
0386 
0387     uint32 ifdEntries = stream.Get_uint16 ();
0388 
0389     if (ifdEntries < 1)
0390         {
0391         return false;
0392         }
0393 
0394     // Make sure we have room for all entries and next IFD link.
0395 
0396     if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
0397         {
0398         return false;
0399         }
0400 
0401     // Check each entry.
0402 
0403     for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
0404         {
0405 
0406         stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
0407 
0408         stream.Skip (2);        // Ignore tag code.
0409 
0410         uint32 tagType  = stream.Get_uint16 ();
0411         uint32 tagCount = stream.Get_uint32 ();
0412 
0413         uint32 tag_type_size = TagTypeSize (tagType);
0414 
0415         if (tag_type_size == 0)
0416             {
0417             return false;
0418             }
0419 
0420         uint32 tag_data_size = tagCount * tag_type_size;
0421 
0422         if (tag_data_size > 4)
0423             {
0424 
0425             uint64 tagOffset = stream.Get_uint32 ();
0426 
0427             tagOffset += offsetDelta;
0428 
0429             if (tagOffset + tag_data_size > stream.Length ())
0430                 {
0431                 return false;
0432                 }
0433 
0434             }
0435 
0436         }
0437 
0438     return true;
0439 
0440     }
0441 
0442 /*****************************************************************************/
0443 
0444 void dng_info::ParseIFD (dng_host &host,
0445                          dng_stream &stream,
0446                          dng_exif *exif,
0447                          dng_shared *shared,
0448                          dng_ifd *ifd,
0449                          uint64 ifdOffset,
0450                          int64 offsetDelta,
0451                          uint32 parentCode)
0452     {
0453 
0454     #if qDNGValidate
0455 
0456     bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
0457                         parentCode <= tcLastMakerNoteIFD);
0458 
0459     #endif
0460 
0461     // TIFF IFDs often read from two very different places in the file,
0462     // one for the IFD itself (and small tags), and elsewhere in the file
0463     // for large tags.  We can reduce the number of calls to the OS
0464     // by double buffering reads for the two areas of the file.
0465 
0466     dng_stream_double_buffered ifdStream (stream);
0467 
0468     ifdStream.SetReadPosition (ifdOffset);
0469 
0470     if (ifd)
0471         {
0472         ifd->fThisIFD = ifdOffset;
0473         }
0474 
0475     uint32 ifdEntries = ifdStream.Get_uint16 ();
0476 
0477     #if qDNGValidate
0478 
0479     // IC hits these warnings on JPG
0480     bool generateOddOffsetWarnings = true;
0481     if (gImagecore)
0482         generateOddOffsetWarnings = false;
0483 
0484     if (gVerbose)
0485         {
0486 
0487         printf ("%s: Offset = %u, Entries = %u\n\n",
0488                 LookupParentCode (parentCode),
0489                 (unsigned) ifdOffset,
0490                 (unsigned) ifdEntries);
0491 
0492         }
0493 
0494     if (generateOddOffsetWarnings && (ifdOffset & 1) && !isMakerNote)
0495         {
0496 
0497         char message [256];
0498 
0499         sprintf (message,
0500                  "%s has odd offset (%u)",
0501                  LookupParentCode (parentCode),
0502                  (unsigned) ifdOffset);
0503 
0504         ReportWarning (message);
0505 
0506         }
0507 
0508     #endif
0509 
0510     uint32 prev_tag_code = 0;
0511 
0512     for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
0513         {
0514 
0515         ifdStream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
0516 
0517         uint32 tagCode  = ifdStream.Get_uint16 ();
0518         uint32 tagType  = ifdStream.Get_uint16 ();
0519 
0520         // Minolta 7D files have a bug in the EXIF block where the count
0521         // is wrong, and we run off into next IFD link.  So if abort parsing
0522         // if we get a zero code/type combinations.
0523 
0524         if (tagCode == 0 && tagType == 0)
0525             {
0526 
0527             #if qDNGValidate
0528 
0529             char message [256];
0530 
0531             sprintf (message,
0532                      "%s had zero/zero tag code/type entry",
0533                      LookupParentCode (parentCode));
0534 
0535             ReportWarning (message);
0536 
0537             #endif
0538 
0539             return;
0540 
0541             }
0542 
0543         uint32 tagCount = ifdStream.Get_uint32 ();
0544 
0545         #if qDNGValidate
0546 
0547             {
0548 
0549             if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote)
0550                 {
0551 
0552                 char message [256];
0553 
0554                 sprintf (message,
0555                          "%s tags are not sorted in ascending numerical order",
0556                          LookupParentCode (parentCode));
0557 
0558                 ReportWarning (message);
0559 
0560                 }
0561 
0562             }
0563 
0564         #endif
0565 
0566         prev_tag_code = tagCode;
0567 
0568         uint32 tag_type_size = TagTypeSize (tagType);
0569 
0570         if (tag_type_size == 0)
0571             {
0572 
0573             #if qDNGValidate
0574 
0575                 {
0576 
0577                 char message [256];
0578 
0579                 sprintf (message,
0580                          "%s %s has unknown type (%u)",
0581                          LookupParentCode (parentCode),
0582                          LookupTagCode (parentCode, tagCode),
0583                          (unsigned) tagType);
0584 
0585                 ReportWarning (message);
0586 
0587                 }
0588 
0589             #endif
0590 
0591             continue;
0592 
0593             }
0594 
0595         bool localTag = true;
0596 
0597         uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
0598 
0599         if (tagCount * tag_type_size > 4)
0600             {
0601 
0602             tagOffset = ifdStream.Get_uint32 ();
0603 
0604             #if qDNGValidate
0605 
0606                 {
0607 
0608                 if (generateOddOffsetWarnings &&
0609                     !(ifdOffset & 1) &&
0610                      (tagOffset & 1) &&
0611                     !isMakerNote     &&
0612                     parentCode != tcKodakDCRPrivateIFD &&
0613                     parentCode != tcKodakKDCPrivateIFD)
0614                     {
0615 
0616                     char message [256];
0617 
0618                     sprintf (message,
0619                              "%s %s has odd data offset (%u)",
0620                              LookupParentCode (parentCode),
0621                              LookupTagCode (parentCode, tagCode),
0622                              (unsigned) tagOffset);
0623 
0624                     ReportWarning (message);
0625 
0626                     }
0627 
0628                 }
0629 
0630             #endif
0631 
0632             tagOffset += offsetDelta;
0633 
0634             localTag = ifdStream.DataInBuffer (tagCount * tag_type_size,
0635                                                tagOffset);
0636 
0637             if (localTag)
0638                 ifdStream.SetReadPosition (tagOffset);
0639             else
0640                 stream.SetReadPosition (tagOffset);
0641 
0642             }
0643 
0644         ParseTag (host,
0645                   localTag ? ifdStream : stream,
0646                   exif,
0647                   shared,
0648                   ifd,
0649                   parentCode,
0650                   tagCode,
0651                   tagType,
0652                   tagCount,
0653                   tagOffset,
0654                   offsetDelta);
0655 
0656         }
0657 
0658     ifdStream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
0659 
0660     uint32 nextIFD = ifdStream.Get_uint32 ();
0661 
0662     #if qDNGValidate
0663 
0664     if (gVerbose)
0665         {
0666         printf ("NextIFD = %u\n", (unsigned) nextIFD);
0667         }
0668 
0669     #endif
0670 
0671     if (ifd)
0672         {
0673         ifd->fNextIFD = nextIFD;
0674         }
0675 
0676     #if qDNGValidate
0677 
0678     if (nextIFD)
0679         {
0680 
0681         if (parentCode != 0 &&
0682                 (parentCode < tcFirstChainedIFD ||
0683                  parentCode > tcLastChainedIFD  ))
0684             {
0685 
0686             char message [256];
0687 
0688             sprintf (message,
0689                      "%s has an unexpected non-zero NextIFD (%u)",
0690                      LookupParentCode (parentCode),
0691                      (unsigned) nextIFD);
0692 
0693             ReportWarning (message);
0694 
0695             }
0696 
0697         }
0698 
0699     if (gVerbose)
0700         {
0701         printf ("\n");
0702         }
0703 
0704     stream.SetReadPosition (ifdStream.Position ());
0705 
0706     #endif
0707 
0708     }
0709 
0710 /*****************************************************************************/
0711 
0712 bool dng_info::ParseMakerNoteIFD (dng_host &host,
0713                                   dng_stream &stream,
0714                                   uint64 ifdSize,
0715                                   uint64 ifdOffset,
0716                                   int64 offsetDelta,
0717                                   uint64 minOffset,
0718                                   uint64 maxOffset,
0719                                   uint32 parentCode)
0720     {
0721 
0722     uint32 tagIndex;
0723     uint32 tagCode;
0724     uint32 tagType;
0725     uint32 tagCount;
0726 
0727     // Assume there is no next IFD pointer.
0728 
0729     fMakerNoteNextIFD = 0;
0730 
0731     // If size is too small to hold a single entry IFD, abort.
0732 
0733     if (ifdSize < 14)
0734         {
0735         return false;
0736         }
0737 
0738     // Get entry count.
0739 
0740     dng_stream_double_buffered ifdStream (stream);
0741 
0742     ifdStream.SetReadPosition (ifdOffset);
0743 
0744     uint32 ifdEntries = ifdStream.Get_uint16 ();
0745 
0746     // Make the entry count if reasonable for the MakerNote size.
0747 
0748     if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
0749         {
0750         return false;
0751         }
0752 
0753     // Scan IFD to verify all the tag types are all valid.
0754 
0755     for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
0756         {
0757 
0758         ifdStream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
0759 
0760         tagType = ifdStream.Get_uint16 ();
0761 
0762         // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we
0763         // need to ignore them.  This was a "firmware 1.0.4" Canon 40D raw file.
0764 
0765         if (parentCode == tcCanonMakerNote && tagType == 0)
0766             {
0767             continue;
0768             }
0769 
0770         if (TagTypeSize (tagType) == 0)
0771             {
0772             return false;
0773             }
0774 
0775         }
0776 
0777     // OK, the IFD looks reasonable enough to parse.
0778 
0779     #if qDNGValidate
0780 
0781     if (gVerbose)
0782         {
0783 
0784         printf ("%s: Offset = %u, Entries = %u\n\n",
0785                 LookupParentCode (parentCode),
0786                 (unsigned) ifdOffset,
0787                 (unsigned) ifdEntries);
0788 
0789         }
0790 
0791     #endif
0792 
0793     for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
0794         {
0795 
0796         ifdStream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
0797 
0798         tagCode  = ifdStream.Get_uint16 ();
0799         tagType  = ifdStream.Get_uint16 ();
0800         tagCount = ifdStream.Get_uint32 ();
0801 
0802         if (tagType == 0)
0803             {
0804             continue;
0805             }
0806 
0807         uint32 tagSize = tagCount * TagTypeSize (tagType);
0808 
0809         uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
0810 
0811         bool localTag = true;
0812 
0813         if (tagSize > 4)
0814             {
0815 
0816             tagOffset = ifdStream.Get_uint32 () + offsetDelta;
0817 
0818             if (tagOffset           < minOffset ||
0819                 tagOffset + tagSize > maxOffset)
0820                 {
0821 
0822                 // Tag data is outside the valid offset range,
0823                 // so ignore this tag.
0824 
0825                 continue;
0826 
0827                 }
0828 
0829             localTag = ifdStream.DataInBuffer (tagSize, tagOffset);
0830 
0831             ifdStream.SetReadPosition (tagOffset);
0832 
0833             stream.SetReadPosition (tagOffset);
0834 
0835             }
0836 
0837         // Olympus switched to using IFDs in version 3 makernotes.
0838 
0839         if (parentCode == tcOlympusMakerNote &&
0840             tagType == ttIFD &&
0841             tagCount == 1)
0842             {
0843 
0844             uint32 olympusMakerParent = 0;
0845 
0846             switch (tagCode)
0847                 {
0848 
0849                 case 8208:
0850                     olympusMakerParent = tcOlympusMakerNote8208;
0851                     break;
0852 
0853                 case 8224:
0854                     olympusMakerParent = tcOlympusMakerNote8224;
0855                     break;
0856 
0857                 case 8240:
0858                     olympusMakerParent = tcOlympusMakerNote8240;
0859                     break;
0860 
0861                 case 8256:
0862                     olympusMakerParent = tcOlympusMakerNote8256;
0863                     break;
0864 
0865                 case 8272:
0866                     olympusMakerParent = tcOlympusMakerNote8272;
0867                     break;
0868 
0869                 case 12288:
0870                     olympusMakerParent = tcOlympusMakerNote12288;
0871                     break;
0872 
0873                 default:
0874                     break;
0875 
0876                 }
0877 
0878             if (olympusMakerParent)
0879                 {
0880 
0881                 stream.SetReadPosition (tagOffset);
0882 
0883                 uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
0884 
0885                 if (subMakerNoteOffset >= minOffset &&
0886                     subMakerNoteOffset <  maxOffset)
0887                     {
0888 
0889                     if (ParseMakerNoteIFD (host,
0890                                            stream,
0891                                            maxOffset - subMakerNoteOffset,
0892                                            subMakerNoteOffset,
0893                                            offsetDelta,
0894                                            minOffset,
0895                                            maxOffset,
0896                                            olympusMakerParent))
0897                         {
0898 
0899                         continue;
0900 
0901                         }
0902 
0903                     }
0904 
0905                 }
0906 
0907             stream.SetReadPosition (tagOffset);
0908 
0909             }
0910 
0911         ParseTag (host,
0912                   localTag ? ifdStream : stream,
0913                   fExif.Get (),
0914                   fShared.Get (),
0915                   NULL,
0916                   parentCode,
0917                   tagCode,
0918                   tagType,
0919                   tagCount,
0920                   tagOffset,
0921                   offsetDelta);
0922 
0923         }
0924 
0925     // Grab next IFD pointer, for possible use.
0926 
0927     if (ifdSize >= 2 + ifdEntries * 12 + 4)
0928         {
0929 
0930         ifdStream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
0931 
0932         fMakerNoteNextIFD = ifdStream.Get_uint32 ();
0933 
0934         }
0935 
0936     #if qDNGValidate
0937 
0938     if (gVerbose)
0939         {
0940         printf ("\n");
0941         }
0942 
0943     #endif
0944 
0945     return true;
0946 
0947     }
0948 
0949 /*****************************************************************************/
0950 
0951 void dng_info::ParseMakerNote (dng_host &host,
0952                                dng_stream &stream,
0953                                uint32 makerNoteCount,
0954                                uint64 makerNoteOffset,
0955                                int64 offsetDelta,
0956                                uint64 minOffset,
0957                                uint64 maxOffset)
0958     {
0959 
0960     uint8 firstBytes [16];
0961 
0962     memset (firstBytes, 0, sizeof (firstBytes));
0963 
0964     stream.SetReadPosition (makerNoteOffset);
0965 
0966     stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
0967                                                  makerNoteCount));
0968 
0969     // Epson MakerNote with header.
0970 
0971     if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
0972         {
0973 
0974         if (makerNoteCount > 8)
0975             {
0976 
0977             ParseMakerNoteIFD (host,
0978                                stream,
0979                                makerNoteCount - 8,
0980                                makerNoteOffset + 8,
0981                                offsetDelta,
0982                                minOffset,
0983                                maxOffset,
0984                                tcEpsonMakerNote);
0985 
0986             }
0987 
0988         return;
0989 
0990         }
0991 
0992     // Fujifilm MakerNote.
0993 
0994     if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
0995         {
0996 
0997         stream.SetReadPosition (makerNoteOffset + 8);
0998 
0999         TempLittleEndian tempEndian (stream);
1000 
1001         uint32 ifd_offset = stream.Get_uint32 ();
1002 
1003         if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
1004             {
1005 
1006             ParseMakerNoteIFD (host,
1007                                stream,
1008                                makerNoteCount - ifd_offset,
1009                                makerNoteOffset + ifd_offset,
1010                                makerNoteOffset,
1011                                minOffset,
1012                                maxOffset,
1013                                tcFujiMakerNote);
1014 
1015             }
1016 
1017         return;
1018 
1019         }
1020 
1021     // Leica MakerNote for models that store entry offsets relative to the start of
1022     // the MakerNote (e.g., M9).
1023 
1024     if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
1025         (memcmp (firstBytes, "LEICA0\003\000",    8) == 0) ||
1026         (memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
1027         (memcmp (firstBytes, "LEICA\000\004\000", 8) == 0) ||
1028         (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0) ||
1029         (memcmp (firstBytes, "LEICA\000\006\000", 8) == 0))
1030         {
1031 
1032         if (makerNoteCount > 8)
1033             {
1034 
1035             ParseMakerNoteIFD (host,
1036                                stream,
1037                                makerNoteCount - 8,
1038                                makerNoteOffset + 8,
1039                                makerNoteOffset,
1040                                minOffset,
1041                                maxOffset,
1042                                tcLeicaMakerNote);
1043 
1044             }
1045 
1046         return;
1047 
1048         }
1049 
1050     // Leica MakerNote for models that store absolute entry offsets (i.e., relative
1051     // to the start of the file, e.g., S2).
1052 
1053     if ((memcmp (firstBytes, "LEICA\000\002\377", 8) == 0) ||
1054         (memcmp (firstBytes, "LEICA\000\002\000", 8) == 0))
1055         {
1056 
1057         if (makerNoteCount > 8)
1058             {
1059 
1060             ParseMakerNoteIFD (host,
1061                                stream,
1062                                makerNoteCount - 8,
1063                                makerNoteOffset + 8,
1064                                offsetDelta,
1065                                minOffset,
1066                                maxOffset,
1067                                tcLeicaMakerNote);
1068 
1069             }
1070 
1071         return;
1072 
1073         }
1074 
1075     // Nikon version 2 MakerNote with header.
1076 
1077     if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
1078         {
1079 
1080         stream.SetReadPosition (makerNoteOffset + 10);
1081 
1082         bool bigEndian = false;
1083 
1084         uint16 endianMark = stream.Get_uint16 ();
1085 
1086         if (endianMark == byteOrderMM)
1087             {
1088             bigEndian = true;
1089             }
1090 
1091         else if (endianMark != byteOrderII)
1092             {
1093             return;
1094             }
1095 
1096         TempBigEndian temp_endian (stream, bigEndian);
1097 
1098         uint16 magic = stream.Get_uint16 ();
1099 
1100         if (magic != 42)
1101             {
1102             return;
1103             }
1104 
1105         uint32 ifd_offset = stream.Get_uint32 ();
1106 
1107         if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
1108             {
1109 
1110             ParseMakerNoteIFD (host,
1111                                stream,
1112                                makerNoteCount - 10 - ifd_offset,
1113                                makerNoteOffset + 10 + ifd_offset,
1114                                makerNoteOffset + 10,
1115                                minOffset,
1116                                maxOffset,
1117                                tcNikonMakerNote);
1118 
1119             }
1120 
1121         return;
1122 
1123         }
1124 
1125     // Newer version of Olympus MakerNote with byte order mark.
1126 
1127     if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
1128         {
1129 
1130         stream.SetReadPosition (makerNoteOffset + 8);
1131 
1132         bool bigEndian = false;
1133 
1134         uint16 endianMark = stream.Get_uint16 ();
1135 
1136         if (endianMark == byteOrderMM)
1137             {
1138             bigEndian = true;
1139             }
1140 
1141         else if (endianMark != byteOrderII)
1142             {
1143             return;
1144             }
1145 
1146         TempBigEndian temp_endian (stream, bigEndian);
1147 
1148         uint16 version = stream.Get_uint16 ();
1149 
1150         if (version != 3)
1151             {
1152             return;
1153             }
1154 
1155         if (makerNoteCount > 12)
1156             {
1157 
1158             ParseMakerNoteIFD (host,
1159                                stream,
1160                                makerNoteCount - 12,
1161                                makerNoteOffset + 12,
1162                                makerNoteOffset,
1163                                minOffset,
1164                                maxOffset,
1165                                tcOlympusMakerNote);
1166 
1167             }
1168 
1169         return;
1170 
1171         }
1172 
1173     // Olympus MakerNote with header.
1174 
1175     if (memcmp (firstBytes, "OLYMP", 5) == 0)
1176         {
1177 
1178         if (makerNoteCount > 8)
1179             {
1180 
1181             ParseMakerNoteIFD (host,
1182                                stream,
1183                                makerNoteCount - 8,
1184                                makerNoteOffset + 8,
1185                                offsetDelta,
1186                                minOffset,
1187                                maxOffset,
1188                                tcOlympusMakerNote);
1189 
1190             }
1191 
1192         return;
1193 
1194         }
1195 
1196     // Panasonic MakerNote.
1197 
1198     if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
1199         {
1200 
1201         if (makerNoteCount > 12)
1202             {
1203 
1204             ParseMakerNoteIFD (host,
1205                                stream,
1206                                makerNoteCount - 12,
1207                                makerNoteOffset + 12,
1208                                offsetDelta,
1209                                minOffset,
1210                                maxOffset,
1211                                tcPanasonicMakerNote);
1212 
1213             }
1214 
1215         return;
1216 
1217         }
1218 
1219     // Pentax MakerNote, absolute addresses.
1220 
1221     if (memcmp (firstBytes, "AOC", 4) == 0)
1222         {
1223 
1224         if (makerNoteCount > 6)
1225             {
1226 
1227             stream.SetReadPosition (makerNoteOffset + 4);
1228 
1229             bool bigEndian = stream.BigEndian ();
1230 
1231             uint16 endianMark = stream.Get_uint16 ();
1232 
1233             if (endianMark == byteOrderMM)
1234                 {
1235                 bigEndian = true;
1236                 }
1237 
1238             else if (endianMark == byteOrderII)
1239                 {
1240                 bigEndian = false;
1241                 }
1242 
1243             TempBigEndian temp_endian (stream, bigEndian);
1244 
1245             ParseMakerNoteIFD (host,
1246                                stream,
1247                                makerNoteCount - 6,
1248                                makerNoteOffset + 6,
1249                                offsetDelta,
1250                                minOffset,
1251                                maxOffset,
1252                                tcPentaxMakerNote);
1253 
1254             }
1255 
1256         return;
1257 
1258         }
1259 
1260     // Pentax MakerNote, relative addresses.
1261 
1262     if (memcmp (firstBytes, "PENTAX", 6) == 0)
1263         {
1264 
1265         if (makerNoteCount > 8)
1266             {
1267 
1268             stream.SetReadPosition (makerNoteOffset + 8);
1269 
1270             bool bigEndian = stream.BigEndian ();
1271 
1272             uint16 endianMark = stream.Get_uint16 ();
1273 
1274             if (endianMark == byteOrderMM)
1275                 {
1276                 bigEndian = true;
1277                 }
1278 
1279             else if (endianMark == byteOrderII)
1280                 {
1281                 bigEndian = false;
1282                 }
1283 
1284             TempBigEndian temp_endian (stream, bigEndian);
1285 
1286             ParseMakerNoteIFD (host,
1287                                stream,
1288                                makerNoteCount - 10,
1289                                makerNoteOffset + 10,
1290                                makerNoteOffset,     // Relative to start of MakerNote.
1291                                minOffset,
1292                                maxOffset,
1293                                tcPentaxMakerNote);
1294 
1295             }
1296 
1297         return;
1298 
1299         }
1300 
1301     // Ricoh MakerNote.
1302 
1303     if (memcmp (firstBytes, "RICOH", 5) == 0 ||
1304         memcmp (firstBytes, "Ricoh", 5) == 0)
1305         {
1306 
1307         if (makerNoteCount > 8)
1308             {
1309 
1310             TempBigEndian tempEndian (stream);
1311 
1312             ParseMakerNoteIFD (host,
1313                                stream,
1314                                makerNoteCount - 8,
1315                                makerNoteOffset + 8,
1316                                offsetDelta,
1317                                minOffset,
1318                                maxOffset,
1319                                tcRicohMakerNote);
1320 
1321             }
1322 
1323         return;
1324 
1325         }
1326 
1327     // Nikon MakerNote without header.
1328 
1329     if (fExif->fMake.StartsWith ("NIKON"))
1330         {
1331 
1332         ParseMakerNoteIFD (host,
1333                            stream,
1334                            makerNoteCount,
1335                            makerNoteOffset,
1336                            offsetDelta,
1337                            minOffset,
1338                            maxOffset,
1339                            tcNikonMakerNote);
1340 
1341         return;
1342 
1343         }
1344 
1345     // Canon MakerNote.
1346 
1347     if (fExif->fMake.StartsWith ("CANON"))
1348         {
1349 
1350         ParseMakerNoteIFD (host,
1351                            stream,
1352                            makerNoteCount,
1353                            makerNoteOffset,
1354                            offsetDelta,
1355                            minOffset,
1356                            maxOffset,
1357                            tcCanonMakerNote);
1358 
1359         return;
1360 
1361         }
1362 
1363     // Minolta MakerNote.
1364 
1365     if (fExif->fMake.StartsWith ("MINOLTA"       ) ||
1366         fExif->fMake.StartsWith ("KONICA MINOLTA"))
1367         {
1368 
1369         ParseMakerNoteIFD (host,
1370                            stream,
1371                            makerNoteCount,
1372                            makerNoteOffset,
1373                            offsetDelta,
1374                            minOffset,
1375                            maxOffset,
1376                            tcMinoltaMakerNote);
1377 
1378         return;
1379 
1380         }
1381 
1382     // Sony MakerNote.
1383 
1384     if (fExif->fMake.StartsWith ("SONY"))
1385         {
1386 
1387         ParseMakerNoteIFD (host,
1388                            stream,
1389                            makerNoteCount,
1390                            makerNoteOffset,
1391                            offsetDelta,
1392                            minOffset,
1393                            maxOffset,
1394                            tcSonyMakerNote);
1395 
1396         return;
1397 
1398         }
1399 
1400     // Kodak MakerNote.
1401 
1402     if (fExif->fMake.StartsWith ("EASTMAN KODAK"))
1403         {
1404 
1405         ParseMakerNoteIFD (host,
1406                            stream,
1407                            makerNoteCount,
1408                            makerNoteOffset,
1409                            offsetDelta,
1410                            minOffset,
1411                            maxOffset,
1412                            tcKodakMakerNote);
1413 
1414         return;
1415 
1416         }
1417 
1418     // Mamiya MakerNote.
1419 
1420     if (fExif->fMake.StartsWith ("Mamiya"))
1421         {
1422 
1423         ParseMakerNoteIFD (host,
1424                            stream,
1425                            makerNoteCount,
1426                            makerNoteOffset,
1427                            offsetDelta,
1428                            minOffset,
1429                            maxOffset,
1430                            tcMamiyaMakerNote);
1431 
1432         // Mamiya uses a MakerNote chain.
1433 
1434         while (fMakerNoteNextIFD)
1435             {
1436 
1437             ParseMakerNoteIFD (host,
1438                                stream,
1439                                makerNoteCount,
1440                                offsetDelta + fMakerNoteNextIFD,
1441                                offsetDelta,
1442                                minOffset,
1443                                maxOffset,
1444                                tcMamiyaMakerNote);
1445 
1446             }
1447 
1448         return;
1449 
1450         }
1451 
1452     // Nikon MakerNote without header.
1453 
1454     if (fExif->fMake.StartsWith ("Hasselblad"))
1455         {
1456 
1457         ParseMakerNoteIFD (host,
1458                            stream,
1459                            makerNoteCount,
1460                            makerNoteOffset,
1461                            offsetDelta,
1462                            minOffset,
1463                            maxOffset,
1464                            tcHasselbladMakerNote);
1465 
1466         return;
1467 
1468         }
1469 
1470     // Samsung MakerNote.
1471 
1472     if (fExif->fMake.StartsWith ("Samsung"))
1473         {
1474 
1475         ParseMakerNoteIFD (host,
1476                            stream,
1477                            makerNoteCount,
1478                            makerNoteOffset,
1479                            makerNoteOffset,
1480                            minOffset,
1481                            maxOffset,
1482                            tcSamsungMakerNote);
1483 
1484         return;
1485 
1486         }
1487 
1488     // Casio MakerNote.
1489 
1490     if (fExif->fMake.StartsWith ("CASIO COMPUTER") &&
1491         memcmp (firstBytes, "QVC\000\000\000", 6) == 0)
1492         {
1493 
1494         ParseMakerNoteIFD (host,
1495                            stream,
1496                            makerNoteCount - 6,
1497                            makerNoteOffset + 6,
1498                            makerNoteOffset,
1499                            minOffset,
1500                            maxOffset,
1501                            tcCasioMakerNote);
1502 
1503         return;
1504 
1505         }
1506 
1507     }
1508 
1509 /*****************************************************************************/
1510 
1511 void dng_info::ParseSonyPrivateData (dng_host & /* host */,
1512                                      dng_stream & /* stream */,
1513                                      uint64 /* count */,
1514                                      uint64 /* oldOffset */,
1515                                      uint64 /* newOffset */)
1516     {
1517 
1518     // Sony private data is encrypted, sorry.
1519 
1520     }
1521 
1522 /*****************************************************************************/
1523 
1524 void dng_info::ParseDNGPrivateData (dng_host &host,
1525                                     dng_stream &stream)
1526     {
1527 
1528     if (fShared->fDNGPrivateDataCount < 2)
1529         {
1530         return;
1531         }
1532 
1533     // DNG private data should always start with a null-terminated
1534     // company name, to define the format of the private data.
1535 
1536     dng_string privateName;
1537 
1538         {
1539 
1540         char buffer [64];
1541 
1542         stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
1543 
1544         uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
1545                                         sizeof (buffer) - 1);
1546 
1547         stream.Get (buffer, readLength);
1548 
1549         buffer [readLength] = 0;
1550 
1551         privateName.Set (buffer);
1552 
1553         }
1554 
1555     // Pentax is storing their MakerNote in the DNGPrivateData data.
1556 
1557     if (privateName.StartsWith ("PENTAX" ) ||
1558         privateName.StartsWith ("SAMSUNG"))
1559         {
1560 
1561         #if qDNGValidate
1562 
1563         if (gVerbose)
1564             {
1565             printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
1566             }
1567 
1568         #endif
1569 
1570         stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
1571 
1572         bool bigEndian = stream.BigEndian ();
1573 
1574         uint16 endianMark = stream.Get_uint16 ();
1575 
1576         if (endianMark == byteOrderMM)
1577             {
1578             bigEndian = true;
1579             }
1580 
1581         else if (endianMark == byteOrderII)
1582             {
1583             bigEndian = false;
1584             }
1585 
1586         TempBigEndian temp_endian (stream, bigEndian);
1587 
1588         ParseMakerNoteIFD (host,
1589                            stream,
1590                            fShared->fDNGPrivateDataCount - 10,
1591                            fShared->fDNGPrivateDataOffset + 10,
1592                            fShared->fDNGPrivateDataOffset,
1593                            fShared->fDNGPrivateDataOffset,
1594                            fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
1595                            tcPentaxMakerNote);
1596 
1597         return;
1598 
1599         }
1600 
1601     // Stop parsing if this is not an Adobe format block.
1602 
1603     if (!privateName.Matches ("Adobe"))
1604         {
1605         return;
1606         }
1607 
1608     TempBigEndian temp_order (stream);
1609 
1610     uint32 section_offset = 6;
1611 
1612     while (section_offset + 8 < fShared->fDNGPrivateDataCount)
1613         {
1614 
1615         stream.SetReadPosition (fShared->fDNGPrivateDataOffset + section_offset);
1616 
1617         uint32 section_key   = stream.Get_uint32 ();
1618         uint32 section_count = stream.Get_uint32 ();
1619 
1620         if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
1621             {
1622 
1623             #if qDNGValidate
1624 
1625             if (gVerbose)
1626                 {
1627                 printf ("Found MakerNote inside DNGPrivateData\n\n");
1628                 }
1629 
1630             #endif
1631 
1632             uint16 order_mark = stream.Get_uint16 ();
1633             uint64 old_offset = stream.Get_uint32 ();
1634 
1635             uint32 tempSize = section_count - 6;
1636 
1637             AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
1638 
1639             uint64 positionInOriginalFile = stream.PositionInOriginalFile();
1640 
1641             stream.Get (tempBlock->Buffer (), tempSize);
1642 
1643             dng_stream tempStream (tempBlock->Buffer (),
1644                                    tempSize,
1645                                    positionInOriginalFile);
1646 
1647             tempStream.SetBigEndian (order_mark == byteOrderMM);
1648 
1649             ParseMakerNote (host,
1650                             tempStream,
1651                             tempSize,
1652                             0,
1653                             0 - old_offset,
1654                             0,
1655                             tempSize);
1656 
1657             }
1658 
1659         else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
1660             {
1661 
1662             #if qDNGValidate
1663 
1664             if (gVerbose)
1665                 {
1666                 printf ("Found Sony private data inside DNGPrivateData\n\n");
1667                 }
1668 
1669             #endif
1670 
1671             uint16 order_mark = stream.Get_uint16 ();
1672             uint64 old_offset = stream.Get_uint32 ();
1673 
1674             uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
1675 
1676             TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
1677 
1678             ParseSonyPrivateData (host,
1679                                   stream,
1680                                   section_count - 6,
1681                                   old_offset,
1682                                   new_offset);
1683 
1684             }
1685 
1686         else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
1687             {
1688 
1689             #if qDNGValidate
1690 
1691             if (gVerbose)
1692                 {
1693                 printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
1694                 }
1695 
1696             #endif
1697 
1698             uint16 order_mark = stream.Get_uint16 ();
1699 
1700             uint32 tagCount = stream.Get_uint32 ();
1701 
1702             uint64 tagOffset = stream.Position ();
1703 
1704             if (tagCount)
1705                 {
1706 
1707                 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1708 
1709                 ParseTag (host,
1710                           stream,
1711                           fExif.Get (),
1712                           fShared.Get (),
1713                           NULL,
1714                           tcFujiRAF,
1715                           tcFujiHeader,
1716                           ttUndefined,
1717                           tagCount,
1718                           tagOffset,
1719                           0);
1720 
1721                 stream.SetReadPosition (tagOffset + tagCount);
1722 
1723                 }
1724 
1725             tagCount = stream.Get_uint32 ();
1726 
1727             tagOffset = stream.Position ();
1728 
1729             if (tagCount)
1730                 {
1731 
1732                 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1733 
1734                 ParseTag (host,
1735                           stream,
1736                           fExif.Get (),
1737                           fShared.Get (),
1738                           NULL,
1739                           tcFujiRAF,
1740                           tcFujiRawInfo1,
1741                           ttUndefined,
1742                           tagCount,
1743                           tagOffset,
1744                           0);
1745 
1746                 stream.SetReadPosition (tagOffset + tagCount);
1747 
1748                 }
1749 
1750             tagCount = stream.Get_uint32 ();
1751 
1752             tagOffset = stream.Position ();
1753 
1754             if (tagCount)
1755                 {
1756 
1757                 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1758 
1759                 ParseTag (host,
1760                           stream,
1761                           fExif.Get (),
1762                           fShared.Get (),
1763                           NULL,
1764                           tcFujiRAF,
1765                           tcFujiRawInfo2,
1766                           ttUndefined,
1767                           tagCount,
1768                           tagOffset,
1769                           0);
1770 
1771                 stream.SetReadPosition (tagOffset + tagCount);
1772 
1773                 }
1774 
1775             }
1776 
1777         else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
1778             {
1779 
1780             #if qDNGValidate
1781 
1782             if (gVerbose)
1783                 {
1784                 printf ("Found Contax Raw header inside DNGPrivateData\n\n");
1785                 }
1786 
1787             #endif
1788 
1789             uint16 order_mark = stream.Get_uint16 ();
1790 
1791             uint32 tagCount  = stream.Get_uint32 ();
1792 
1793             uint64 tagOffset = stream.Position ();
1794 
1795             if (tagCount)
1796                 {
1797 
1798                 TempBigEndian contax_order (stream, order_mark == byteOrderMM);
1799 
1800                 ParseTag (host,
1801                           stream,
1802                           fExif.Get (),
1803                           fShared.Get (),
1804                           NULL,
1805                           tcContaxRAW,
1806                           tcContaxHeader,
1807                           ttUndefined,
1808                           tagCount,
1809                           tagOffset,
1810                           0);
1811 
1812                 }
1813 
1814             }
1815 
1816         else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
1817             {
1818 
1819             #if qDNGValidate
1820 
1821             if (gVerbose)
1822                 {
1823                 printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
1824                 }
1825 
1826             #endif
1827 
1828             uint16 order_mark = stream.Get_uint16 ();
1829             uint32 entries    = stream.Get_uint16 ();
1830 
1831             uint64 crwTagStart = stream.Position ();
1832 
1833             for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
1834                 {
1835 
1836                 stream.SetReadPosition (crwTagStart);
1837 
1838                 for (uint32 index = 0; index < entries; index++)
1839                     {
1840 
1841                     uint32 tagCode = stream.Get_uint16 ();
1842 
1843                     uint32 tagCount = stream.Get_uint32 ();
1844 
1845                     uint64 tagOffset = stream.Position ();
1846 
1847                     // We need to grab the model id tag first, and then all the
1848                     // other tags.
1849 
1850                     if ((parsePass == 1) == (tagCode == 0x5834))
1851                         {
1852 
1853                         TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1854 
1855                         ParseTag (host,
1856                                   stream,
1857                                   fExif.Get (),
1858                                   fShared.Get (),
1859                                   NULL,
1860                                   tcCanonCRW,
1861                                   tagCode,
1862                                   ttUndefined,
1863                                   tagCount,
1864                                   tagOffset,
1865                                   0);
1866 
1867                         }
1868 
1869                     stream.SetReadPosition (tagOffset + tagCount);
1870 
1871                     }
1872 
1873                 }
1874 
1875             }
1876 
1877         else if (section_count > 4)
1878             {
1879 
1880             uint32 parentCode = 0;
1881 
1882             bool code32  = false;
1883             bool hasType = true;
1884 
1885             switch (section_key)
1886                 {
1887 
1888                 case DNG_CHAR4 ('M','R','W',' '):
1889                     {
1890                     parentCode = tcMinoltaMRW;
1891                     code32     = true;
1892                     hasType    = false;
1893                     break;
1894                     }
1895 
1896                 case DNG_CHAR4 ('P','a','n','o'):
1897                     {
1898                     parentCode = tcPanasonicRAW;
1899                     break;
1900                     }
1901 
1902                 case DNG_CHAR4 ('L','e','a','f'):
1903                     {
1904                     parentCode = tcLeafMOS;
1905                     break;
1906                     }
1907 
1908                 case DNG_CHAR4 ('K','o','d','a'):
1909                     {
1910                     parentCode = tcKodakDCRPrivateIFD;
1911                     break;
1912                     }
1913 
1914                 case DNG_CHAR4 ('K','D','C',' '):
1915                     {
1916                     parentCode = tcKodakKDCPrivateIFD;
1917                     break;
1918                     }
1919 
1920                 default:
1921                     break;
1922 
1923                 }
1924 
1925             if (parentCode)
1926                 {
1927 
1928                 #if qDNGValidate
1929 
1930                 if (gVerbose)
1931                     {
1932                     printf ("Found %s tags inside DNGPrivateData\n\n",
1933                             LookupParentCode (parentCode));
1934                     }
1935 
1936                 #endif
1937 
1938                 uint16 order_mark = stream.Get_uint16 ();
1939                 uint32 entries    = stream.Get_uint16 ();
1940 
1941                 for (uint32 index = 0; index < entries; index++)
1942                     {
1943 
1944                     uint32 tagCode = code32 ? stream.Get_uint32 ()
1945                                             : stream.Get_uint16 ();
1946 
1947                     uint32 tagType  = hasType ? stream.Get_uint16 ()
1948                                               : ttUndefined;
1949 
1950                     uint32 tagCount = stream.Get_uint32 ();
1951 
1952                     uint32 tagSize = tagCount * TagTypeSize (tagType);
1953 
1954                     uint64 tagOffset = stream.Position ();
1955 
1956                     TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1957 
1958                     ParseTag (host,
1959                               stream,
1960                               fExif.Get (),
1961                               fShared.Get (),
1962                               NULL,
1963                               parentCode,
1964                               tagCode,
1965                               tagType,
1966                               tagCount,
1967                               tagOffset,
1968                               0);
1969 
1970                     stream.SetReadPosition (tagOffset + tagSize);
1971 
1972                     }
1973 
1974                 }
1975 
1976             }
1977 
1978         section_offset += 8 + section_count;
1979 
1980         if (section_offset & 1)
1981             {
1982             section_offset++;
1983             }
1984 
1985         }
1986 
1987     }
1988 
1989 /*****************************************************************************/
1990 
1991 void dng_info::Parse (dng_host &host,
1992                       dng_stream &stream)
1993     {
1994 
1995     fTIFFBlockOffset = stream.Position ();
1996 
1997     fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
1998 
1999     // Check byte order indicator.
2000 
2001     uint16 byteOrder = stream.Get_uint16 ();
2002 
2003     if (byteOrder == byteOrderII)
2004         {
2005 
2006         fBigEndian = false;
2007 
2008         #if qDNGValidate
2009 
2010         if (gVerbose)
2011             {
2012             printf ("\nUses little-endian byte order\n");
2013             }
2014 
2015         #endif
2016 
2017         stream.SetLittleEndian ();
2018 
2019         }
2020 
2021     else if (byteOrder == byteOrderMM)
2022         {
2023 
2024         fBigEndian = true;
2025 
2026         #if qDNGValidate
2027 
2028         if (gVerbose)
2029             {
2030             printf ("\nUses big-endian byte order\n");
2031             }
2032 
2033         #endif
2034 
2035         stream.SetBigEndian ();
2036 
2037         }
2038 
2039     else
2040         {
2041 
2042         #if qDNGValidate
2043 
2044         ReportError ("Unknown byte order");
2045 
2046         #endif
2047 
2048         ThrowBadFormat ();
2049 
2050         }
2051 
2052     // Check "magic number" indicator.
2053 
2054     fMagic = stream.Get_uint16 ();
2055 
2056     #if qDNGValidate
2057 
2058     if (gVerbose)
2059         {
2060         printf ("Magic number = %u\n\n", (unsigned) fMagic);
2061         }
2062 
2063     #endif
2064 
2065     ValidateMagic ();
2066 
2067     // Parse IFD 0.
2068 
2069     uint64 next_offset = stream.Get_uint32 ();
2070 
2071     fExif.Reset (host.Make_dng_exif ());
2072 
2073     fShared.Reset (host.Make_dng_shared ());
2074 
2075     fIFD.push_back (host.Make_dng_ifd ());
2076 
2077     ParseIFD (host,
2078               stream,
2079               fExif.Get (),
2080               fShared.Get (),
2081               fIFD [0],
2082               fTIFFBlockOffset + next_offset,
2083               fTIFFBlockOffset,
2084               0);
2085 
2086     next_offset = fIFD [0]->fNextIFD;
2087 
2088     // Parse chained IFDs.
2089 
2090     while (next_offset)
2091         {
2092 
2093         if (next_offset >= stream.Length ())
2094             {
2095 
2096             #if qDNGValidate
2097 
2098                 {
2099 
2100                 ReportWarning ("Chained IFD offset past end of stream");
2101 
2102                 }
2103 
2104             #endif
2105 
2106             break;
2107 
2108             }
2109 
2110         // Some TIFF file writers forget about the next IFD offset, so
2111         // validate the IFD at that offset before parsing it.
2112 
2113         if (!ValidateIFD (stream,
2114                           fTIFFBlockOffset + next_offset,
2115                           fTIFFBlockOffset))
2116             {
2117 
2118             #if qDNGValidate
2119 
2120                 {
2121 
2122                 ReportWarning ("Chained IFD is not valid");
2123 
2124                 }
2125 
2126             #endif
2127 
2128             break;
2129 
2130             }
2131 
2132         if (ChainedIFDCount () == kMaxChainedIFDs)
2133             {
2134 
2135             #if qDNGValidate
2136 
2137                 {
2138 
2139                 ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
2140 
2141                 }
2142 
2143             #endif
2144 
2145             break;
2146 
2147             }
2148 
2149         fChainedIFD.push_back (host.Make_dng_ifd ());
2150 
2151         fChainedSubIFD.push_back (std::vector <dng_ifd *> ());
2152 
2153         ParseIFD (host,
2154                   stream,
2155                   NULL,
2156                   NULL,
2157                   fChainedIFD [ChainedIFDCount () - 1],
2158                   fTIFFBlockOffset + next_offset,
2159                   fTIFFBlockOffset,
2160                   tcFirstChainedIFD + ChainedIFDCount () - 1);
2161 
2162         next_offset = fChainedIFD [ChainedIFDCount () - 1]->fNextIFD;
2163 
2164         }
2165 
2166     // Parse SubIFDs.
2167 
2168     uint32 searchedIFDs = 0;
2169 
2170     bool tooManySubIFDs = false;
2171 
2172     while (searchedIFDs < IFDCount () && !tooManySubIFDs)
2173         {
2174 
2175         uint32 searchLimit = IFDCount ();
2176 
2177         for (uint32 searchIndex = searchedIFDs;
2178              searchIndex < searchLimit && !tooManySubIFDs;
2179              searchIndex++)
2180             {
2181 
2182             for (uint32 subIndex = 0;
2183                  subIndex < fIFD [searchIndex]->fSubIFDsCount;
2184                  subIndex++)
2185                 {
2186 
2187                 if (IFDCount () == kMaxSubIFDs + 1)
2188                     {
2189 
2190                     tooManySubIFDs = true;
2191 
2192                     break;
2193 
2194                     }
2195 
2196                 stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
2197                                         subIndex * 4);
2198 
2199                 uint32 sub_ifd_offset = stream.Get_uint32 ();
2200 
2201                 fIFD.push_back (host.Make_dng_ifd ());
2202 
2203                 ParseIFD (host,
2204                           stream,
2205                           fExif.Get (),
2206                           fShared.Get (),
2207                           fIFD [IFDCount () - 1],
2208                           fTIFFBlockOffset + sub_ifd_offset,
2209                           fTIFFBlockOffset,
2210                           tcFirstSubIFD + IFDCount () - 2);
2211 
2212                 }
2213 
2214             searchedIFDs = searchLimit;
2215 
2216             }
2217 
2218         }
2219 
2220     #if qDNGValidate
2221 
2222         {
2223 
2224         if (tooManySubIFDs)
2225             {
2226 
2227             ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
2228 
2229             }
2230 
2231         }
2232 
2233     #endif
2234 
2235     // Parse SubIFDs in Chained IFDs.  Don't currently need to make this a
2236     // recursive search.
2237 
2238     for (uint32 chainedIndex = 0;
2239          chainedIndex < ChainedIFDCount ();
2240          chainedIndex++)
2241         {
2242 
2243         for (uint32 subIndex = 0;
2244              subIndex < fChainedIFD [chainedIndex]->fSubIFDsCount;
2245              subIndex++)
2246             {
2247 
2248             if (subIndex == kMaxSubIFDs)
2249                 {
2250 
2251                 #if qDNGValidate
2252 
2253                 ReportWarning ("Chained SubIFD count exceeds DNG SDK parsing limit");
2254 
2255                 #endif
2256 
2257                 break;
2258 
2259                 }
2260 
2261             stream.SetReadPosition (fChainedIFD [chainedIndex]->fSubIFDsOffset +
2262                                     subIndex * 4);
2263 
2264             uint32 sub_ifd_offset = stream.Get_uint32 ();
2265 
2266             fChainedSubIFD [chainedIndex].push_back (host.Make_dng_ifd ());
2267 
2268             ParseIFD (host,
2269                       stream,
2270                       fExif.Get (),
2271                       fShared.Get (),
2272                       fChainedSubIFD [chainedIndex] [subIndex],
2273                       fTIFFBlockOffset + sub_ifd_offset,
2274                       fTIFFBlockOffset,
2275                       tcFirstSubIFD + subIndex);
2276 
2277             }
2278 
2279         }
2280 
2281     // Parse EXIF IFD.
2282 
2283     if (fShared->fExifIFD)
2284         {
2285 
2286         ParseIFD (host,
2287                   stream,
2288                   fExif.Get (),
2289                   fShared.Get (),
2290                   NULL,
2291                   fTIFFBlockOffset + fShared->fExifIFD,
2292                   fTIFFBlockOffset,
2293                   tcExifIFD);
2294 
2295         }
2296 
2297     // Parse GPS IFD.
2298 
2299     if (fShared->fGPSInfo)
2300         {
2301 
2302         ParseIFD (host,
2303                   stream,
2304                   fExif.Get (),
2305                   fShared.Get (),
2306                   NULL,
2307                   fTIFFBlockOffset + fShared->fGPSInfo,
2308                   fTIFFBlockOffset,
2309                   tcGPSInfo);
2310 
2311         }
2312 
2313     // Parse Interoperability IFD.
2314 
2315     if (fShared->fInteroperabilityIFD)
2316         {
2317 
2318         // Some Kodak KDC files have bogus Interoperability IFDs, so
2319         // validate the IFD before trying to parse it.
2320 
2321         if (ValidateIFD (stream,
2322                          fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2323                          fTIFFBlockOffset))
2324             {
2325 
2326             ParseIFD (host,
2327                       stream,
2328                       fExif.Get (),
2329                       fShared.Get (),
2330                       NULL,
2331                       fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2332                       fTIFFBlockOffset,
2333                       tcInteroperabilityIFD);
2334 
2335             }
2336 
2337         #if qDNGValidate
2338 
2339         else
2340             {
2341 
2342             ReportWarning ("The Interoperability IFD is not a valid IFD");
2343 
2344             }
2345 
2346         #endif
2347 
2348         }
2349 
2350     // Parse Kodak DCR Private IFD.
2351 
2352     if (fShared->fKodakDCRPrivateIFD)
2353         {
2354 
2355         ParseIFD (host,
2356                   stream,
2357                   fExif.Get (),
2358                   fShared.Get (),
2359                   NULL,
2360                   fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
2361                   fTIFFBlockOffset,
2362                   tcKodakDCRPrivateIFD);
2363 
2364         }
2365 
2366     // Parse Kodak KDC Private IFD.
2367 
2368     if (fShared->fKodakKDCPrivateIFD)
2369         {
2370 
2371         ParseIFD (host,
2372                   stream,
2373                   fExif.Get (),
2374                   fShared.Get (),
2375                   NULL,
2376                   fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
2377                   fTIFFBlockOffset,
2378                   tcKodakKDCPrivateIFD);
2379 
2380         }
2381 
2382     // Parse MakerNote tag.
2383 
2384     if (fShared->fMakerNoteCount)
2385         {
2386 
2387         ParseMakerNote (host,
2388                         stream,
2389                         (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
2390                         fShared->fMakerNoteOffset,
2391                         fTIFFBlockOffset,
2392                         0,
2393                         stream.Length ());
2394 
2395         }
2396 
2397     // Parse DNGPrivateData tag.
2398 
2399     if (fShared->fDNGPrivateDataCount &&
2400         fShared->fDNGVersion)
2401         {
2402 
2403         ParseDNGPrivateData (host, stream);
2404 
2405         }
2406 
2407     #if qDNGValidate
2408 
2409     // If we are running dng_validate on stand-alone camera profile file,
2410     // complete the validation of the profile.
2411 
2412     if (fMagic == magicExtendedProfile)
2413         {
2414 
2415         dng_camera_profile_info &profileInfo = fShared->fCameraProfile;
2416 
2417         dng_camera_profile profile;
2418 
2419         profile.Parse (stream, profileInfo);
2420 
2421         if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes))
2422             {
2423 
2424             ReportError ("Invalid camera profile file");
2425 
2426             }
2427 
2428         }
2429 
2430     #endif
2431 
2432     }
2433 
2434 /*****************************************************************************/
2435 
2436 void dng_info::PostParse (dng_host &host)
2437     {
2438 
2439     uint32 index;
2440 
2441     fExif->PostParse (host, *fShared.Get ());
2442 
2443     fShared->PostParse (host, *fExif.Get ());
2444 
2445     for (index = 0; index < IFDCount (); index++)
2446         {
2447 
2448         fIFD [index]->PostParse ();
2449 
2450         }
2451 
2452     for (index = 0; index < ChainedIFDCount (); index++)
2453         {
2454 
2455         fChainedIFD [index]->PostParse ();
2456 
2457         }
2458 
2459     for (size_t i = 0; i < fChainedSubIFD.size (); i++)
2460         {
2461 
2462         std::vector <dng_ifd *> &chain = fChainedSubIFD [i];
2463 
2464         for (size_t j = 0; j < chain.size (); j++)
2465             {
2466 
2467             if (chain [j])
2468                 {
2469                 chain [j]->PostParse ();
2470                 }
2471 
2472             }
2473 
2474         }
2475 
2476     if (fShared->fDNGVersion != 0)
2477         {
2478 
2479         // Find main IFD.
2480 
2481         fMainIndex = -1;
2482 
2483         for (index = 0; index < IFDCount (); index++)
2484             {
2485 
2486             if (fIFD [index]->fUsesNewSubFileType &&
2487                 fIFD [index]->fNewSubFileType == sfMainImage)
2488                 {
2489 
2490                 if (fMainIndex == -1)
2491                     {
2492 
2493                     fMainIndex = index;
2494 
2495                     }
2496 
2497                 #if qDNGValidate
2498 
2499                 else
2500                     {
2501 
2502                     ReportError ("Multiple IFDs marked as main image");
2503 
2504                     }
2505 
2506                 #endif
2507 
2508                 }
2509 
2510             else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
2511                      fIFD [index]->fNewSubFileType == sfAltPreviewImage)
2512                 {
2513 
2514                 // Fill in default color space for DNG previews if not included.
2515 
2516                 if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
2517                     {
2518 
2519                     if (fIFD [index]->fSamplesPerPixel == 1)
2520                         {
2521 
2522                         fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
2523 
2524                         }
2525 
2526                     else
2527                         {
2528 
2529                         fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
2530 
2531                         }
2532 
2533                     }
2534 
2535                 }
2536 
2537             }
2538 
2539         // Deal with lossless JPEG bug in early DNG versions.
2540 
2541         if (fShared->fDNGVersion < dngVersion_1_1_0_0)
2542             {
2543 
2544             if (fMainIndex != -1)
2545                 {
2546 
2547                 fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
2548 
2549                 }
2550 
2551             }
2552 
2553         // Find mask index.
2554 
2555         for (index = 0; index < IFDCount (); index++)
2556             {
2557 
2558             if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
2559                 {
2560 
2561                 if (fMaskIndex == -1)
2562                     {
2563 
2564                     fMaskIndex = index;
2565 
2566                     }
2567 
2568                 #if qDNGValidate
2569 
2570                 else
2571                     {
2572 
2573                     ReportError ("Multiple IFDs marked as transparency mask image");
2574 
2575                     }
2576 
2577                 #endif
2578 
2579                 }
2580 
2581             }
2582 
2583         // Find depth index.
2584 
2585         for (index = 0; index < IFDCount (); index++)
2586             {
2587 
2588             if (fIFD [index]->fNewSubFileType == sfDepthMap)
2589                 {
2590 
2591                 if (fDepthIndex == -1)
2592                     {
2593 
2594                     fDepthIndex = index;
2595 
2596                     }
2597 
2598                 #if qDNGValidate
2599 
2600                 else
2601                     {
2602 
2603                     ReportError ("Multiple IFDs marked as depth map image");
2604 
2605                     }
2606 
2607                 #endif
2608 
2609                 }
2610 
2611             }
2612 
2613         // Find enhanced ifd index.
2614 
2615         for (index = 0; index < IFDCount (); index++)
2616             {
2617 
2618             if (fIFD [index]->fNewSubFileType == sfEnhancedImage)
2619                 {
2620 
2621                 if (fEnhancedIndex == -1)
2622                     {
2623 
2624                     fEnhancedIndex = index;
2625 
2626                     }
2627 
2628                 #if qDNGValidate
2629 
2630                 else
2631                     {
2632 
2633                     ReportError ("Multiple IFDs marked as enhanced image");
2634 
2635                     }
2636 
2637                 #endif
2638 
2639                 }
2640 
2641             }
2642 
2643         // Warn about Chained IFDs.
2644 
2645         #if qDNGValidate
2646 
2647         if (ChainedIFDCount () > 0)
2648             {
2649 
2650             ReportWarning ("This file has Chained IFDs, which will be ignored by DNG readers");
2651 
2652             }
2653 
2654         #endif
2655 
2656         }
2657 
2658     }
2659 
2660 /*****************************************************************************/
2661 
2662 bool dng_info::IsValidDNG ()
2663     {
2664 
2665     // Check shared info.
2666 
2667     if (!fShared->IsValidDNG ())
2668         {
2669 
2670         return false;
2671 
2672         }
2673 
2674     // Check TIFF magic number.
2675 
2676     if (fMagic != 42)
2677         {
2678 
2679         #if qDNGValidate
2680 
2681         ReportError ("Invalid TIFF magic number");
2682 
2683         #endif
2684 
2685         return false;
2686 
2687         }
2688 
2689     // Make sure we have a main image IFD.
2690 
2691     if (fMainIndex == -1)
2692         {
2693 
2694         #if qDNGValidate
2695 
2696         ReportError ("Unable to find main image IFD");
2697 
2698         #endif
2699 
2700         return false;
2701 
2702         }
2703 
2704     // Make sure is each IFD is valid.
2705 
2706     for (uint32 index = 0; index < IFDCount (); index++)
2707         {
2708 
2709         uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
2710 
2711         if (!fIFD [index]->IsValidDNG (*fShared.Get (),
2712                                        parentCode))
2713             {
2714 
2715             // Only errors in the main and transparency mask IFDs are fatal to parsing.
2716 
2717             if (index == (uint32) fMainIndex ||
2718                 index == (uint32) fMaskIndex)
2719                 {
2720 
2721                 return false;
2722 
2723                 }
2724 
2725             // Also errors to depth map...
2726 
2727             if (index == (uint32) fDepthIndex)
2728                 {
2729 
2730                 return false;
2731 
2732                 }
2733 
2734             }
2735 
2736         }
2737 
2738     return true;
2739 
2740     }
2741 
2742 /*****************************************************************************/