void dng_gain_map::PutStream (dng_stream &stream) const { stream.Put_uint32 (fPoints.v); stream.Put_uint32 (fPoints.h); stream.Put_real64 (fSpacing.v); stream.Put_real64 (fSpacing.h); stream.Put_real64 (fOrigin.v); stream.Put_real64 (fOrigin.h); stream.Put_uint32 (fPlanes); for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++) { for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++) { for (uint32 plane = 0; plane < fPlanes; plane++) { stream.Put_real32 (Entry (rowIndex, colIndex, plane)); } } } }
dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host, dng_stream &stream) : dng_inplace_opcode (dngOpcode_GainMap, stream, "GainMap") , fAreaSpec () , fGainMap () { uint32 byteCount = stream.Get_uint32 (); uint64 startPosition = stream.Position (); fAreaSpec.GetData (stream); fGainMap.Reset (dng_gain_map::GetStream (host, stream)); if (stream.Position () != startPosition + byteCount) { ThrowBadFormat (); } }
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 ()); }
void dng_camera_profile::ReadHueSatMap (dng_stream &stream, dng_hue_sat_map &hueSatMap, uint32 hues, uint32 sats, uint32 vals, bool skipSat0) { hueSatMap.SetDivisions (hues, sats, vals); for (uint32 val = 0; val < vals; val++) { for (uint32 hue = 0; hue < hues; hue++) { for (uint32 sat = skipSat0 ? 1 : 0; sat < sats; sat++) { dng_hue_sat_map::HSBModify modify; modify.fHueShift = stream.Get_real32 (); modify.fSatScale = stream.Get_real32 (); modify.fValScale = stream.Get_real32 (); hueSatMap.SetDelta (hue, sat, val, modify); } } } }
dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (dng_stream &stream) : dng_inplace_opcode (dngOpcode_MapPolynomial, stream, "MapPolynomial") , fAreaSpec () , fDegree (0) { uint32 dataSize = stream.Get_uint32 (); fAreaSpec.GetData (stream); fDegree = stream.Get_uint32 (); if (dataSize != dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8) { ThrowBadFormat (); } if (fDegree > kMaxDegree) { ThrowBadFormat (); } for (uint32 j = 0; j <= kMaxDegree; j++) { if (j <= fDegree) { fCoefficient [j] = stream.Get_real64 (); } else { fCoefficient [j] = 0.0; } } #if qDNGValidate if (gVerbose) { for (uint32 k = 0; k <= fDegree; k++) { printf (" Coefficient [%u] = %f\n", k, fCoefficient [k]); } } #endif }
void dng_opcode_TrimBounds::PutData (dng_stream &stream) const { stream.Put_uint32 (16); stream.Put_int32 (fBounds.t); stream.Put_int32 (fBounds.l); stream.Put_int32 (fBounds.b); stream.Put_int32 (fBounds.r); }
void dng_area_spec::GetData (dng_stream &stream) { fArea.t = stream.Get_int32 (); fArea.l = stream.Get_int32 (); fArea.b = stream.Get_int32 (); fArea.r = stream.Get_int32 (); fPlane = stream.Get_uint32 (); fPlanes = stream.Get_uint32 (); fRowPitch = stream.Get_uint32 (); fColPitch = stream.Get_uint32 (); if (fPlanes < 1) { ThrowBadFormat (); } if (fRowPitch < 1 || fColPitch < 1) { ThrowBadFormat (); } if (fArea.IsEmpty () && (fRowPitch != 1 || fColPitch != 1)) { ThrowBadFormat (); } #if qDNGValidate if (gVerbose) { printf ("AreaSpec: t=%d, l=%d, b=%d, r=%d, p=%u:%u, rp=%u, cp=%u\n", (int) fArea.t, (int) fArea.l, (int) fArea.b, (int) fArea.r, (unsigned) fPlane, (unsigned) fPlanes, (unsigned) fRowPitch, (unsigned) fColPitch); } #endif }
void dng_area_spec::PutData (dng_stream &stream) const { stream.Put_int32 (fArea.t); stream.Put_int32 (fArea.l); stream.Put_int32 (fArea.b); stream.Put_int32 (fArea.r); stream.Put_uint32 (fPlane); stream.Put_uint32 (fPlanes); stream.Put_uint32 (fRowPitch); stream.Put_uint32 (fColPitch); }
void dng_opcode_MapPolynomial::PutData (dng_stream &stream) const { stream.Put_uint32 (dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8); fAreaSpec.PutData (stream); stream.Put_uint32 (fDegree); for (uint32 j = 0; j <= fDegree; j++) { stream.Put_real64 (fCoefficient [j]); } }
void dng_opcode_MapTable::PutData (dng_stream &stream) const { stream.Put_uint32 (dng_area_spec::kDataSize + 4 + fCount * 2); fAreaSpec.PutData (stream); stream.Put_uint32 (fCount); uint16 *table = fTable->Buffer_uint16 (); for (uint32 index = 0; index < fCount; index++) { stream.Put_uint16 (table [index]); } }
void dng_jpeg_preview::WriteData (dng_host & /* host */, dng_image_writer & /* writer */, dng_basic_tag_set &basic, dng_stream &stream) const { basic.SetTileOffset (0, (uint32) stream.Position ()); basic.SetTileByteCount (0, fCompressedData->LogicalSize ()); stream.Put (fCompressedData->Buffer (), fCompressedData->LogicalSize ()); if (fCompressedData->LogicalSize () & 1) { stream.Put_uint8 (0); } }
void dng_stream::CopyToStream (dng_stream &dstStream, uint64 count) { uint8 smallBuffer [1024]; if (count <= sizeof (smallBuffer)) { Get (smallBuffer, (uint32) count); dstStream.Put (smallBuffer, (uint32) count); } else { const uint32 bigBufferSize = (uint32) Min_uint64 (kBigBufferSize, count); dng_memory_data bigBuffer (bigBufferSize); while (count) { uint32 blockCount = (uint32) Min_uint64 (bigBufferSize, count); Get (bigBuffer.Buffer (), blockCount); dstStream.Put (bigBuffer.Buffer (), blockCount); count -= blockCount; } } }
void dng_opcode_GainMap::PutData (dng_stream &stream) const { stream.Put_uint32 (dng_area_spec::kDataSize + fGainMap->PutStreamSize ()); fAreaSpec.PutData (stream); fGainMap->PutStream (stream); }
TempStreamSniffer::TempStreamSniffer (dng_stream &stream, dng_abort_sniffer *sniffer) : fStream (stream) , fOldSniffer (stream.Sniffer ()) { fStream.SetSniffer (sniffer); }
TempBigEndian::TempBigEndian (dng_stream &stream, bool bigEndian) : fStream (stream) , fOldSwap (stream.SwapBytes ()) { fStream.SetBigEndian (bigEndian); }
dng_opcode_TrimBounds::dng_opcode_TrimBounds (dng_stream &stream) : dng_opcode (dngOpcode_TrimBounds, stream, "TrimBounds") , fBounds () { if (stream.Get_uint32 () != 16) { ThrowBadFormat (); } fBounds.t = stream.Get_int32 (); fBounds.l = stream.Get_int32 (); fBounds.b = stream.Get_int32 (); fBounds.r = stream.Get_int32 (); if (fBounds.IsEmpty ()) { ThrowBadFormat (); } #if qDNGValidate if (gVerbose) { printf ("Bounds: t=%d, l=%d, b=%d, r=%d\n", (int) fBounds.t, (int) fBounds.l, (int) fBounds.b, (int) fBounds.r); } #endif }
void dng_opcode_DeltaPerRow::PutData (dng_stream &stream) const { uint32 deltas = (fAreaSpec.Area ().H () + fAreaSpec.RowPitch () - 1) / fAreaSpec.RowPitch (); stream.Put_uint32 (dng_area_spec::kDataSize + 4 + deltas * 4); fAreaSpec.PutData (stream); stream.Put_uint32 (deltas); real32 *table = fTable->Buffer_real32 (); for (uint32 j = 0; j < deltas; j++) { stream.Put_real32 (table [j]); } }
void dng_opcode_ScalePerColumn::PutData (dng_stream &stream) const { uint32 scales = (fAreaSpec.Area ().W () + fAreaSpec.ColPitch () - 1) / fAreaSpec.ColPitch (); stream.Put_uint32 (dng_area_spec::kDataSize + 4 + scales * 4); fAreaSpec.PutData (stream); stream.Put_uint32 (scales); real32 *table = fTable->Buffer_real32 (); for (uint32 j = 0; j < scales; j++) { stream.Put_real32 (table [j]); } }
void dng_iptc::ParseString (dng_stream &stream, dng_string &s, CharSet charSet) { uint32 length = stream.Get_uint16 (); dng_memory_data buffer (length + 1); char *c = buffer.Buffer_char (); stream.Get (c, length); c [length] = 0; switch (charSet) { case kCharSetUTF8: { s.Set_UTF8 (c); break; } default: { s.Set_SystemEncoding (c); } } s.SetLineEndingsToNewLines (); s.StripLowASCII (); s.TrimTrailingBlanks (); }
void dng_memory_stream::CopyToStream (dng_stream &dstStream, uint64 count) { if (count < kBigBufferSize) { dng_stream::CopyToStream (dstStream, count); } else { Flush (); uint64 offset = Position (); if (offset + count > Length ()) { ThrowEndOfFile (); } while (count) { uint32 pageIndex = (uint32) (offset / fPageSize); uint32 pageOffset = (uint32) (offset % fPageSize); uint32 blockCount = (uint32) Min_uint64 (fPageSize - pageOffset, count); const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () + pageOffset; dstStream.Put (sPtr, blockCount); offset += blockCount; count -= blockCount; } SetReadPosition (offset); } }
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 }
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::ParseMakerNote (dng_host &host, dng_stream &stream, uint32 makerNoteCount, uint64 makerNoteOffset, int64 offsetDelta, uint64 minOffset, uint64 maxOffset) { uint8 firstBytes [16]; memset (firstBytes, 0, sizeof (firstBytes)); stream.SetReadPosition (makerNoteOffset); stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes), makerNoteCount)); // Epson MakerNote with header. if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0) { if (makerNoteCount > 8) { ParseMakerNoteIFD (host, stream, makerNoteCount - 8, makerNoteOffset + 8, offsetDelta, minOffset, maxOffset, tcEpsonMakerNote); } return; } // Fujifilm MakerNote. if (memcmp (firstBytes, "FUJIFILM", 8) == 0) { stream.SetReadPosition (makerNoteOffset + 8); TempLittleEndian tempEndian (stream); uint32 ifd_offset = stream.Get_uint32 (); if (ifd_offset >= 12 && ifd_offset < makerNoteCount) { ParseMakerNoteIFD (host, stream, makerNoteCount - ifd_offset, makerNoteOffset + ifd_offset, makerNoteOffset, minOffset, maxOffset, tcFujiMakerNote); } return; } // Leica MakerNote. if (memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) { if (makerNoteCount > 8) { ParseMakerNoteIFD (host, stream, makerNoteCount - 8, makerNoteOffset + 8, makerNoteOffset, minOffset, maxOffset, tcLeicaMakerNote); } return; } // Nikon version 2 MakerNote with header. if (memcmp (firstBytes, "Nikon\000\002", 7) == 0) { stream.SetReadPosition (makerNoteOffset + 10); bool bigEndian = false; uint16 endianMark = stream.Get_uint16 (); if (endianMark == byteOrderMM) { bigEndian = true; } else if (endianMark != byteOrderII) { return; } TempBigEndian temp_endian (stream, bigEndian); uint16 magic = stream.Get_uint16 (); if (magic != 42) { return; } uint32 ifd_offset = stream.Get_uint32 (); if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10) { ParseMakerNoteIFD (host, stream, makerNoteCount - 10 - ifd_offset, makerNoteOffset + 10 + ifd_offset, makerNoteOffset + 10, minOffset, maxOffset, tcNikonMakerNote); } return; } // Newer version of Olympus MakerNote with byte order mark. if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0) { stream.SetReadPosition (makerNoteOffset + 8); bool bigEndian = false; uint16 endianMark = stream.Get_uint16 (); if (endianMark == byteOrderMM) { bigEndian = true; } else if (endianMark != byteOrderII) { return; } TempBigEndian temp_endian (stream, bigEndian); uint16 version = stream.Get_uint16 (); if (version != 3) { return; } if (makerNoteCount > 12) { ParseMakerNoteIFD (host, stream, makerNoteCount - 12, makerNoteOffset + 12, makerNoteOffset, minOffset, maxOffset, tcOlympusMakerNote); } return; } // Olympus MakerNote with header. if (memcmp (firstBytes, "OLYMP", 5) == 0) { if (makerNoteCount > 8) { ParseMakerNoteIFD (host, stream, makerNoteCount - 8, makerNoteOffset + 8, offsetDelta, minOffset, maxOffset, tcOlympusMakerNote); } return; } // Panasonic MakerNote. if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0) { if (makerNoteCount > 12) { ParseMakerNoteIFD (host, stream, makerNoteCount - 12, makerNoteOffset + 12, offsetDelta, minOffset, maxOffset, tcPanasonicMakerNote); } return; } // Pentax MakerNote. if (memcmp (firstBytes, "AOC", 4) == 0) { if (makerNoteCount > 6) { stream.SetReadPosition (makerNoteOffset + 4); bool bigEndian = stream.BigEndian (); uint16 endianMark = stream.Get_uint16 (); if (endianMark == byteOrderMM) { bigEndian = true; } else if (endianMark == byteOrderII) { bigEndian = false; } TempBigEndian temp_endian (stream, bigEndian); ParseMakerNoteIFD (host, stream, makerNoteCount - 6, makerNoteOffset + 6, offsetDelta, minOffset, maxOffset, tcPentaxMakerNote); } return; } // Ricoh MakerNote. if (memcmp (firstBytes, "RICOH", 5) == 0 || memcmp (firstBytes, "Ricoh", 5) == 0) { if (makerNoteCount > 8) { TempBigEndian tempEndian (stream); ParseMakerNoteIFD (host, stream, makerNoteCount - 8, makerNoteOffset + 8, offsetDelta, minOffset, maxOffset, tcRicohMakerNote); } return; } // Nikon MakerNote without header. if (fExif->fMake.StartsWith ("NIKON")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcNikonMakerNote); return; } // Canon MakerNote. if (fExif->fMake.StartsWith ("CANON")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcCanonMakerNote); return; } // Minolta MakerNote. if (fExif->fMake.StartsWith ("MINOLTA" ) || fExif->fMake.StartsWith ("KONICA MINOLTA")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcMinoltaMakerNote); return; } // Sony MakerNote. if (fExif->fMake.StartsWith ("SONY")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcSonyMakerNote); return; } // Kodak MakerNote. if (fExif->fMake.StartsWith ("EASTMAN KODAK")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcKodakMakerNote); return; } // Mamiya MakerNote. if (fExif->fMake.StartsWith ("Mamiya")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcMamiyaMakerNote); // Mamiya uses a MakerNote chain. while (fMakerNoteNextIFD) { ParseMakerNoteIFD (host, stream, makerNoteCount, offsetDelta + fMakerNoteNextIFD, offsetDelta, minOffset, maxOffset, tcMamiyaMakerNote); } return; } // Nikon MakerNote without header. if (fExif->fMake.StartsWith ("Hasselblad")) { ParseMakerNoteIFD (host, stream, makerNoteCount, makerNoteOffset, offsetDelta, minOffset, maxOffset, tcHasselbladMakerNote); return; } }
bool dng_info::ParseMakerNoteIFD (dng_host &host, dng_stream &stream, uint64 ifdSize, uint64 ifdOffset, int64 offsetDelta, uint64 minOffset, uint64 maxOffset, uint32 parentCode) { uint32 tagIndex; uint32 tagCode; uint32 tagType; uint32 tagCount; // Assume there is no next IFD pointer. fMakerNoteNextIFD = 0; // If size is too small to hold a single entry IFD, abort. if (ifdSize < 14) { return false; } // Get entry count. stream.SetReadPosition (ifdOffset); uint32 ifdEntries = stream.Get_uint16 (); // Make the entry count if reasonable for the MakerNote size. if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize) { return false; } // Scan IFD to verify all the tag types are all valid. for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++) { stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2); tagType = stream.Get_uint16 (); // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we // need to ignore them. This was a "firmware 1.0.4" Canon 40D raw file. if (parentCode == tcCanonMakerNote && tagType == 0) { continue; } if (TagTypeSize (tagType) == 0) { return false; } } // OK, the IFD looks reasonable enough to parse. #if qDNGValidate if (gVerbose) { printf ("%s: Offset = %u, Entries = %u\n\n", LookupParentCode (parentCode), (unsigned) ifdOffset, (unsigned) ifdEntries); } #endif for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++) { stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12); tagCode = stream.Get_uint16 (); tagType = stream.Get_uint16 (); tagCount = stream.Get_uint32 (); if (tagType == 0) { continue; } uint32 tagSize = tagCount * TagTypeSize (tagType); uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8; if (tagSize > 4) { tagOffset = stream.Get_uint32 () + offsetDelta; if (tagOffset < minOffset || tagOffset + tagSize > maxOffset) { // Tag data is outside the valid offset range, // so ignore this tag. continue; } stream.SetReadPosition (tagOffset); } // Olympus switched to using IFDs in version 3 makernotes. if (parentCode == tcOlympusMakerNote && tagType == ttIFD && tagCount == 1) { 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) { stream.SetReadPosition (tagOffset); uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta; if (subMakerNoteOffset >= minOffset && subMakerNoteOffset < maxOffset) { if (ParseMakerNoteIFD (host, stream, maxOffset - subMakerNoteOffset, subMakerNoteOffset, offsetDelta, minOffset, maxOffset, olympusMakerParent)) { continue; } } } stream.SetReadPosition (tagOffset); } ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, parentCode, tagCode, tagType, tagCount, tagOffset, offsetDelta); } // Grab next IFD pointer, for possible use. if (ifdSize >= 2 + ifdEntries * 12 + 4) { stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12); fMakerNoteNextIFD = stream.Get_uint32 (); } #if qDNGValidate if (gVerbose) { printf ("\n"); } #endif return true; }
void dng_info::ParseIFD (dng_host &host, dng_stream &stream, dng_exif *exif, dng_shared *shared, dng_ifd *ifd, uint64 ifdOffset, int64 offsetDelta, uint32 parentCode) { #if qDNGValidate bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD && parentCode <= tcLastMakerNoteIFD); #endif stream.SetReadPosition (ifdOffset); if (ifd) { ifd->fThisIFD = ifdOffset; } uint32 ifdEntries = stream.Get_uint16 (); #if qDNGValidate if (gVerbose) { printf ("%s: Offset = %u, Entries = %u\n\n", LookupParentCode (parentCode), (unsigned) ifdOffset, (unsigned) ifdEntries); } if ((ifdOffset & 1) && !isMakerNote) { char message [256]; sprintf (message, "%s has odd offset (%u)", LookupParentCode (parentCode), (unsigned) ifdOffset); ReportWarning (message); } #endif uint32 prev_tag_code = 0; for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) { stream.SetReadPosition (ifdOffset + 2 + tag_index * 12); uint32 tagCode = stream.Get_uint16 (); uint32 tagType = stream.Get_uint16 (); // Minolta 7D files have a bug in the EXIF block where the count // is wrong, and we run off into next IFD link. So if abort parsing // if we get a zero code/type combinations. if (tagCode == 0 && tagType == 0) { #if qDNGValidate char message [256]; sprintf (message, "%s had zero/zero tag code/type entry", LookupParentCode (parentCode)); ReportWarning (message); #endif return; } uint32 tagCount = stream.Get_uint32 (); #if qDNGValidate { if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote) { char message [256]; sprintf (message, "%s tags are not sorted in ascending numerical order", LookupParentCode (parentCode)); ReportWarning (message); } } #endif prev_tag_code = tagCode; uint32 tag_type_size = TagTypeSize (tagType); if (tag_type_size == 0) { #if qDNGValidate { char message [256]; sprintf (message, "%s %s has unknown type (%u)", LookupParentCode (parentCode), LookupTagCode (parentCode, tagCode), (unsigned) tagType); ReportWarning (message); } #endif continue; } uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8; if (tagCount * tag_type_size > 4) { tagOffset = stream.Get_uint32 (); #if qDNGValidate { if (!(ifdOffset & 1) && (tagOffset & 1) && !isMakerNote && parentCode != tcKodakDCRPrivateIFD && parentCode != tcKodakKDCPrivateIFD) { char message [256]; sprintf (message, "%s %s has odd data offset (%u)", LookupParentCode (parentCode), LookupTagCode (parentCode, tagCode), (unsigned) tagOffset); ReportWarning (message); } } #endif tagOffset += offsetDelta; stream.SetReadPosition (tagOffset); } ParseTag (host, stream, exif, shared, ifd, parentCode, tagCode, tagType, tagCount, tagOffset, offsetDelta); } stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12); uint32 nextIFD = stream.Get_uint32 (); #if qDNGValidate if (gVerbose) { printf ("NextIFD = %u\n", (unsigned) nextIFD); } #endif if (ifd) { ifd->fNextIFD = nextIFD; } #if qDNGValidate if (nextIFD) { if (parentCode != 0 && (parentCode < tcFirstChainedIFD || parentCode > tcLastChainedIFD )) { char message [256]; sprintf (message, "%s has an unexpected non-zero NextIFD (%u)", LookupParentCode (parentCode), (unsigned) nextIFD); ReportWarning (message); } } if (gVerbose) { printf ("\n"); } #endif }
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::ParseDNGPrivateData (dng_host &host, dng_stream &stream) { if (fShared->fDNGPrivateDataCount < 2) { return; } // DNG private data should always start with a null-terminated // company name, to define the format of the private data. dng_string privateName; { char buffer [64]; stream.SetReadPosition (fShared->fDNGPrivateDataOffset); uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount, sizeof (buffer) - 1); stream.Get (buffer, readLength); buffer [readLength] = 0; privateName.Set (buffer); } // Pentax is storing their MakerNote in the DNGPrivateData data. if (privateName.StartsWith ("PENTAX" ) || privateName.StartsWith ("SAMSUNG")) { #if qDNGValidate if (gVerbose) { printf ("Parsing Pentax/Samsung DNGPrivateData\n\n"); } #endif stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8); bool bigEndian = stream.BigEndian (); uint16 endianMark = stream.Get_uint16 (); if (endianMark == byteOrderMM) { bigEndian = true; } else if (endianMark == byteOrderII) { bigEndian = false; } TempBigEndian temp_endian (stream, bigEndian); ParseMakerNoteIFD (host, stream, fShared->fDNGPrivateDataCount - 10, fShared->fDNGPrivateDataOffset + 10, fShared->fDNGPrivateDataOffset, fShared->fDNGPrivateDataOffset, fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount, tcPentaxMakerNote); return; } // Stop parsing if this is not an Adobe format block. if (!privateName.Matches ("Adobe")) { return; } TempBigEndian temp_order (stream); uint32 section_offset = 6; while (section_offset + 8 < fShared->fDNGPrivateDataCount) { stream.SetReadPosition (fShared->fDNGPrivateDataOffset + section_offset); uint32 section_key = stream.Get_uint32 (); uint32 section_count = stream.Get_uint32 (); if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6) { #if qDNGValidate if (gVerbose) { printf ("Found MakerNote inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint64 old_offset = stream.Get_uint32 (); uint32 tempSize = section_count - 6; AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize)); uint64 positionInOriginalFile = stream.PositionInOriginalFile(); stream.Get (tempBlock->Buffer (), tempSize); dng_stream tempStream (tempBlock->Buffer (), tempSize, positionInOriginalFile); tempStream.SetBigEndian (order_mark == byteOrderMM); ParseMakerNote (host, tempStream, tempSize, 0, 0 - old_offset, 0, tempSize); } else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6) { #if qDNGValidate if (gVerbose) { printf ("Found Sony private data inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint64 old_offset = stream.Get_uint32 (); uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14; TempBigEndian sr2_order (stream, order_mark == byteOrderMM); ParseSonyPrivateData (host, stream, section_count - 6, old_offset, new_offset); } else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Fuji RAF tags inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiHeader, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } tagCount = stream.Get_uint32 (); tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiRawInfo1, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } tagCount = stream.Get_uint32 (); tagOffset = stream.Position (); if (tagCount) { TempBigEndian raf_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcFujiRAF, tcFujiRawInfo2, ttUndefined, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagCount); } } else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Contax Raw header inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); if (tagCount) { TempBigEndian contax_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcContaxRAW, tcContaxHeader, ttUndefined, tagCount, tagOffset, 0); } } else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4) { #if qDNGValidate if (gVerbose) { printf ("Found Canon CRW tags inside DNGPrivateData\n\n"); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 entries = stream.Get_uint16 (); uint64 crwTagStart = stream.Position (); for (uint32 parsePass = 1; parsePass <= 2; parsePass++) { stream.SetReadPosition (crwTagStart); for (uint32 index = 0; index < entries; index++) { uint32 tagCode = stream.Get_uint16 (); uint32 tagCount = stream.Get_uint32 (); uint64 tagOffset = stream.Position (); // We need to grab the model id tag first, and then all the // other tags. if ((parsePass == 1) == (tagCode == 0x5834)) { TempBigEndian tag_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, tcCanonCRW, tagCode, ttUndefined, tagCount, tagOffset, 0); } stream.SetReadPosition (tagOffset + tagCount); } } } else if (section_count > 4) { uint32 parentCode = 0; bool code32 = false; bool hasType = true; switch (section_key) { case DNG_CHAR4 ('M','R','W',' '): { parentCode = tcMinoltaMRW; code32 = true; hasType = false; break; } case DNG_CHAR4 ('P','a','n','o'): { parentCode = tcPanasonicRAW; break; } case DNG_CHAR4 ('L','e','a','f'): { parentCode = tcLeafMOS; break; } case DNG_CHAR4 ('K','o','d','a'): { parentCode = tcKodakDCRPrivateIFD; break; } case DNG_CHAR4 ('K','D','C',' '): { parentCode = tcKodakKDCPrivateIFD; break; } default: break; } if (parentCode) { #if qDNGValidate if (gVerbose) { printf ("Found %s tags inside DNGPrivateData\n\n", LookupParentCode (parentCode)); } #endif uint16 order_mark = stream.Get_uint16 (); uint32 entries = stream.Get_uint16 (); for (uint32 index = 0; index < entries; index++) { uint32 tagCode = code32 ? stream.Get_uint32 () : stream.Get_uint16 (); uint32 tagType = hasType ? stream.Get_uint16 () : ttUndefined; uint32 tagCount = stream.Get_uint32 (); uint32 tagSize = tagCount * TagTypeSize (tagType); uint64 tagOffset = stream.Position (); TempBigEndian tag_order (stream, order_mark == byteOrderMM); ParseTag (host, stream, fExif.Get (), fShared.Get (), NULL, parentCode, tagCode, tagType, tagCount, tagOffset, 0); stream.SetReadPosition (tagOffset + tagSize); } } } section_offset += 8 + section_count; if (section_offset & 1) { section_offset++; } } }
void dng_iptc::SpoolString (dng_stream &stream, const dng_string &s, uint8 dataSet, uint32 maxChars, CharSet charSet) { if (s.IsEmpty ()) { return; } stream.Put_uint16 (0x1C02); stream.Put_uint8 (dataSet); dng_string ss (s); ss.SetLineEndingsToReturns (); if (charSet == kCharSetUTF8) { // UTF-8 encoding. if (ss.Length () > maxChars) { ss.Truncate (maxChars); } uint32 len = ss.Length (); stream.Put_uint16 ((uint16) len); stream.Put (ss.Get (), len); } else { // System character set encoding. dng_memory_data buffer; uint32 len = ss.Get_SystemEncoding (buffer); if (len > maxChars) { uint32 lower = 0; uint32 upper = ss.Length () - 1; while (upper > lower) { uint32 middle = (upper + lower + 1) >> 1; dng_string sss (ss); sss.Truncate (middle); len = sss.Get_SystemEncoding (buffer); if (len <= maxChars) { lower = middle; } else { upper = middle - 1; } } ss.Truncate (lower); len = ss.Get_SystemEncoding (buffer); } stream.Put_uint16 ((uint16) len); stream.Put (buffer.Buffer_char (), len); }
void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const { DNG_ASSERT (fCompressedData.Get (), "SpoolAdobeThumbnail: no data"); DNG_ASSERT (fPhotometricInterpretation == piYCbCr, "SpoolAdobeThumbnail: Non-YCbCr"); uint32 compressedSize = fCompressedData->LogicalSize (); stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); stream.Put_uint16 (1036); stream.Put_uint16 (0); stream.Put_uint32 (compressedSize + 28); uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4; stream.Put_uint32 (1); stream.Put_uint32 (fPreviewSize.h); stream.Put_uint32 (fPreviewSize.v); stream.Put_uint32 (widthBytes); stream.Put_uint32 (widthBytes * fPreviewSize.v); stream.Put_uint32 (compressedSize); stream.Put_uint16 (24); stream.Put_uint16 (1); stream.Put (fCompressedData->Buffer (), compressedSize); if (compressedSize & 1) { stream.Put_uint8 (0); } }
void dng_camera_profile::Parse (dng_stream &stream, dng_camera_profile_info &profileInfo) { SetUniqueCameraModelRestriction (profileInfo.fUniqueCameraModel.Get ()); if (profileInfo.fProfileName.NotEmpty ()) { SetName (profileInfo.fProfileName.Get ()); } SetCopyright (profileInfo.fProfileCopyright.Get ()); SetEmbedPolicy (profileInfo.fEmbedPolicy); SetCalibrationIlluminant1 (profileInfo.fCalibrationIlluminant1); SetColorMatrix1 (profileInfo.fColorMatrix1); if (profileInfo.fForwardMatrix1.NotEmpty ()) { SetForwardMatrix1 (profileInfo.fForwardMatrix1); } if (profileInfo.fReductionMatrix1.NotEmpty ()) { SetReductionMatrix1 (profileInfo.fReductionMatrix1); } if (profileInfo.fColorMatrix2.NotEmpty ()) { SetCalibrationIlluminant2 (profileInfo.fCalibrationIlluminant2); SetColorMatrix2 (profileInfo.fColorMatrix2); if (profileInfo.fForwardMatrix2.NotEmpty ()) { SetForwardMatrix2 (profileInfo.fForwardMatrix2); } if (profileInfo.fReductionMatrix2.NotEmpty ()) { SetReductionMatrix2 (profileInfo.fReductionMatrix2); } } SetProfileCalibrationSignature (profileInfo.fProfileCalibrationSignature.Get ()); if (profileInfo.fHueSatDeltas1Offset != 0 && profileInfo.fHueSatDeltas1Count != 0) { TempBigEndian setEndianness (stream, profileInfo.fBigEndian); stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset); bool skipSat0 = (profileInfo.fHueSatDeltas1Count == profileInfo.fProfileHues * (profileInfo.fProfileSats - 1) * profileInfo.fProfileVals * 3); ReadHueSatMap (stream, fHueSatDeltas1, profileInfo.fProfileHues, profileInfo.fProfileSats, profileInfo.fProfileVals, skipSat0); } if (profileInfo.fHueSatDeltas2Offset != 0 && profileInfo.fHueSatDeltas2Count != 0) { TempBigEndian setEndianness (stream, profileInfo.fBigEndian); stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset); bool skipSat0 = (profileInfo.fHueSatDeltas2Count == profileInfo.fProfileHues * (profileInfo.fProfileSats - 1) * profileInfo.fProfileVals * 3); ReadHueSatMap (stream, fHueSatDeltas2, profileInfo.fProfileHues, profileInfo.fProfileSats, profileInfo.fProfileVals, skipSat0); } if (profileInfo.fLookTableOffset != 0 && profileInfo.fLookTableCount != 0) { TempBigEndian setEndianness (stream, profileInfo.fBigEndian); stream.SetReadPosition (profileInfo.fLookTableOffset); bool skipSat0 = (profileInfo.fLookTableCount == profileInfo.fLookTableHues * (profileInfo.fLookTableSats - 1) * profileInfo.fLookTableVals * 3); ReadHueSatMap (stream, fLookTable, profileInfo.fLookTableHues, profileInfo.fLookTableSats, profileInfo.fLookTableVals, skipSat0); } if ((profileInfo.fToneCurveCount & 1) == 0) { TempBigEndian setEndianness (stream, profileInfo.fBigEndian); stream.SetReadPosition (profileInfo.fToneCurveOffset); uint32 points = profileInfo.fToneCurveCount / 2; fToneCurve.fCoord.resize (points); for (size_t i = 0; i < points; i++) { dng_point_real64 point; point.h = stream.Get_real32 (); point.v = stream.Get_real32 (); fToneCurve.fCoord [i] = point; } } }