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

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_shared.h"
0010 
0011 #include "dng_camera_profile.h"
0012 #include "dng_exceptions.h"
0013 #include "dng_globals.h"
0014 #include "dng_memory.h"
0015 #include "dng_parse_utils.h"
0016 #include "dng_tag_codes.h"
0017 #include "dng_tag_types.h"
0018 #include "dng_tag_values.h"
0019 #include "dng_utils.h"
0020 
0021 /*****************************************************************************/
0022 
0023 dng_camera_profile_info::dng_camera_profile_info ()
0024 
0025     :   fBigEndian (false)
0026 
0027     ,   fColorPlanes (0)
0028 
0029     ,   fCalibrationIlluminant1 (lsUnknown)
0030     ,   fCalibrationIlluminant2 (lsUnknown)
0031 
0032     ,   fColorMatrix1 ()
0033     ,   fColorMatrix2 ()
0034 
0035     ,   fForwardMatrix1 ()
0036     ,   fForwardMatrix2 ()
0037 
0038     ,   fReductionMatrix1 ()
0039     ,   fReductionMatrix2 ()
0040 
0041     ,   fProfileCalibrationSignature ()
0042 
0043     ,   fProfileName ()
0044 
0045     ,   fProfileCopyright ()
0046 
0047     ,   fEmbedPolicy (pepAllowCopying)
0048 
0049     ,   fProfileHues (0)
0050     ,   fProfileSats (0)
0051     ,   fProfileVals (0)
0052 
0053     ,   fHueSatDeltas1Offset (0)
0054     ,   fHueSatDeltas1Count  (0)
0055 
0056     ,   fHueSatDeltas2Offset (0)
0057     ,   fHueSatDeltas2Count  (0)
0058 
0059     ,   fHueSatMapEncoding (encoding_Linear)
0060 
0061     ,   fLookTableHues (0)
0062     ,   fLookTableSats (0)
0063     ,   fLookTableVals (0)
0064 
0065     ,   fLookTableOffset (0)
0066     ,   fLookTableCount  (0)
0067 
0068     ,   fLookTableEncoding (encoding_Linear)
0069 
0070     ,   fBaselineExposureOffset (0, 100)
0071 
0072     ,   fDefaultBlackRender (defaultBlackRender_Auto)
0073 
0074     ,   fToneCurveOffset     (0)
0075     ,   fToneCurveCount      (0)
0076 
0077     ,   fUniqueCameraModel ()
0078 
0079     {
0080 
0081     }
0082 
0083 /*****************************************************************************/
0084 
0085 dng_camera_profile_info::~dng_camera_profile_info ()
0086     {
0087 
0088     }
0089 
0090 /*****************************************************************************/
0091 
0092 DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
0093 bool dng_camera_profile_info::ParseTag (dng_stream &stream,
0094                                         uint32 parentCode,
0095                                         uint32 tagCode,
0096                                         uint32 tagType,
0097                                         uint32 tagCount,
0098                                         uint64 tagOffset)
0099     {
0100 
0101     switch (tagCode)
0102         {
0103 
0104         case tcCalibrationIlluminant1:
0105             {
0106 
0107             CheckTagType (parentCode, tagCode, tagType, ttShort);
0108 
0109             CheckTagCount (parentCode, tagCode, tagCount, 1);
0110 
0111             fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType);
0112 
0113             #if qDNGValidate
0114 
0115             if (gVerbose)
0116                 {
0117 
0118                 printf ("CalibrationIlluminant1: %s\n",
0119                         LookupLightSource (fCalibrationIlluminant1));
0120 
0121                 }
0122 
0123             #endif
0124 
0125             break;
0126 
0127             }
0128 
0129         case tcCalibrationIlluminant2:
0130             {
0131 
0132             CheckTagType (parentCode, tagCode, tagType, ttShort);
0133 
0134             CheckTagCount (parentCode, tagCode, tagCount, 1);
0135 
0136             fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType);
0137 
0138             #if qDNGValidate
0139 
0140             if (gVerbose)
0141                 {
0142 
0143                 printf ("CalibrationIlluminant2: %s\n",
0144                         LookupLightSource (fCalibrationIlluminant2));
0145 
0146                 }
0147 
0148             #endif
0149 
0150             break;
0151 
0152             }
0153 
0154         case tcColorMatrix1:
0155             {
0156 
0157             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0158 
0159             if (fColorPlanes == 0)
0160                 {
0161 
0162                 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
0163 
0164                 }
0165 
0166             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0167                 return false;
0168 
0169             if (!ParseMatrixTag (stream,
0170                                  parentCode,
0171                                  tagCode,
0172                                  tagType,
0173                                  tagCount,
0174                                  fColorPlanes,
0175                                  3,
0176                                  fColorMatrix1))
0177                 return false;
0178 
0179             #if qDNGValidate
0180 
0181             if (gVerbose)
0182                 {
0183 
0184                 printf ("ColorMatrix1:\n");
0185 
0186                 DumpMatrix (fColorMatrix1);
0187 
0188                 }
0189 
0190             #endif
0191 
0192             break;
0193 
0194             }
0195 
0196         case tcColorMatrix2:
0197             {
0198 
0199             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0200 
0201             // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
0202             // only have a ColorMatrix2 tag and no ColorMatrix1 tag.
0203 
0204             bool hasselbladHack = (fColorPlanes == 0);
0205 
0206             if (hasselbladHack)
0207                 {
0208 
0209                 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
0210 
0211                 #if qDNGValidate
0212 
0213                 ReportWarning ("ColorMatrix2 without ColorMatrix1");
0214 
0215                 #endif
0216 
0217                 }
0218 
0219             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0220                 return false;
0221 
0222             if (!ParseMatrixTag (stream,
0223                                  parentCode,
0224                                  tagCode,
0225                                  tagType,
0226                                  tagCount,
0227                                  fColorPlanes,
0228                                  3,
0229                                  fColorMatrix2))
0230                 return false;
0231 
0232             #if qDNGValidate
0233 
0234             if (gVerbose)
0235                 {
0236 
0237                 printf ("ColorMatrix2:\n");
0238 
0239                 DumpMatrix (fColorMatrix2);
0240 
0241                 }
0242 
0243             #endif
0244 
0245             if (hasselbladHack)
0246                 {
0247 
0248                 fColorMatrix1 = fColorMatrix2;
0249 
0250                 fColorMatrix2 = dng_matrix ();
0251 
0252                 }
0253 
0254             break;
0255 
0256             }
0257 
0258         case tcForwardMatrix1:
0259             {
0260 
0261             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0262 
0263             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0264                 return false;
0265 
0266             if (!ParseMatrixTag (stream,
0267                                  parentCode,
0268                                  tagCode,
0269                                  tagType,
0270                                  tagCount,
0271                                  3,
0272                                  fColorPlanes,
0273                                  fForwardMatrix1))
0274                 return false;
0275 
0276             #if qDNGValidate
0277 
0278             if (gVerbose)
0279                 {
0280 
0281                 printf ("ForwardMatrix1:\n");
0282 
0283                 DumpMatrix (fForwardMatrix1);
0284 
0285                 }
0286 
0287             #endif
0288 
0289             break;
0290 
0291             }
0292 
0293         case tcForwardMatrix2:
0294             {
0295 
0296             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0297 
0298             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0299                 return false;
0300 
0301             if (!ParseMatrixTag (stream,
0302                                  parentCode,
0303                                  tagCode,
0304                                  tagType,
0305                                  tagCount,
0306                                  3,
0307                                  fColorPlanes,
0308                                  fForwardMatrix2))
0309                 return false;
0310 
0311             #if qDNGValidate
0312 
0313             if (gVerbose)
0314                 {
0315 
0316                 printf ("ForwardMatrix2:\n");
0317 
0318                 DumpMatrix (fForwardMatrix2);
0319 
0320                 }
0321 
0322             #endif
0323 
0324             break;
0325 
0326             }
0327 
0328         case tcReductionMatrix1:
0329             {
0330 
0331             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0332 
0333             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0334                 return false;
0335 
0336             if (!ParseMatrixTag (stream,
0337                                  parentCode,
0338                                  tagCode,
0339                                  tagType,
0340                                  tagCount,
0341                                  3,
0342                                  fColorPlanes,
0343                                  fReductionMatrix1))
0344                 return false;
0345 
0346             #if qDNGValidate
0347 
0348             if (gVerbose)
0349                 {
0350 
0351                 printf ("ReductionMatrix1:\n");
0352 
0353                 DumpMatrix (fReductionMatrix1);
0354 
0355                 }
0356 
0357             #endif
0358 
0359             break;
0360 
0361             }
0362 
0363         case tcReductionMatrix2:
0364             {
0365 
0366             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0367 
0368             if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
0369                 return false;
0370 
0371             if (!ParseMatrixTag (stream,
0372                                  parentCode,
0373                                  tagCode,
0374                                  tagType,
0375                                  tagCount,
0376                                  3,
0377                                  fColorPlanes,
0378                                  fReductionMatrix2))
0379                 return false;
0380 
0381             #if qDNGValidate
0382 
0383             if (gVerbose)
0384                 {
0385 
0386                 printf ("ReductionMatrix2:\n");
0387 
0388                 DumpMatrix (fReductionMatrix2);
0389 
0390                 }
0391 
0392             #endif
0393 
0394             break;
0395 
0396             }
0397 
0398         case tcProfileCalibrationSignature:
0399             {
0400 
0401             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
0402 
0403             ParseStringTag (stream,
0404                             parentCode,
0405                             tagCode,
0406                             tagCount,
0407                             fProfileCalibrationSignature,
0408                             false);
0409 
0410             #if qDNGValidate
0411 
0412             if (gVerbose)
0413                 {
0414 
0415                 printf ("ProfileCalibrationSignature: ");
0416 
0417                 DumpString (fProfileCalibrationSignature);
0418 
0419                 printf ("\n");
0420 
0421                 }
0422 
0423             #endif
0424 
0425             break;
0426 
0427             }
0428 
0429         case tcProfileName:
0430             {
0431 
0432             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
0433 
0434             ParseStringTag (stream,
0435                             parentCode,
0436                             tagCode,
0437                             tagCount,
0438                             fProfileName,
0439                             false);
0440 
0441             #if qDNGValidate
0442 
0443             if (gVerbose)
0444                 {
0445 
0446                 printf ("ProfileName: ");
0447 
0448                 DumpString (fProfileName);
0449 
0450                 printf ("\n");
0451 
0452                 }
0453 
0454             #endif
0455 
0456             break;
0457 
0458             }
0459 
0460         case tcProfileCopyright:
0461             {
0462 
0463             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
0464 
0465             ParseStringTag (stream,
0466                             parentCode,
0467                             tagCode,
0468                             tagCount,
0469                             fProfileCopyright,
0470                             false);
0471 
0472             #if qDNGValidate
0473 
0474             if (gVerbose)
0475                 {
0476 
0477                 printf ("ProfileCopyright: ");
0478 
0479                 DumpString (fProfileCopyright);
0480 
0481                 printf ("\n");
0482 
0483                 }
0484 
0485             #endif
0486 
0487             break;
0488 
0489             }
0490 
0491         case tcProfileEmbedPolicy:
0492             {
0493 
0494             CheckTagType (parentCode, tagCode, tagType, ttLong);
0495 
0496             CheckTagCount (parentCode, tagCode, tagCount, 1);
0497 
0498             fEmbedPolicy = stream.TagValue_uint32 (tagType);
0499 
0500             #if qDNGValidate
0501 
0502             if (gVerbose)
0503                 {
0504 
0505                 const char *policy;
0506 
0507                 switch (fEmbedPolicy)
0508                     {
0509 
0510                     case pepAllowCopying:
0511                         policy = "Allow copying";
0512                         break;
0513 
0514                     case pepEmbedIfUsed:
0515                         policy = "Embed if used";
0516                         break;
0517 
0518                     case pepEmbedNever:
0519                         policy = "Embed never";
0520                         break;
0521 
0522                     case pepNoRestrictions:
0523                         policy = "No restrictions";
0524                         break;
0525 
0526                     default:
0527                         policy = "INVALID VALUE";
0528 
0529                     }
0530 
0531                 printf ("ProfileEmbedPolicy: %s\n", policy);
0532 
0533                 }
0534 
0535             #endif
0536 
0537             break;
0538 
0539             }
0540 
0541         case tcProfileHueSatMapDims:
0542             {
0543 
0544             CheckTagType (parentCode, tagCode, tagType, ttLong);
0545 
0546             CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
0547 
0548             fProfileHues = stream.TagValue_uint32 (tagType);
0549             fProfileSats = stream.TagValue_uint32 (tagType);
0550 
0551             if (tagCount > 2)
0552                 fProfileVals = stream.TagValue_uint32 (tagType);
0553             else
0554                 fProfileVals = 1;
0555 
0556             #if qDNGValidate
0557 
0558             if (gVerbose)
0559                 {
0560 
0561                 printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n",
0562                         (unsigned) fProfileHues,
0563                         (unsigned) fProfileSats,
0564                         (unsigned) fProfileVals);
0565 
0566                 }
0567 
0568             #endif
0569 
0570             break;
0571 
0572             }
0573 
0574         case tcProfileHueSatMapData1:
0575             {
0576 
0577             if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
0578                 return false;
0579 
0580             if (fProfileSats == 0)
0581                 return false;
0582 
0583             dng_safe_uint32 hueCount (fProfileHues);
0584             dng_safe_uint32 valCount (fProfileVals);
0585 
0586             bool skipSat0 = (tagCount == (hueCount *
0587                                           (fProfileSats - 1) *
0588                                           (valCount * 3u)).Get ());
0589 
0590             if (!skipSat0)
0591                 {
0592 
0593                 dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u;
0594 
0595                 if (!CheckTagCount (parentCode,
0596                                     tagCode,
0597                                     tagCount,
0598                                     expected.Get ()))
0599                     {
0600                     return false;
0601                     }
0602 
0603                 }
0604 
0605             fBigEndian = stream.BigEndian ();
0606 
0607             fHueSatDeltas1Offset = tagOffset;
0608             fHueSatDeltas1Count  = tagCount;
0609 
0610             #if qDNGValidate
0611 
0612             if (gVerbose)
0613                 {
0614 
0615                 printf ("ProfileHueSatMapData1:\n");
0616 
0617                 DumpHueSatMap (stream,
0618                                fProfileHues,
0619                                fProfileSats,
0620                                fProfileVals,
0621                                skipSat0);
0622 
0623                 }
0624 
0625             #endif
0626 
0627             break;
0628 
0629             }
0630 
0631         case tcProfileHueSatMapData2:
0632             {
0633 
0634             if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
0635                 return false;
0636 
0637             if (fProfileSats == 0)
0638                 return false;
0639 
0640             dng_safe_uint32 hueCount (fProfileHues);
0641             dng_safe_uint32 valCount (fProfileVals);
0642 
0643             bool skipSat0 = (tagCount == (hueCount *
0644                                           (fProfileSats - 1) *
0645                                           (valCount * 3u)).Get ());
0646 
0647             if (!skipSat0)
0648                 {
0649 
0650                 dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u;
0651 
0652                 if (!CheckTagCount (parentCode,
0653                                     tagCode,
0654                                     tagCount,
0655                                     expected.Get ()))
0656                     {
0657                     return false;
0658                     }
0659 
0660                 }
0661 
0662             fBigEndian = stream.BigEndian ();
0663 
0664             fHueSatDeltas2Offset = tagOffset;
0665             fHueSatDeltas2Count  = tagCount;
0666 
0667             #if qDNGValidate
0668 
0669             if (gVerbose)
0670                 {
0671 
0672                 printf ("ProfileHueSatMapData2:\n");
0673 
0674                 DumpHueSatMap (stream,
0675                                fProfileHues,
0676                                fProfileSats,
0677                                fProfileVals,
0678                                skipSat0);
0679 
0680                 }
0681 
0682             #endif
0683 
0684             break;
0685 
0686             }
0687 
0688         case tcProfileHueSatMapEncoding:
0689             {
0690 
0691             CheckTagType (parentCode, tagCode, tagType, ttLong);
0692 
0693             CheckTagCount (parentCode, tagCode, tagCount, 1);
0694 
0695             fHueSatMapEncoding = stream.TagValue_uint32 (tagType);
0696 
0697             #if qDNGValidate
0698 
0699             if (gVerbose)
0700                 {
0701 
0702                 const char *encoding = NULL;
0703 
0704                 switch (fHueSatMapEncoding)
0705                     {
0706 
0707                     case encoding_Linear:
0708                         encoding = "Linear";
0709                         break;
0710 
0711                     case encoding_sRGB:
0712                         encoding = "sRGB";
0713                         break;
0714 
0715                     default:
0716                         encoding = "INVALID VALUE";
0717 
0718                     }
0719 
0720                 printf ("ProfileHueSatMapEncoding: %s\n", encoding);
0721 
0722                 }
0723 
0724             #endif
0725 
0726             break;
0727 
0728             }
0729 
0730         case tcProfileLookTableDims:
0731             {
0732 
0733             CheckTagType (parentCode, tagCode, tagType, ttLong);
0734 
0735             CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
0736 
0737             fLookTableHues = stream.TagValue_uint32 (tagType);
0738             fLookTableSats = stream.TagValue_uint32 (tagType);
0739 
0740             if (tagCount > 2)
0741                 fLookTableVals = stream.TagValue_uint32 (tagType);
0742             else
0743                 fLookTableVals = 1;
0744 
0745             #if qDNGValidate
0746 
0747             if (gVerbose)
0748                 {
0749 
0750                 printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n",
0751                         (unsigned) fLookTableHues,
0752                         (unsigned) fLookTableSats,
0753                         (unsigned) fLookTableVals);
0754 
0755                 }
0756 
0757             #endif
0758 
0759             break;
0760 
0761             }
0762 
0763         case tcProfileLookTableData:
0764             {
0765 
0766             if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
0767                 return false;
0768 
0769             if (fLookTableSats == 0)
0770                 return false;
0771 
0772             dng_safe_uint32 hueCount (fLookTableHues);
0773             dng_safe_uint32 valCount (fLookTableVals);
0774 
0775             bool skipSat0 = (tagCount == (hueCount *
0776                                           (fLookTableSats - 1) *
0777                                           valCount * 3u).Get ());
0778 
0779             if (!skipSat0)
0780                 {
0781 
0782                 dng_safe_uint32 expected = hueCount * valCount * fLookTableSats * 3u;
0783 
0784                 if (!CheckTagCount (parentCode,
0785                                     tagCode,
0786                                     tagCount,
0787                                     expected.Get ()))
0788                     {
0789                     return false;
0790                     }
0791 
0792                 }
0793 
0794             fBigEndian = stream.BigEndian ();
0795 
0796             fLookTableOffset = tagOffset;
0797             fLookTableCount  = tagCount;
0798 
0799             #if qDNGValidate
0800 
0801             if (gVerbose)
0802                 {
0803 
0804                 printf ("ProfileLookTableData:\n");
0805 
0806                 DumpHueSatMap (stream,
0807                                fLookTableHues,
0808                                fLookTableSats,
0809                                fLookTableVals,
0810                                skipSat0);
0811 
0812                 }
0813 
0814             #endif
0815 
0816             break;
0817 
0818             }
0819 
0820         case tcProfileLookTableEncoding:
0821             {
0822 
0823             CheckTagType (parentCode, tagCode, tagType, ttLong);
0824 
0825             CheckTagCount (parentCode, tagCode, tagCount, 1);
0826 
0827             fLookTableEncoding = stream.TagValue_uint32 (tagType);
0828 
0829             #if qDNGValidate
0830 
0831             if (gVerbose)
0832                 {
0833 
0834                 const char *encoding = NULL;
0835 
0836                 switch (fLookTableEncoding)
0837                     {
0838 
0839                     case encoding_Linear:
0840                         encoding = "Linear";
0841                         break;
0842 
0843                     case encoding_sRGB:
0844                         encoding = "sRGB";
0845                         break;
0846 
0847                     default:
0848                         encoding = "INVALID VALUE";
0849 
0850                     }
0851 
0852                 printf ("ProfileLookTableEncoding: %s\n", encoding);
0853 
0854                 }
0855 
0856             #endif
0857 
0858             break;
0859 
0860             }
0861 
0862         case tcBaselineExposureOffset:
0863             {
0864 
0865             CheckTagType (parentCode, tagCode, tagType, ttSRational);
0866 
0867             CheckTagCount (parentCode, tagCode, tagCount, 1);
0868 
0869             fBaselineExposureOffset = stream.TagValue_srational (tagType);
0870 
0871             #if qDNGValidate
0872 
0873             if (gVerbose)
0874                 {
0875 
0876                 printf ("BaselineExposureOffset: %+0.2f\n",
0877                         fBaselineExposureOffset.As_real64 ());
0878 
0879                 }
0880 
0881             #endif
0882 
0883             break;
0884 
0885             }
0886 
0887         case tcDefaultBlackRender:
0888             {
0889 
0890             CheckTagType (parentCode, tagCode, tagType, ttLong);
0891 
0892             CheckTagCount (parentCode, tagCode, tagCount, 1);
0893 
0894             fDefaultBlackRender = stream.TagValue_uint32 (tagType);
0895 
0896             #if qDNGValidate
0897 
0898             if (gVerbose)
0899                 {
0900 
0901                 const char *setting = NULL;
0902 
0903                 switch (fDefaultBlackRender)
0904                     {
0905 
0906                     case defaultBlackRender_Auto:
0907                         setting = "Auto";
0908                         break;
0909 
0910                     case defaultBlackRender_None:
0911                         setting = "None";
0912                         break;
0913 
0914                     default:
0915                         setting = "INVALID VALUE";
0916 
0917                     }
0918 
0919                 printf ("DefaultBlackRender: %s\n",
0920                         setting);
0921 
0922                 }
0923 
0924             #endif
0925 
0926             break;
0927 
0928             }
0929 
0930         case tcProfileToneCurve:
0931             {
0932 
0933             if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
0934                 return false;
0935 
0936             if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
0937                 return false;
0938 
0939             if ((tagCount & 1) != 0)
0940                 {
0941 
0942                 #if qDNGValidate
0943 
0944                     {
0945 
0946                     char message [256];
0947 
0948                     sprintf (message,
0949                              "%s %s has odd count (%u)",
0950                              LookupParentCode (parentCode),
0951                              LookupTagCode (parentCode, tagCode),
0952                              (unsigned) tagCount);
0953 
0954                     ReportWarning (message);
0955 
0956                     }
0957 
0958                 #endif
0959 
0960                 return false;
0961 
0962                 }
0963 
0964             fBigEndian = stream.BigEndian ();
0965 
0966             fToneCurveOffset = tagOffset;
0967             fToneCurveCount  = tagCount;
0968 
0969             #if qDNGValidate
0970 
0971             if (gVerbose)
0972                 {
0973 
0974                 DumpTagValues (stream,
0975                                "Coord",
0976                                parentCode,
0977                                tagCode,
0978                                tagType,
0979                                tagCount);
0980 
0981 
0982                 }
0983 
0984             #endif
0985 
0986             break;
0987 
0988             }
0989 
0990         case tcUniqueCameraModel:
0991             {
0992 
0993             // Note: This code is only used when parsing stand-alone
0994             // profiles.  The embedded profiles are assumed to be restricted
0995             // to the model they are embedded in.
0996 
0997             CheckTagType (parentCode, tagCode, tagType, ttAscii);
0998 
0999             ParseStringTag (stream,
1000                             parentCode,
1001                             tagCode,
1002                             tagCount,
1003                             fUniqueCameraModel,
1004                             false);
1005 
1006             bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
1007 
1008             #if qDNGValidate
1009 
1010             if (didTrim)
1011                 {
1012 
1013                 ReportWarning ("UniqueCameraModel string has trailing blanks");
1014 
1015                 }
1016 
1017             if (gVerbose)
1018                 {
1019 
1020                 printf ("UniqueCameraModel: ");
1021 
1022                 DumpString (fUniqueCameraModel);
1023 
1024                 printf ("\n");
1025 
1026                 }
1027 
1028             #else
1029 
1030             (void) didTrim;     // Unused
1031 
1032             #endif
1033 
1034             break;
1035 
1036             }
1037 
1038         default:
1039             {
1040 
1041             return false;
1042 
1043             }
1044 
1045         }
1046 
1047     return true;
1048 
1049     }
1050 
1051 /*****************************************************************************/
1052 
1053 bool dng_camera_profile_info::ParseExtended (dng_stream &stream)
1054     {
1055 
1056     try
1057         {
1058 
1059         // Offsets are relative to the start of this structure, not the entire file.
1060 
1061         uint64 startPosition = stream.Position ();
1062 
1063         // Read header. Like a TIFF header, but with different magic number
1064         // Plus all offsets are relative to the start of the IFD, not to the
1065         // stream or file.
1066 
1067         uint16 byteOrder = stream.Get_uint16 ();
1068 
1069         if (byteOrder == byteOrderMM)
1070             fBigEndian = true;
1071 
1072         else if (byteOrder == byteOrderII)
1073             fBigEndian = false;
1074 
1075         else
1076             return false;
1077 
1078         TempBigEndian setEndianness (stream, fBigEndian);
1079 
1080         uint16 magicNumber = stream.Get_uint16 ();
1081 
1082         if (magicNumber != magicExtendedProfile)
1083             {
1084             return false;
1085             }
1086 
1087         uint32 offset = stream.Get_uint32 ();
1088 
1089         stream.Skip (offset - 8);
1090 
1091         // Start on IFD entries.
1092 
1093         uint32 ifdEntries = stream.Get_uint16 ();
1094 
1095         if (ifdEntries < 1)
1096             {
1097             return false;
1098             }
1099 
1100         for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
1101             {
1102 
1103             stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12);
1104 
1105             uint16 tagCode  = stream.Get_uint16 ();
1106             uint32 tagType  = stream.Get_uint16 ();
1107             uint32 tagCount = stream.Get_uint32 ();
1108 
1109             uint64 tagOffset = stream.Position ();
1110 
1111             if (TagTypeSize (tagType) * tagCount > 4)
1112                 {
1113 
1114                 tagOffset = startPosition + stream.Get_uint32 ();
1115 
1116                 stream.SetReadPosition (tagOffset);
1117 
1118                 }
1119 
1120             if (!ParseTag (stream,
1121                            0,
1122                            tagCode,
1123                            tagType,
1124                            tagCount,
1125                            tagOffset))
1126                 {
1127 
1128                 #if qDNGValidate
1129 
1130                 if (gVerbose)
1131                     {
1132 
1133                     stream.SetReadPosition (tagOffset);
1134 
1135                     printf ("*");
1136 
1137                     DumpTagValues (stream,
1138                                    LookupTagType (tagType),
1139                                    0,
1140                                    tagCode,
1141                                    tagType,
1142                                    tagCount);
1143 
1144                     }
1145 
1146                 #endif
1147 
1148                 }
1149 
1150             }
1151 
1152         return true;
1153 
1154         }
1155 
1156     catch (...)
1157         {
1158 
1159         // Eat parsing errors.
1160 
1161         }
1162 
1163     return false;
1164 
1165     }
1166 
1167 /*****************************************************************************/
1168 
1169 dng_shared::dng_shared ()
1170 
1171     :   fExifIFD             (0)
1172     ,   fGPSInfo             (0)
1173     ,   fInteroperabilityIFD (0)
1174     ,   fKodakDCRPrivateIFD  (0)
1175     ,   fKodakKDCPrivateIFD  (0)
1176 
1177     ,   fXMPCount  (0)
1178     ,   fXMPOffset (0)
1179 
1180     ,   fIPTC_NAA_Count  (0)
1181     ,   fIPTC_NAA_Offset (0)
1182 
1183     ,   fMakerNoteCount  (0)
1184     ,   fMakerNoteOffset (0)
1185     ,   fMakerNoteSafety (0)
1186 
1187     ,   fDNGVersion         (0)
1188     ,   fDNGBackwardVersion (0)
1189 
1190     ,   fUniqueCameraModel    ()
1191     ,   fLocalizedCameraModel ()
1192 
1193     ,   fCameraProfile ()
1194 
1195     ,   fExtraCameraProfiles ()
1196 
1197     ,   fCameraCalibration1 ()
1198     ,   fCameraCalibration2 ()
1199 
1200     ,   fCameraCalibrationSignature  ()
1201 
1202     ,   fAnalogBalance ()
1203 
1204     ,   fAsShotNeutral ()
1205 
1206     ,   fAsShotWhiteXY ()
1207 
1208     ,   fBaselineExposure      (0, 1)
1209     ,   fBaselineNoise         (1, 1)
1210     ,   fBaselineSharpness     (1, 1)
1211     ,   fLinearResponseLimit   (1, 1)
1212     ,   fShadowScale           (1, 1)
1213 
1214     ,   fHasBaselineExposure (false)
1215     ,   fHasShadowScale      (false)
1216 
1217     ,   fDNGPrivateDataCount  (0)
1218     ,   fDNGPrivateDataOffset (0)
1219 
1220     ,   fRawImageDigest    ()
1221     ,   fNewRawImageDigest ()
1222 
1223     ,   fRawDataUniqueID ()
1224 
1225     ,   fOriginalRawFileName ()
1226 
1227     ,   fOriginalRawFileDataCount  (0)
1228     ,   fOriginalRawFileDataOffset (0)
1229 
1230     ,   fOriginalRawFileDigest ()
1231 
1232     ,   fAsShotICCProfileCount  (0)
1233     ,   fAsShotICCProfileOffset (0)
1234 
1235     ,   fAsShotPreProfileMatrix ()
1236 
1237     ,   fCurrentICCProfileCount  (0)
1238     ,   fCurrentICCProfileOffset (0)
1239 
1240     ,   fCurrentPreProfileMatrix ()
1241 
1242     ,   fColorimetricReference (crSceneReferred)
1243 
1244     ,   fAsShotProfileName ()
1245 
1246     ,   fOriginalDefaultFinalSize     ()
1247     ,   fOriginalBestQualityFinalSize ()
1248 
1249     ,   fOriginalDefaultCropSizeH ()
1250     ,   fOriginalDefaultCropSizeV ()
1251 
1252     ,   fDepthFormat      (depthFormatUnknown)
1253     ,   fDepthNear        (0, 0)
1254     ,   fDepthFar         (0, 0)
1255     ,   fDepthUnits       (depthUnitsUnknown)
1256     ,   fDepthMeasureType (depthMeasureUnknown)
1257 
1258     {
1259 
1260     }
1261 
1262 /*****************************************************************************/
1263 
1264 dng_shared::~dng_shared ()
1265     {
1266 
1267     }
1268 
1269 /*****************************************************************************/
1270 
1271 bool dng_shared::ParseTag (dng_stream &stream,
1272                            dng_exif &exif,
1273                            uint32 parentCode,
1274                            bool /* isMainIFD */,
1275                            uint32 tagCode,
1276                            uint32 tagType,
1277                            uint32 tagCount,
1278                            uint64 tagOffset,
1279                            int64 /* offsetDelta */)
1280     {
1281 
1282     if (parentCode == 0)
1283         {
1284 
1285         if (Parse_ifd0 (stream,
1286                         exif,
1287                         parentCode,
1288                         tagCode,
1289                         tagType,
1290                         tagCount,
1291                         tagOffset))
1292             {
1293 
1294             return true;
1295 
1296             }
1297 
1298         }
1299 
1300     if (parentCode == 0 ||
1301         parentCode == tcExifIFD)
1302         {
1303 
1304         if (Parse_ifd0_exif (stream,
1305                              exif,
1306                              parentCode,
1307                              tagCode,
1308                              tagType,
1309                              tagCount,
1310                              tagOffset))
1311             {
1312 
1313             return true;
1314 
1315             }
1316 
1317         }
1318 
1319     return false;
1320 
1321     }
1322 
1323 /*****************************************************************************/
1324 
1325 // Parses tags that should only appear in IFD 0.
1326 
1327 bool dng_shared::Parse_ifd0 (dng_stream &stream,
1328                              dng_exif & /* exif */,
1329                              uint32 parentCode,
1330                              uint32 tagCode,
1331                              uint32 tagType,
1332                              uint32 tagCount,
1333                              uint64 tagOffset)
1334     {
1335 
1336     switch (tagCode)
1337         {
1338 
1339         case tcXMP:
1340             {
1341 
1342             CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined);
1343 
1344             fXMPCount  = tagCount;
1345             fXMPOffset = fXMPCount ? tagOffset : 0;
1346 
1347             #if qDNGValidate
1348 
1349             if (gVerbose)
1350                 {
1351 
1352                 printf ("XMP: Count = %u, Offset = %u\n",
1353                         (unsigned) fXMPCount,
1354                         (unsigned) fXMPOffset);
1355 
1356                 if (fXMPCount)
1357                     {
1358 
1359                     DumpXMP (stream, fXMPCount);
1360 
1361                     }
1362 
1363                 }
1364 
1365             #endif
1366 
1367             break;
1368 
1369             }
1370 
1371         case tcIPTC_NAA:
1372             {
1373 
1374             CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined);
1375 
1376             fIPTC_NAA_Count = (dng_safe_uint32 (tagCount) * TagTypeSize (tagType)).Get ();
1377             fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0;
1378 
1379             #if qDNGValidate
1380 
1381             if (gVerbose)
1382                 {
1383 
1384                 printf ("IPTC/NAA: Count = %u, Offset = %u\n",
1385                         (unsigned) fIPTC_NAA_Count,
1386                         (unsigned) fIPTC_NAA_Offset);
1387 
1388                 if (fIPTC_NAA_Count)
1389                     {
1390 
1391                     DumpHexAscii (stream, fIPTC_NAA_Count);
1392 
1393                     }
1394 
1395                 // Compute and output the digest.
1396 
1397                 dng_memory_data buffer (fIPTC_NAA_Count);
1398 
1399                 stream.SetReadPosition (fIPTC_NAA_Offset);
1400 
1401                 stream.Get (buffer.Buffer (), fIPTC_NAA_Count);
1402 
1403                 const uint8 *data = buffer.Buffer_uint8 ();
1404 
1405                 uint32 count = fIPTC_NAA_Count;
1406 
1407                 // Method 1: Counting all bytes (this is correct).
1408 
1409                     {
1410 
1411                     dng_md5_printer printer;
1412 
1413                     printer.Process (data, count);
1414 
1415                     printf ("IPTCDigest: ");
1416 
1417                     DumpFingerprint (printer.Result ());
1418 
1419                     printf ("\n");
1420 
1421                     }
1422 
1423                 // Method 2: Ignoring zero padding.
1424 
1425                     {
1426 
1427                     uint32 removed = 0;
1428 
1429                     while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
1430                         {
1431                         removed++;
1432                         count--;
1433                         }
1434 
1435                     if (removed != 0)
1436                         {
1437 
1438                         dng_md5_printer printer;
1439 
1440                         printer.Process (data, count);
1441 
1442                         printf ("IPTCDigest (ignoring zero padding): ");
1443 
1444                         DumpFingerprint (printer.Result ());
1445 
1446                         printf ("\n");
1447 
1448                         }
1449 
1450                     }
1451 
1452                 }
1453 
1454             #endif
1455 
1456             break;
1457 
1458             }
1459 
1460         case tcExifIFD:
1461             {
1462 
1463             CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1464 
1465             CheckTagCount (parentCode, tagCode, tagCount, 1);
1466 
1467             fExifIFD = stream.TagValue_uint32 (tagType);
1468 
1469             #if qDNGValidate
1470 
1471             if (gVerbose)
1472                 {
1473                 printf ("ExifIFD: %u\n", (unsigned) fExifIFD);
1474                 }
1475 
1476             #endif
1477 
1478             break;
1479 
1480             }
1481 
1482         case tcGPSInfo:
1483             {
1484 
1485             CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1486 
1487             CheckTagCount (parentCode, tagCode, tagCount, 1);
1488 
1489             fGPSInfo = stream.TagValue_uint32 (tagType);
1490 
1491             #if qDNGValidate
1492 
1493             if (gVerbose)
1494                 {
1495                 printf ("GPSInfo: %u\n", (unsigned) fGPSInfo);
1496                 }
1497 
1498             #endif
1499 
1500             break;
1501 
1502             }
1503 
1504         case tcKodakDCRPrivateIFD:
1505             {
1506 
1507             CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1508 
1509             CheckTagCount (parentCode, tagCode, tagCount, 1);
1510 
1511             fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType);
1512 
1513             #if qDNGValidate
1514 
1515             if (gVerbose)
1516                 {
1517                 printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD);
1518                 }
1519 
1520             #endif
1521 
1522             break;
1523 
1524             }
1525 
1526         case tcKodakKDCPrivateIFD:
1527             {
1528 
1529             CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1530 
1531             CheckTagCount (parentCode, tagCode, tagCount, 1);
1532 
1533             fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType);
1534 
1535             #if qDNGValidate
1536 
1537             if (gVerbose)
1538                 {
1539                 printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD);
1540                 }
1541 
1542             #endif
1543 
1544             break;
1545 
1546             }
1547 
1548         case tcDNGVersion:
1549             {
1550 
1551             CheckTagType (parentCode, tagCode, tagType, ttByte);
1552 
1553             CheckTagCount (parentCode, tagCode, tagCount, 4);
1554 
1555             uint32 b0 = stream.Get_uint8 ();
1556             uint32 b1 = stream.Get_uint8 ();
1557             uint32 b2 = stream.Get_uint8 ();
1558             uint32 b3 = stream.Get_uint8 ();
1559 
1560             fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1561 
1562             #if qDNGValidate
1563 
1564             if (gVerbose)
1565                 {
1566                 printf ("DNGVersion: %u.%u.%u.%u\n",
1567                         (unsigned) b0,
1568                         (unsigned) b1,
1569                         (unsigned) b2,
1570                         (unsigned) b3);
1571                 }
1572 
1573             #endif
1574 
1575             break;
1576 
1577             }
1578 
1579         case tcDNGBackwardVersion:
1580             {
1581 
1582             CheckTagType (parentCode, tagCode, tagType, ttByte);
1583 
1584             CheckTagCount (parentCode, tagCode, tagCount, 4);
1585 
1586             uint32 b0 = stream.Get_uint8 ();
1587             uint32 b1 = stream.Get_uint8 ();
1588             uint32 b2 = stream.Get_uint8 ();
1589             uint32 b3 = stream.Get_uint8 ();
1590 
1591             fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1592 
1593             #if qDNGValidate
1594 
1595             if (gVerbose)
1596                 {
1597                 printf ("DNGBackwardVersion: %u.%u.%u.%u\n",
1598                         (unsigned) b0,
1599                         (unsigned) b1,
1600                         (unsigned) b2,
1601                         (unsigned) b3);
1602                 }
1603 
1604             #endif
1605 
1606             break;
1607 
1608             }
1609 
1610         case tcUniqueCameraModel:
1611             {
1612 
1613             CheckTagType (parentCode, tagCode, tagType, ttAscii);
1614 
1615             ParseStringTag (stream,
1616                             parentCode,
1617                             tagCode,
1618                             tagCount,
1619                             fUniqueCameraModel,
1620                             false);
1621 
1622             bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
1623 
1624             #if qDNGValidate
1625 
1626             if (didTrim)
1627                 {
1628 
1629                 ReportWarning ("UniqueCameraModel string has trailing blanks");
1630 
1631                 }
1632 
1633             if (gVerbose)
1634                 {
1635 
1636                 printf ("UniqueCameraModel: ");
1637 
1638                 DumpString (fUniqueCameraModel);
1639 
1640                 printf ("\n");
1641 
1642                 }
1643 
1644             #else
1645 
1646             (void) didTrim;     // Unused
1647 
1648             #endif
1649 
1650             break;
1651 
1652             }
1653 
1654         case tcLocalizedCameraModel:
1655             {
1656 
1657             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1658 
1659             ParseStringTag (stream,
1660                             parentCode,
1661                             tagCode,
1662                             tagCount,
1663                             fLocalizedCameraModel,
1664                             false);
1665 
1666             bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks ();
1667 
1668             #if qDNGValidate
1669 
1670             if (didTrim)
1671                 {
1672 
1673                 ReportWarning ("LocalizedCameraModel string has trailing blanks");
1674 
1675                 }
1676 
1677             if (gVerbose)
1678                 {
1679 
1680                 printf ("LocalizedCameraModel: ");
1681 
1682                 DumpString (fLocalizedCameraModel);
1683 
1684                 printf ("\n");
1685 
1686                 }
1687 
1688             #else
1689 
1690             (void) didTrim;     // Unused
1691 
1692             #endif
1693 
1694             break;
1695 
1696             }
1697 
1698         case tcCameraCalibration1:
1699             {
1700 
1701             CheckTagType (parentCode, tagCode, tagType, ttSRational);
1702 
1703             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1704                 return false;
1705 
1706             if (!ParseMatrixTag (stream,
1707                                  parentCode,
1708                                  tagCode,
1709                                  tagType,
1710                                  tagCount,
1711                                  fCameraProfile.fColorPlanes,
1712                                  fCameraProfile.fColorPlanes,
1713                                  fCameraCalibration1))
1714                 return false;
1715 
1716             #if qDNGValidate
1717 
1718             if (gVerbose)
1719                 {
1720 
1721                 printf ("CameraCalibration1:\n");
1722 
1723                 DumpMatrix (fCameraCalibration1);
1724 
1725                 }
1726 
1727             #endif
1728 
1729             break;
1730 
1731             }
1732 
1733         case tcCameraCalibration2:
1734             {
1735 
1736             CheckTagType (parentCode, tagCode, tagType, ttSRational);
1737 
1738             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1739                 return false;
1740 
1741             if (!ParseMatrixTag (stream,
1742                                  parentCode,
1743                                  tagCode,
1744                                  tagType,
1745                                  tagCount,
1746                                  fCameraProfile.fColorPlanes,
1747                                  fCameraProfile.fColorPlanes,
1748                                  fCameraCalibration2))
1749                 return false;
1750 
1751             #if qDNGValidate
1752 
1753             if (gVerbose)
1754                 {
1755 
1756                 printf ("CameraCalibration2:\n");
1757 
1758                 DumpMatrix (fCameraCalibration2);
1759 
1760                 }
1761 
1762             #endif
1763 
1764             break;
1765 
1766             }
1767 
1768         case tcCameraCalibrationSignature:
1769             {
1770 
1771             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1772 
1773             ParseStringTag (stream,
1774                             parentCode,
1775                             tagCode,
1776                             tagCount,
1777                             fCameraCalibrationSignature,
1778                             false);
1779 
1780             #if qDNGValidate
1781 
1782             if (gVerbose)
1783                 {
1784 
1785                 printf ("CameraCalibrationSignature: ");
1786 
1787                 DumpString (fCameraCalibrationSignature);
1788 
1789                 printf ("\n");
1790 
1791                 }
1792 
1793             #endif
1794 
1795             break;
1796 
1797             }
1798 
1799         case tcAnalogBalance:
1800             {
1801 
1802             CheckTagType (parentCode, tagCode, tagType, ttRational);
1803 
1804             // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
1805             // they don't have any ColorMatrix tags.
1806 
1807             bool hasselbladHack = (fDNGVersion == 0 &&
1808                                    fCameraProfile.fColorPlanes == 0);
1809 
1810             if (hasselbladHack)
1811                 {
1812 
1813                 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1814 
1815                 #if qDNGValidate
1816 
1817                 ReportWarning ("AnalogBalance without ColorMatrix1");
1818 
1819                 #endif
1820 
1821                 }
1822 
1823             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1824                 return false;
1825 
1826             if (!ParseVectorTag (stream,
1827                                  parentCode,
1828                                  tagCode,
1829                                  tagType,
1830                                  tagCount,
1831                                  fCameraProfile.fColorPlanes,
1832                                  fAnalogBalance))
1833                 return false;
1834 
1835             #if qDNGValidate
1836 
1837             if (gVerbose)
1838                 {
1839 
1840                 printf ("AnalogBalance:");
1841 
1842                 DumpVector (fAnalogBalance);
1843 
1844                 }
1845 
1846             #endif
1847 
1848             break;
1849 
1850             }
1851 
1852         case tcAsShotNeutral:
1853             {
1854 
1855             CheckTagType (parentCode, tagCode, tagType, ttRational);
1856 
1857             // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
1858             // they don't have any ColorMatrix tags.
1859 
1860             bool hasselbladHack = (fDNGVersion == 0 &&
1861                                    fCameraProfile.fColorPlanes == 0);
1862 
1863             if (hasselbladHack)
1864                 {
1865 
1866                 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1867 
1868                 #if qDNGValidate
1869 
1870                 ReportWarning ("AsShotNeutral without ColorMatrix1");
1871 
1872                 #endif
1873 
1874                 }
1875 
1876             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1877                 return false;
1878 
1879             if (!ParseVectorTag (stream,
1880                                  parentCode,
1881                                  tagCode,
1882                                  tagType,
1883                                  tagCount,
1884                                  fCameraProfile.fColorPlanes,
1885                                  fAsShotNeutral))
1886                 return false;
1887 
1888             #if qDNGValidate
1889 
1890             if (gVerbose)
1891                 {
1892 
1893                 printf ("AsShotNeutral:");
1894 
1895                 DumpVector (fAsShotNeutral);
1896 
1897                 }
1898 
1899             #endif
1900 
1901             break;
1902 
1903             }
1904 
1905         case tcAsShotWhiteXY:
1906             {
1907 
1908             CheckTagType (parentCode, tagCode, tagType, ttRational);
1909 
1910             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1911                 return false;
1912 
1913             if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1914                 return false;
1915 
1916             fAsShotWhiteXY.x = stream.TagValue_real64 (tagType);
1917             fAsShotWhiteXY.y = stream.TagValue_real64 (tagType);
1918 
1919             #if qDNGValidate
1920 
1921             if (gVerbose)
1922                 {
1923 
1924                 printf ("AsShotWhiteXY: %0.4f %0.4f\n",
1925                         fAsShotWhiteXY.x,
1926                         fAsShotWhiteXY.y);
1927 
1928                 }
1929 
1930             #endif
1931 
1932             break;
1933 
1934             }
1935 
1936         case tcBaselineExposure:
1937             {
1938 
1939             CheckTagType (parentCode, tagCode, tagType, ttSRational);
1940 
1941             CheckTagCount (parentCode, tagCode, tagCount, 1);
1942 
1943             fBaselineExposure = stream.TagValue_srational (tagType);
1944 
1945             fHasBaselineExposure = true;
1946 
1947             #if qDNGValidate
1948 
1949             if (gVerbose)
1950                 {
1951 
1952                 printf ("BaselineExposure: %+0.2f\n",
1953                         fBaselineExposure.As_real64 ());
1954 
1955                 }
1956 
1957             #endif
1958 
1959             break;
1960 
1961             }
1962 
1963         case tcBaselineNoise:
1964             {
1965 
1966             CheckTagType (parentCode, tagCode, tagType, ttRational);
1967 
1968             CheckTagCount (parentCode, tagCode, tagCount, 1);
1969 
1970             fBaselineNoise = stream.TagValue_urational (tagType);
1971 
1972             #if qDNGValidate
1973 
1974             if (gVerbose)
1975                 {
1976 
1977                 printf ("BaselineNoise: %0.2f\n",
1978                         fBaselineNoise.As_real64 ());
1979 
1980                 }
1981 
1982             #endif
1983 
1984             break;
1985 
1986             }
1987 
1988         case tcBaselineSharpness:
1989             {
1990 
1991             CheckTagType (parentCode, tagCode, tagType, ttRational);
1992 
1993             CheckTagCount (parentCode, tagCode, tagCount, 1);
1994 
1995             fBaselineSharpness = stream.TagValue_urational (tagType);
1996 
1997             #if qDNGValidate
1998 
1999             if (gVerbose)
2000                 {
2001 
2002                 printf ("BaselineSharpness: %0.2f\n",
2003                         fBaselineSharpness.As_real64 ());
2004 
2005                 }
2006 
2007             #endif
2008 
2009             break;
2010 
2011             }
2012 
2013         case tcLinearResponseLimit:
2014             {
2015 
2016             CheckTagType (parentCode, tagCode, tagType, ttRational);
2017 
2018             CheckTagCount (parentCode, tagCode, tagCount, 1);
2019 
2020             fLinearResponseLimit = stream.TagValue_urational (tagType);
2021 
2022             #if qDNGValidate
2023 
2024             if (gVerbose)
2025                 {
2026 
2027                 printf ("LinearResponseLimit: %0.2f\n",
2028                         fLinearResponseLimit.As_real64 ());
2029 
2030                 }
2031 
2032             #endif
2033 
2034             break;
2035 
2036             }
2037 
2038         case tcShadowScale:
2039             {
2040 
2041             CheckTagType (parentCode, tagCode, tagType, ttRational);
2042 
2043             CheckTagCount (parentCode, tagCode, tagCount, 1);
2044 
2045             fShadowScale = stream.TagValue_urational (tagType);
2046 
2047             fHasShadowScale = true;
2048 
2049             #if qDNGValidate
2050 
2051             if (gVerbose)
2052                 {
2053 
2054                 printf ("ShadowScale: %0.4f\n",
2055                         fShadowScale.As_real64 ());
2056 
2057                 }
2058 
2059             #endif
2060 
2061             break;
2062 
2063             }
2064 
2065         case tcDNGPrivateData:
2066             {
2067 
2068             CheckTagType (parentCode, tagCode, tagType, ttByte);
2069 
2070             fDNGPrivateDataCount  = tagCount;
2071             fDNGPrivateDataOffset = tagOffset;
2072 
2073             #if qDNGValidate
2074 
2075             if (gVerbose)
2076                 {
2077 
2078                 printf ("DNGPrivateData: Count = %u, Offset = %u\n",
2079                         (unsigned) fDNGPrivateDataCount,
2080                         (unsigned) fDNGPrivateDataOffset);
2081 
2082                 DumpHexAscii (stream, tagCount);
2083 
2084                 }
2085 
2086             #endif
2087 
2088             break;
2089 
2090             }
2091 
2092         case tcMakerNoteSafety:
2093             {
2094 
2095             CheckTagType (parentCode, tagCode, tagType, ttShort);
2096 
2097             CheckTagCount (parentCode, tagCode, tagCount, 1);
2098 
2099             fMakerNoteSafety = stream.TagValue_uint32 (tagType);
2100 
2101             #if qDNGValidate
2102 
2103             if (gVerbose)
2104                 {
2105 
2106                 printf ("MakerNoteSafety: %s\n",
2107                         LookupMakerNoteSafety (fMakerNoteSafety));
2108 
2109                 }
2110 
2111             #endif
2112 
2113             break;
2114 
2115             }
2116 
2117         case tcRawImageDigest:
2118             {
2119 
2120             if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2121                 return false;
2122 
2123             if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2124                 return false;
2125 
2126             stream.Get (fRawImageDigest.data, 16);
2127 
2128             #if qDNGValidate
2129 
2130             if (gVerbose)
2131                 {
2132 
2133                 printf ("RawImageDigest: ");
2134 
2135                 DumpFingerprint (fRawImageDigest);
2136 
2137                 printf ("\n");
2138 
2139                 }
2140 
2141             #endif
2142 
2143             break;
2144 
2145             }
2146 
2147         case tcNewRawImageDigest:
2148             {
2149 
2150             if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2151                 return false;
2152 
2153             if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2154                 return false;
2155 
2156             stream.Get (fNewRawImageDigest.data, 16);
2157 
2158             #if qDNGValidate
2159 
2160             if (gVerbose)
2161                 {
2162 
2163                 printf ("NewRawImageDigest: ");
2164 
2165                 DumpFingerprint (fNewRawImageDigest);
2166 
2167                 printf ("\n");
2168 
2169                 }
2170 
2171             #endif
2172 
2173             break;
2174 
2175             }
2176 
2177         case tcRawDataUniqueID:
2178             {
2179 
2180             if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2181                 return false;
2182 
2183             if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2184                 return false;
2185 
2186             stream.Get (fRawDataUniqueID.data, 16);
2187 
2188             #if qDNGValidate
2189 
2190             if (gVerbose)
2191                 {
2192 
2193                 printf ("RawDataUniqueID: ");
2194 
2195                 DumpFingerprint (fRawDataUniqueID);
2196 
2197                 printf ("\n");
2198 
2199                 }
2200 
2201             #endif
2202 
2203             break;
2204 
2205             }
2206 
2207         case tcOriginalRawFileName:
2208             {
2209 
2210             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2211 
2212             ParseStringTag (stream,
2213                             parentCode,
2214                             tagCode,
2215                             tagCount,
2216                             fOriginalRawFileName,
2217                             false);
2218 
2219             #if qDNGValidate
2220 
2221             if (gVerbose)
2222                 {
2223 
2224                 printf ("OriginalRawFileName: ");
2225 
2226                 DumpString (fOriginalRawFileName);
2227 
2228                 printf ("\n");
2229 
2230                 }
2231 
2232             #endif
2233 
2234             break;
2235 
2236             }
2237 
2238         case tcOriginalRawFileData:
2239             {
2240 
2241             CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2242 
2243             fOriginalRawFileDataCount  = tagCount;
2244             fOriginalRawFileDataOffset = tagOffset;
2245 
2246             #if qDNGValidate
2247 
2248             if (gVerbose)
2249                 {
2250 
2251                 printf ("OriginalRawFileData: Count = %u, Offset = %u\n",
2252                         (unsigned) fOriginalRawFileDataCount,
2253                         (unsigned) fOriginalRawFileDataOffset);
2254 
2255                 DumpHexAscii (stream, tagCount);
2256 
2257                 }
2258 
2259             #endif
2260 
2261             break;
2262 
2263             }
2264 
2265         case tcOriginalRawFileDigest:
2266             {
2267 
2268             if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2269                 return false;
2270 
2271             if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2272                 return false;
2273 
2274             stream.Get (fOriginalRawFileDigest.data, 16);
2275 
2276             #if qDNGValidate
2277 
2278             if (gVerbose)
2279                 {
2280 
2281                 printf ("OriginalRawFileDigest: ");
2282 
2283                 DumpFingerprint (fOriginalRawFileDigest);
2284 
2285                 printf ("\n");
2286 
2287                 }
2288 
2289             #endif
2290 
2291             break;
2292 
2293             }
2294 
2295         case tcAsShotICCProfile:
2296             {
2297 
2298             CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2299 
2300             fAsShotICCProfileCount  = tagCount;
2301             fAsShotICCProfileOffset = tagOffset;
2302 
2303             #if qDNGValidate
2304 
2305             if (gVerbose)
2306                 {
2307 
2308                 printf ("AsShotICCProfile: Count = %u, Offset = %u\n",
2309                         (unsigned) fAsShotICCProfileCount,
2310                         (unsigned) fAsShotICCProfileOffset);
2311 
2312                 DumpHexAscii (stream, tagCount);
2313 
2314                 }
2315 
2316             #endif
2317 
2318             break;
2319 
2320             }
2321 
2322         case tcAsShotPreProfileMatrix:
2323             {
2324 
2325             CheckTagType (parentCode, tagCode, tagType, ttSRational);
2326 
2327             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2328                 return false;
2329 
2330             uint32 rows = fCameraProfile.fColorPlanes;
2331 
2332             if (tagCount == fCameraProfile.fColorPlanes * 3)
2333                 {
2334                 rows = 3;
2335                 }
2336 
2337             if (!ParseMatrixTag (stream,
2338                                  parentCode,
2339                                  tagCode,
2340                                  tagType,
2341                                  tagCount,
2342                                  rows,
2343                                  fCameraProfile.fColorPlanes,
2344                                  fAsShotPreProfileMatrix))
2345                 return false;
2346 
2347             #if qDNGValidate
2348 
2349             if (gVerbose)
2350                 {
2351 
2352                 printf ("AsShotPreProfileMatrix:\n");
2353 
2354                 DumpMatrix (fAsShotPreProfileMatrix);
2355 
2356                 }
2357 
2358             #endif
2359 
2360             break;
2361 
2362             }
2363 
2364         case tcCurrentICCProfile:
2365             {
2366 
2367             CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2368 
2369             fCurrentICCProfileCount  = tagCount;
2370             fCurrentICCProfileOffset = tagOffset;
2371 
2372             #if qDNGValidate
2373 
2374             if (gVerbose)
2375                 {
2376 
2377                 printf ("CurrentICCProfile: Count = %u, Offset = %u\n",
2378                         (unsigned) fCurrentICCProfileCount,
2379                         (unsigned) fCurrentICCProfileOffset);
2380 
2381                 DumpHexAscii (stream, tagCount);
2382 
2383                 }
2384 
2385             #endif
2386 
2387             break;
2388 
2389             }
2390 
2391         case tcCurrentPreProfileMatrix:
2392             {
2393 
2394             CheckTagType (parentCode, tagCode, tagType, ttSRational);
2395 
2396             if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2397                 return false;
2398 
2399             uint32 rows = fCameraProfile.fColorPlanes;
2400 
2401             if (tagCount == fCameraProfile.fColorPlanes * 3)
2402                 {
2403                 rows = 3;
2404                 }
2405 
2406             if (!ParseMatrixTag (stream,
2407                                  parentCode,
2408                                  tagCode,
2409                                  tagType,
2410                                  tagCount,
2411                                  rows,
2412                                  fCameraProfile.fColorPlanes,
2413                                  fCurrentPreProfileMatrix))
2414                 return false;
2415 
2416             #if qDNGValidate
2417 
2418             if (gVerbose)
2419                 {
2420 
2421                 printf ("CurrentPreProfileMatrix:\n");
2422 
2423                 DumpMatrix (fCurrentPreProfileMatrix);
2424 
2425                 }
2426 
2427             #endif
2428 
2429             break;
2430 
2431             }
2432 
2433         case tcColorimetricReference:
2434             {
2435 
2436             CheckTagType (parentCode, tagCode, tagType, ttShort);
2437 
2438             CheckTagCount (parentCode, tagCode, tagCount, 1);
2439 
2440             fColorimetricReference = stream.TagValue_uint32 (tagType);
2441 
2442             #if qDNGValidate
2443 
2444             if (gVerbose)
2445                 {
2446 
2447                 printf ("ColorimetricReference: %s\n",
2448                         LookupColorimetricReference (fColorimetricReference));
2449 
2450                 }
2451 
2452             #endif
2453 
2454             break;
2455 
2456             }
2457 
2458         case tcExtraCameraProfiles:
2459             {
2460 
2461             CheckTagType (parentCode, tagCode, tagType, ttLong);
2462 
2463             CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount);
2464 
2465             #if qDNGValidate
2466 
2467             if (gVerbose)
2468                 {
2469 
2470                 printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount);
2471 
2472                 }
2473 
2474             #endif
2475 
2476             fExtraCameraProfiles.reserve (tagCount);
2477 
2478             for (uint32 index = 0; index < tagCount; index++)
2479                 {
2480 
2481                 #if qDNGValidate
2482 
2483                 if (gVerbose)
2484                     {
2485 
2486                     printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index);
2487 
2488                     }
2489 
2490                 #endif
2491 
2492                 stream.SetReadPosition (tagOffset + index * 4);
2493 
2494                 uint32 profileOffset = stream.TagValue_uint32 (tagType);
2495 
2496                 dng_camera_profile_info profileInfo;
2497 
2498                 stream.SetReadPosition (profileOffset);
2499 
2500                 if (profileInfo.ParseExtended (stream))
2501                     {
2502 
2503                     fExtraCameraProfiles.push_back (profileInfo);
2504 
2505                     }
2506 
2507                 else
2508                     {
2509 
2510                     #if qDNGValidate
2511 
2512                     ReportWarning ("Unable to parse extra camera profile");
2513 
2514                     #endif
2515 
2516                     }
2517 
2518                 }
2519 
2520             #if qDNGValidate
2521 
2522             if (gVerbose)
2523                 {
2524 
2525                 printf ("\nDone with ExtraCameraProfiles\n\n");
2526 
2527                 }
2528 
2529             #endif
2530 
2531             break;
2532 
2533             }
2534 
2535         case tcAsShotProfileName:
2536             {
2537 
2538             CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2539 
2540             ParseStringTag (stream,
2541                             parentCode,
2542                             tagCode,
2543                             tagCount,
2544                             fAsShotProfileName,
2545                             false);
2546 
2547             #if qDNGValidate
2548 
2549             if (gVerbose)
2550                 {
2551 
2552                 printf ("AsShotProfileName: ");
2553 
2554                 DumpString (fAsShotProfileName);
2555 
2556                 printf ("\n");
2557 
2558                 }
2559 
2560             #endif
2561 
2562             break;
2563 
2564             }
2565 
2566         case tcOriginalDefaultFinalSize:
2567             {
2568 
2569             CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2570 
2571             if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2572                 return false;
2573 
2574             fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType);
2575             fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType);
2576 
2577             #if qDNGValidate
2578 
2579             if (gVerbose)
2580                 {
2581 
2582                 printf ("OriginalDefaultFinalSize: H = %d V = %d\n",
2583                         (int) fOriginalDefaultFinalSize.h,
2584                         (int) fOriginalDefaultFinalSize.v);
2585 
2586                 }
2587 
2588             #endif
2589 
2590             break;
2591 
2592             }
2593 
2594         case tcOriginalBestQualityFinalSize:
2595             {
2596 
2597             CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2598 
2599             if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2600                 return false;
2601 
2602             fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType);
2603             fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType);
2604 
2605             #if qDNGValidate
2606 
2607             if (gVerbose)
2608                 {
2609 
2610                 printf ("OriginalBestQualityFinalSize: H = %d V = %d\n",
2611                         (int) fOriginalBestQualityFinalSize.h,
2612                         (int) fOriginalBestQualityFinalSize.v);
2613 
2614                 }
2615 
2616             #endif
2617 
2618             break;
2619 
2620             }
2621 
2622         case tcOriginalDefaultCropSize:
2623             {
2624 
2625             CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
2626 
2627             if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2628                 return false;
2629 
2630             fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType);
2631             fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType);
2632 
2633             #if qDNGValidate
2634 
2635             if (gVerbose)
2636                 {
2637 
2638                 printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n",
2639                         fOriginalDefaultCropSizeH.As_real64 (),
2640                         fOriginalDefaultCropSizeV.As_real64 ());
2641 
2642                 }
2643 
2644             #endif
2645 
2646             break;
2647 
2648             }
2649 
2650         case tcDepthFormat:
2651             {
2652 
2653             CheckTagType (parentCode, tagCode, tagType, ttShort);
2654 
2655             CheckTagCount (parentCode, tagCode, tagCount, 1);
2656 
2657             fDepthFormat = stream.TagValue_uint32 (tagType);
2658 
2659             #if qDNGValidate
2660 
2661             if (gVerbose)
2662                 {
2663 
2664                 printf ("DepthFormat: %s\n",
2665                         LookupDepthFormat (fDepthFormat));
2666 
2667                 }
2668 
2669             #endif
2670 
2671             break;
2672 
2673             }
2674 
2675         case tcDepthNear:
2676             {
2677 
2678             CheckTagType (parentCode, tagCode, tagType, ttRational);
2679 
2680             CheckTagCount (parentCode, tagCode, tagCount, 1);
2681 
2682             fDepthNear = stream.TagValue_urational (tagType);
2683 
2684             #if qDNGValidate
2685 
2686             if (gVerbose)
2687                 {
2688 
2689                 printf ("DepthNear: ");
2690 
2691                 if (fDepthNear == dng_urational (0, 0))
2692                     {
2693                     printf ("Unknown");
2694                     }
2695                 else if (fDepthNear.d == 0)
2696                     {
2697                     printf ("Infinity");
2698                     }
2699                 else
2700                     {
2701                     printf ("%0.2f", fDepthNear.As_real64 ());
2702                     }
2703 
2704                 printf ("\n");
2705 
2706                 }
2707 
2708             #endif
2709 
2710             break;
2711 
2712             }
2713 
2714          case tcDepthFar:
2715             {
2716 
2717             CheckTagType (parentCode, tagCode, tagType, ttRational);
2718 
2719             CheckTagCount (parentCode, tagCode, tagCount, 1);
2720 
2721             fDepthFar = stream.TagValue_urational (tagType);
2722 
2723             #if qDNGValidate
2724 
2725             if (gVerbose)
2726                 {
2727 
2728                 printf ("DepthFar: ");
2729 
2730                 if (fDepthFar == dng_urational (0, 0))
2731                     {
2732                     printf ("Unknown");
2733                     }
2734                 else if (fDepthFar.d == 0)
2735                     {
2736                     printf ("Infinity");
2737                     }
2738                 else
2739                     {
2740                     printf ("%0.2f", fDepthFar.As_real64 ());
2741                     }
2742 
2743                 printf ("\n");
2744 
2745                 }
2746 
2747             #endif
2748 
2749             break;
2750 
2751             }
2752 
2753         case tcDepthUnits:
2754             {
2755 
2756             CheckTagType (parentCode, tagCode, tagType, ttShort);
2757 
2758             CheckTagCount (parentCode, tagCode, tagCount, 1);
2759 
2760             fDepthUnits = stream.TagValue_uint32 (tagType);
2761 
2762             #if qDNGValidate
2763 
2764             if (gVerbose)
2765                 {
2766 
2767                 printf ("DepthUnits: %s\n",
2768                         LookupDepthUnits (fDepthUnits));
2769 
2770                 }
2771 
2772             #endif
2773 
2774             break;
2775 
2776             }
2777 
2778         case tcDepthMeasureType:
2779             {
2780 
2781             CheckTagType (parentCode, tagCode, tagType, ttShort);
2782 
2783             CheckTagCount (parentCode, tagCode, tagCount, 1);
2784 
2785             fDepthMeasureType = stream.TagValue_uint32 (tagType);
2786 
2787             #if qDNGValidate
2788 
2789             if (gVerbose)
2790                 {
2791 
2792                 printf ("DepthMeasureType: %s\n",
2793                         LookupDepthMeasureType (fDepthMeasureType));
2794 
2795                 }
2796 
2797             #endif
2798 
2799             break;
2800 
2801             }
2802 
2803         default:
2804             {
2805 
2806             // The main camera profile tags also appear in IFD 0
2807 
2808             return fCameraProfile.ParseTag (stream,
2809                                             parentCode,
2810                                             tagCode,
2811                                             tagType,
2812                                             tagCount,
2813                                             tagOffset);
2814 
2815             }
2816 
2817         }
2818 
2819     return true;
2820 
2821     }
2822 
2823 /*****************************************************************************/
2824 
2825 // Parses tags that should only appear in IFD 0 or EXIF IFD.
2826 
2827 bool dng_shared::Parse_ifd0_exif (dng_stream &stream,
2828                                   dng_exif & /* exif */,
2829                                   uint32 parentCode,
2830                                   uint32 tagCode,
2831                                   uint32 tagType,
2832                                   uint32 tagCount,
2833                                   uint64 tagOffset)
2834     {
2835 
2836     switch (tagCode)
2837         {
2838 
2839         case tcMakerNote:
2840             {
2841 
2842             CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2843 
2844             fMakerNoteCount  = tagCount;
2845             fMakerNoteOffset = tagOffset;
2846 
2847             #if qDNGValidate
2848 
2849             if (gVerbose)
2850                 {
2851 
2852                 printf ("MakerNote: Count = %u, Offset = %u\n",
2853                         (unsigned) fMakerNoteCount,
2854                         (unsigned) fMakerNoteOffset);
2855 
2856                 DumpHexAscii (stream, tagCount);
2857 
2858                 }
2859 
2860             #endif
2861 
2862             break;
2863 
2864             }
2865 
2866         case tcInteroperabilityIFD:
2867             {
2868 
2869             CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
2870 
2871             CheckTagCount (parentCode, tagCode, tagCount, 1);
2872 
2873             fInteroperabilityIFD = stream.TagValue_uint32 (tagType);
2874 
2875             #if qDNGValidate
2876 
2877             if (gVerbose)
2878                 {
2879                 printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD);
2880                 }
2881 
2882             #endif
2883 
2884             break;
2885 
2886             }
2887 
2888         default:
2889             {
2890 
2891             return false;
2892 
2893             }
2894 
2895         }
2896 
2897     return true;
2898 
2899     }
2900 
2901 /*****************************************************************************/
2902 
2903 void dng_shared::PostParse (dng_host & /* host */,
2904                             dng_exif & /* exif */)
2905     {
2906 
2907     // Fill in default values for DNG images.
2908 
2909     if (fDNGVersion != 0)
2910         {
2911 
2912         // Support for DNG versions before 1.0.0.0.
2913 
2914         if (fDNGVersion < dngVersion_1_0_0_0)
2915             {
2916 
2917             #if qDNGValidate
2918 
2919             ReportWarning ("DNGVersion less than 1.0.0.0");
2920 
2921             #endif
2922 
2923             // The CalibrationIlluminant tags were added just before
2924             // DNG version 1.0.0.0, and were hardcoded before that.
2925 
2926             fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA;
2927             fCameraProfile.fCalibrationIlluminant2 = lsD65;
2928 
2929             fDNGVersion = dngVersion_1_0_0_0;
2930 
2931             }
2932 
2933         // Default value for DNGBackwardVersion tag.
2934 
2935         if (fDNGBackwardVersion == 0)
2936             {
2937 
2938             fDNGBackwardVersion = fDNGVersion & 0xFFFF0000;
2939 
2940             }
2941 
2942         // Check DNGBackwardVersion value.
2943 
2944         if (fDNGBackwardVersion < dngVersion_1_0_0_0)
2945             {
2946 
2947             #if qDNGValidate
2948 
2949             ReportWarning ("DNGBackwardVersion less than 1.0.0.0");
2950 
2951             #endif
2952 
2953             fDNGBackwardVersion = dngVersion_1_0_0_0;
2954 
2955             }
2956 
2957         if (fDNGBackwardVersion > fDNGVersion)
2958             {
2959 
2960             #if qDNGValidate
2961 
2962             ReportWarning ("DNGBackwardVersion > DNGVersion");
2963 
2964             #endif
2965 
2966             fDNGBackwardVersion = fDNGVersion;
2967 
2968             }
2969 
2970         // Check UniqueCameraModel.
2971 
2972         if (fUniqueCameraModel.IsEmpty ())
2973             {
2974 
2975             #if qDNGValidate
2976 
2977             ReportWarning ("Missing or invalid UniqueCameraModel");
2978 
2979             #endif
2980 
2981             fUniqueCameraModel.Set ("Digital Negative");
2982 
2983             }
2984 
2985         // If we don't know the color depth yet, it must be a monochrome DNG.
2986 
2987         if (fCameraProfile.fColorPlanes == 0)
2988             {
2989 
2990             fCameraProfile.fColorPlanes = 1;
2991 
2992             }
2993 
2994         // Check color info.
2995 
2996         if (fCameraProfile.fColorPlanes > 1)
2997             {
2998 
2999             // Check illuminant pair.
3000 
3001             if (fCameraProfile.fColorMatrix2.NotEmpty ())
3002                 {
3003 
3004                 if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown ||
3005                     (fCameraProfile.fCalibrationIlluminant2 == lsUnknown ||
3006                     (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2)))
3007                     {
3008 
3009                     #if qDNGValidate
3010 
3011                     ReportWarning ("Invalid CalibrationIlluminant pair");
3012 
3013                     #endif
3014 
3015                     fCameraProfile.fColorMatrix2 = dng_matrix ();
3016 
3017                     }
3018 
3019                 }
3020 
3021             // If the colorimetric reference is the ICC profile PCS, then the
3022             // data must already be white balanced.  The "AsShotWhiteXY" is required
3023             // to be the ICC Profile PCS white point.
3024 
3025             if (fColorimetricReference == crICCProfilePCS)
3026                 {
3027 
3028                 if (fAsShotNeutral.NotEmpty ())
3029                     {
3030 
3031                     #if qDNGValidate
3032 
3033                     ReportWarning ("AsShotNeutral not allowed for this "
3034                                    "ColorimetricReference value");
3035 
3036                     #endif
3037 
3038                     fAsShotNeutral.Clear ();
3039 
3040                     }
3041 
3042                 dng_xy_coord pcs = PCStoXY ();
3043 
3044                 #if qDNGValidate
3045 
3046                 if (fAsShotWhiteXY.IsValid ())
3047                     {
3048 
3049                     if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 ||
3050                         Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01)
3051                         {
3052 
3053                         ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS");
3054 
3055                         }
3056 
3057                     }
3058 
3059                 #endif
3060 
3061                 fAsShotWhiteXY = pcs;
3062 
3063                 }
3064 
3065             else
3066                 {
3067 
3068                 // Warn if both AsShotNeutral and AsShotWhiteXY are specified.
3069 
3070                 if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ())
3071                     {
3072 
3073                     #if qDNGValidate
3074 
3075                     ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included");
3076 
3077                     #endif
3078 
3079                     fAsShotWhiteXY = dng_xy_coord ();
3080 
3081                     }
3082 
3083                 // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified.
3084 
3085                 #if qDNGValidate
3086 
3087                 if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ())
3088                     {
3089 
3090                     ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included",
3091                                    "legal but not recommended");
3092 
3093                     }
3094 
3095                 #endif
3096 
3097                 }
3098 
3099             // Default values of calibration signatures are required for legacy
3100             // compatiblity.
3101 
3102             if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
3103                 fCameraProfile.fCalibrationIlluminant2 == lsD65            &&
3104                 fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes &&
3105                 fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes &&
3106                 fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes &&
3107                 fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes &&
3108                 fCameraCalibrationSignature.IsEmpty ()                     &&
3109                 fCameraProfile.fProfileCalibrationSignature.IsEmpty ()     )
3110                 {
3111 
3112                 fCameraCalibrationSignature.Set (kAdobeCalibrationSignature);
3113 
3114                 fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature);
3115 
3116                 }
3117 
3118             }
3119 
3120         // Check BaselineNoise.
3121 
3122         if (fBaselineNoise.As_real64 () <= 0.0)
3123             {
3124 
3125             #if qDNGValidate
3126 
3127             ReportWarning ("Invalid BaselineNoise");
3128 
3129             #endif
3130 
3131             fBaselineNoise = dng_urational (1, 1);
3132 
3133             }
3134 
3135         // Check BaselineSharpness.
3136 
3137         if (fBaselineSharpness.As_real64 () <= 0.0)
3138             {
3139 
3140             #if qDNGValidate
3141 
3142             ReportWarning ("Invalid BaselineSharpness");
3143 
3144             #endif
3145 
3146             fBaselineSharpness = dng_urational (1, 1);
3147 
3148             }
3149 
3150         // Check LinearResponseLimit.
3151 
3152         if (fLinearResponseLimit.As_real64 () < 0.5 ||
3153             fLinearResponseLimit.As_real64 () > 1.0)
3154             {
3155 
3156             #if qDNGValidate
3157 
3158             ReportWarning ("Invalid LinearResponseLimit");
3159 
3160             #endif
3161 
3162             fLinearResponseLimit = dng_urational (1, 1);
3163 
3164             }
3165 
3166         // Check ShadowScale.
3167 
3168         if (fShadowScale.As_real64 () <= 0.0)
3169             {
3170 
3171             #if qDNGValidate
3172 
3173             ReportWarning ("Invalid ShadowScale");
3174 
3175             #endif
3176 
3177             fShadowScale = dng_urational (1, 1);
3178 
3179             }
3180 
3181         }
3182 
3183     }
3184 
3185 /*****************************************************************************/
3186 
3187 bool dng_shared::IsValidDNG ()
3188     {
3189 
3190     // Check DNGVersion value.
3191 
3192     if (fDNGVersion < dngVersion_1_0_0_0)
3193         {
3194 
3195         #if qDNGValidate
3196 
3197         if (fDNGVersion != dngVersion_None)
3198             {
3199 
3200             ReportError ("Invalid DNGVersion");
3201 
3202             }
3203 
3204         #if qDNGValidateTarget
3205 
3206         else
3207             {
3208 
3209             ReportError ("Missing DNGVersion");
3210 
3211             }
3212 
3213         #endif
3214 
3215         #endif
3216 
3217         return false;
3218 
3219         }
3220 
3221     // Check DNGBackwardVersion value.
3222 
3223     if (fDNGBackwardVersion > dngVersion_Current)
3224         {
3225 
3226         #if qDNGValidate
3227 
3228         ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
3229 
3230         #endif
3231 
3232         ThrowUnsupportedDNG ();
3233 
3234         }
3235 
3236     // Check color transform info.
3237 
3238     if (fCameraProfile.fColorPlanes > 1)
3239         {
3240 
3241         // CameraCalibration1 is optional, but it must be valid if present.
3242 
3243         if (fCameraCalibration1.Cols () != 0 ||
3244             fCameraCalibration1.Rows () != 0)
3245             {
3246 
3247             if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes ||
3248                 fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes)
3249                 {
3250 
3251                 #if qDNGValidate
3252 
3253                 ReportError ("CameraCalibration1 is wrong size");
3254 
3255                 #endif
3256 
3257                 return false;
3258 
3259                 }
3260 
3261             // Make sure it is invertable.
3262 
3263             try
3264                 {
3265 
3266                 (void) Invert (fCameraCalibration1);
3267 
3268                 }
3269 
3270             catch (...)
3271                 {
3272 
3273                 #if qDNGValidate
3274 
3275                 ReportError ("CameraCalibration1 is not invertable");
3276 
3277                 #endif
3278 
3279                 return false;
3280 
3281                 }
3282 
3283             }
3284 
3285         // CameraCalibration2 is optional, but it must be valid if present.
3286 
3287         if (fCameraCalibration2.Cols () != 0 ||
3288             fCameraCalibration2.Rows () != 0)
3289             {
3290 
3291             if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes ||
3292                 fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes)
3293                 {
3294 
3295                 #if qDNGValidate
3296 
3297                 ReportError ("CameraCalibration2 is wrong size");
3298 
3299                 #endif
3300 
3301                 return false;
3302 
3303                 }
3304 
3305             // Make sure it is invertable.
3306 
3307             try
3308                 {
3309 
3310                 (void) Invert (fCameraCalibration2);
3311 
3312                 }
3313 
3314             catch (...)
3315                 {
3316 
3317                 #if qDNGValidate
3318 
3319                 ReportError ("CameraCalibration2 is not invertable");
3320 
3321                 #endif
3322 
3323                 return false;
3324 
3325                 }
3326 
3327             }
3328 
3329         // Check analog balance
3330 
3331         dng_matrix analogBalance;
3332 
3333         if (fAnalogBalance.NotEmpty ())
3334             {
3335 
3336             analogBalance = fAnalogBalance.AsDiagonal ();
3337 
3338             try
3339                 {
3340 
3341                 (void) Invert (analogBalance);
3342 
3343                 }
3344 
3345             catch (...)
3346                 {
3347 
3348                 #if qDNGValidate
3349 
3350                 ReportError ("AnalogBalance is not invertable");
3351 
3352                 #endif
3353 
3354                 return false;
3355 
3356                 }
3357 
3358             }
3359 
3360         }
3361 
3362     return true;
3363 
3364     }
3365 
3366 /*****************************************************************************/