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