void dng_stream::DuplicateStream (dng_stream &dstStream) { // Turn off sniffers for this operation. TempStreamSniffer noSniffer1 (*this , NULL); TempStreamSniffer noSniffer2 (dstStream, NULL); // First grow the destination stream if required, in an attempt to // reserve any needed space before overwriting the existing data. if (dstStream.Length () < Length ()) { dstStream.SetLength (Length ()); } SetReadPosition (0); dstStream.SetWritePosition (0); CopyToStream (dstStream, Length ()); dstStream.Flush (); dstStream.SetLength (Length ()); }
bool dng_info::ValidateIFD (dng_stream &stream, uint64 ifdOffset, int64 offsetDelta) { // Make sure we have a count. if (ifdOffset + 2 > stream.Length ()) { return false; } // Get entry count. stream.SetReadPosition (ifdOffset); uint32 ifdEntries = stream.Get_uint16 (); if (ifdEntries < 1) { return false; } // Make sure we have room for all entries and next IFD link. if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ()) { return false; } // Check each entry. for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) { stream.SetReadPosition (ifdOffset + 2 + tag_index * 12); stream.Skip (2); // Ignore tag code. uint32 tagType = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint32 tag_type_size = TagTypeSize (tagType); if (tag_type_size == 0) { return false; } uint32 tag_data_size = tagCount * tag_type_size; if (tag_data_size > 4) { uint64 tagOffset = stream.Get_uint32 (); tagOffset += offsetDelta; if (tagOffset + tag_data_size > stream.Length ()) { return false; } } } return true; }
void dng_info::ParseTag (dng_host &host, dng_stream &stream, dng_exif *exif, dng_shared *shared, dng_ifd *ifd, uint32 parentCode, uint32 tagCode, uint32 tagType, uint32 tagCount, uint64 tagOffset, int64 offsetDelta) { bool isSubIFD = parentCode >= tcFirstSubIFD && parentCode <= tcLastSubIFD; bool isMainIFD = (parentCode == 0 || isSubIFD) && ifd && ifd->fUsesNewSubFileType && ifd->fNewSubFileType == sfMainImage; // Panasonic RAW format stores private tags using tag codes < 254 in // IFD 0. Redirect the parsing of these tags into a logical // "PanasonicRAW" IFD. // Panasonic is starting to use some higher numbers also (280..283). if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType || (tagCode >= 280 && tagCode <= 283))) { parentCode = tcPanasonicRAW; ifd = NULL; } stream.SetReadPosition (tagOffset); if (ifd && ifd->ParseTag (stream, parentCode, tagCode, tagType, tagCount, tagOffset)) { return; } stream.SetReadPosition (tagOffset); if (exif && shared && exif->ParseTag (stream, *shared, parentCode, isMainIFD, tagCode, tagType, tagCount, tagOffset)) { return; } stream.SetReadPosition (tagOffset); if (shared && exif && shared->ParseTag (stream, *exif, parentCode, isMainIFD, tagCode, tagType, tagCount, tagOffset, offsetDelta)) { return; } if (parentCode == tcOlympusMakerNote && tagType == ttUndefined && tagCount >= 14) { uint32 olympusMakerParent = 0; switch (tagCode) { case 8208: olympusMakerParent = tcOlympusMakerNote8208; break; case 8224: olympusMakerParent = tcOlympusMakerNote8224; break; case 8240: olympusMakerParent = tcOlympusMakerNote8240; break; case 8256: olympusMakerParent = tcOlympusMakerNote8256; break; case 8272: olympusMakerParent = tcOlympusMakerNote8272; break; case 12288: olympusMakerParent = tcOlympusMakerNote12288; break; default: break; } if (olympusMakerParent) { // Olympus made a mistake in some camera models in computing // the size of these sub-tags, so we fudge the count. if (ParseMakerNoteIFD (host, stream, stream.Length () - tagOffset, tagOffset, offsetDelta, tagOffset, stream.Length (), olympusMakerParent)) { return; } } } if (parentCode == tcRicohMakerNote && tagCode == 0x2001 && tagType == ttUndefined && tagCount > 22) { char header [20]; stream.SetReadPosition (tagOffset); stream.Get (header, sizeof (header)); if (memcmp (header, "[Ricoh Camera Info]", 19) == 0) { ParseMakerNoteIFD (host, stream, tagCount - 20, tagOffset + 20, offsetDelta, tagOffset + 20, tagOffset + tagCount, tcRicohMakerNoteCameraInfo); return; } } #if qDNGValidate { stream.SetReadPosition (tagOffset); if (gVerbose) { printf ("*"); DumpTagValues (stream, LookupTagType (tagType), parentCode, tagCode, tagType, tagCount); } // If type is ASCII, then parse anyway so we report any ASCII // NULL termination or character set errors. else if (tagType == ttAscii) { dng_string s; ParseStringTag (stream, parentCode, tagCode, tagCount, s, false); } } #endif }
void dng_info::Parse (dng_host &host, dng_stream &stream) { fTIFFBlockOffset = stream.Position (); fTIFFBlockOriginalOffset = stream.PositionInOriginalFile (); // Check byte order indicator. uint16 byteOrder = stream.Get_uint16 (); if (byteOrder == byteOrderII) { fBigEndian = false; #if qDNGValidate if (gVerbose) { printf ("\nUses little-endian byte order\n"); } #endif stream.SetLittleEndian (); } else if (byteOrder == byteOrderMM) { fBigEndian = true; #if qDNGValidate if (gVerbose) { printf ("\nUses big-endian byte order\n"); } #endif stream.SetBigEndian (); } else { #if qDNGValidate ReportError ("Unknown byte order"); #endif ThrowBadFormat (); } // Check "magic number" indicator. fMagic = stream.Get_uint16 (); #if qDNGValidate if (gVerbose) { printf ("Magic number = %u\n\n", (unsigned) fMagic); } #endif ValidateMagic (); // Parse IFD 0. uint64 next_offset = stream.Get_uint32 (); fExif.Reset (host.Make_dng_exif ()); fShared.Reset (host.Make_dng_shared ()); fIFD [0].Reset (host.Make_dng_ifd ()); ParseIFD (host, stream, fExif.Get (), fShared.Get (), fIFD [0].Get (), fTIFFBlockOffset + next_offset, fTIFFBlockOffset, 0); next_offset = fIFD [0]->fNextIFD; fIFDCount = 1; // Parse chained IFDs. while (next_offset) { if (next_offset >= stream.Length ()) { #if qDNGValidate { ReportWarning ("Chained IFD offset past end of stream"); } #endif break; } // Some TIFF file writers forget about the next IFD offset, so // validate the IFD at that offset before parsing it. if (!ValidateIFD (stream, fTIFFBlockOffset + next_offset, fTIFFBlockOffset)) { #if qDNGValidate { ReportWarning ("Chained IFD is not valid"); } #endif break; } if (fChainedIFDCount == kMaxChainedIFDs) { #if qDNGValidate { ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit"); } #endif break; } fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ()); ParseIFD (host, stream, NULL, NULL, fChainedIFD [fChainedIFDCount].Get (), fTIFFBlockOffset + next_offset, fTIFFBlockOffset, tcFirstChainedIFD + fChainedIFDCount); next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD; fChainedIFDCount++; } // Parse SubIFDs. uint32 searchedIFDs = 0; bool tooManySubIFDs = false; while (searchedIFDs < fIFDCount && !tooManySubIFDs) { uint32 searchLimit = fIFDCount; for (uint32 searchIndex = searchedIFDs; searchIndex < searchLimit && !tooManySubIFDs; searchIndex++) { for (uint32 subIndex = 0; subIndex < fIFD [searchIndex]->fSubIFDsCount; subIndex++) { if (fIFDCount == kMaxSubIFDs + 1) { tooManySubIFDs = true; break; } stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset + subIndex * 4); uint32 sub_ifd_offset = stream.Get_uint32 (); fIFD [fIFDCount].Reset (host.Make_dng_ifd ()); ParseIFD (host, stream, fExif.Get (), fShared.Get (), fIFD [fIFDCount].Get (), fTIFFBlockOffset + sub_ifd_offset, fTIFFBlockOffset, tcFirstSubIFD + fIFDCount - 1); fIFDCount++; } searchedIFDs = searchLimit; } } #if qDNGValidate { if (tooManySubIFDs) { ReportWarning ("SubIFD count exceeds DNG SDK parsing limit"); } } #endif // Parse EXIF IFD. if (fShared->fExifIFD) { ParseIFD (host, stream, fExif.Get (), fShared.Get (), NULL, fTIFFBlockOffset + fShared->fExifIFD, fTIFFBlockOffset, tcExifIFD); } // Parse GPS IFD. if (fShared->fGPSInfo) { ParseIFD (host, stream, fExif.Get (), fShared.Get (), NULL, fTIFFBlockOffset + fShared->fGPSInfo, fTIFFBlockOffset, tcGPSInfo); } // Parse Interoperability IFD. if (fShared->fInteroperabilityIFD) { // Some Kodak KDC files have bogus Interoperability IFDs, so // validate the IFD before trying to parse it. if (ValidateIFD (stream, fTIFFBlockOffset + fShared->fInteroperabilityIFD, fTIFFBlockOffset)) { ParseIFD (host, stream, fExif.Get (), fShared.Get (), NULL, fTIFFBlockOffset + fShared->fInteroperabilityIFD, fTIFFBlockOffset, tcInteroperabilityIFD); } #if qDNGValidate else { ReportWarning ("The Interoperability IFD is not a valid IFD"); } #endif } // Parse Kodak DCR Private IFD. if (fShared->fKodakDCRPrivateIFD) { ParseIFD (host, stream, fExif.Get (), fShared.Get (), NULL, fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD, fTIFFBlockOffset, tcKodakDCRPrivateIFD); } // Parse Kodak KDC Private IFD. if (fShared->fKodakKDCPrivateIFD) { ParseIFD (host, stream, fExif.Get (), fShared.Get (), NULL, fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD, fTIFFBlockOffset, tcKodakKDCPrivateIFD); } // Parse MakerNote tag. if (fShared->fMakerNoteCount) { ParseMakerNote (host, stream, (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount), fShared->fMakerNoteOffset, fTIFFBlockOffset, 0, stream.Length ()); } // Parse DNGPrivateData tag. if (fShared->fDNGPrivateDataCount && fShared->fDNGVersion) { ParseDNGPrivateData (host, stream); } #if qDNGValidate // If we are running dng_validate on stand-alone camera profile file, // complete the validation of the profile. if (fMagic == magicExtendedProfile) { dng_camera_profile_info &profileInfo = fShared->fCameraProfile; dng_camera_profile profile; profile.Parse (stream, profileInfo); if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes)) { ReportError ("Invalid camera profile file"); } } #endif }