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_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_camera_profile_info::ParseTag (dng_stream &stream, uint32 parentCode, uint32 tagCode, uint32 tagType, uint32 tagCount, uint64 tagOffset) { switch (tagCode) { case tcCalibrationIlluminant1: { CheckTagType (parentCode, tagCode, tagType, ttShort); CheckTagCount (parentCode, tagCode, tagCount, 1); fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("CalibrationIlluminant1: %s\n", LookupLightSource (fCalibrationIlluminant1)); } #endif break; } case tcCalibrationIlluminant2: { CheckTagType (parentCode, tagCode, tagType, ttShort); CheckTagCount (parentCode, tagCode, tagCount, 1); fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { printf ("CalibrationIlluminant2: %s\n", LookupLightSource (fCalibrationIlluminant2)); } #endif break; } case tcColorMatrix1: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (fColorPlanes == 0) { fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); } if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, fColorPlanes, 3, fColorMatrix1)) return false; #if qDNGValidate if (gVerbose) { printf ("ColorMatrix1:\n"); DumpMatrix (fColorMatrix1); } #endif break; } case tcColorMatrix2: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, fColorPlanes, 3, fColorMatrix2)) return false; #if qDNGValidate if (gVerbose) { printf ("ColorMatrix2:\n"); DumpMatrix (fColorMatrix2); } #endif break; } case tcForwardMatrix1: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, 3, fColorPlanes, fForwardMatrix1)) return false; #if qDNGValidate if (gVerbose) { printf ("ForwardMatrix1:\n"); DumpMatrix (fForwardMatrix1); } #endif break; } case tcForwardMatrix2: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, 3, fColorPlanes, fForwardMatrix2)) return false; #if qDNGValidate if (gVerbose) { printf ("ForwardMatrix2:\n"); DumpMatrix (fForwardMatrix2); } #endif break; } case tcReductionMatrix1: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, 3, fColorPlanes, fReductionMatrix1)) return false; #if qDNGValidate if (gVerbose) { printf ("ReductionMatrix1:\n"); DumpMatrix (fReductionMatrix1); } #endif break; } case tcReductionMatrix2: { CheckTagType (parentCode, tagCode, tagType, ttSRational); if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) return false; if (!ParseMatrixTag (stream, parentCode, tagCode, tagType, tagCount, 3, fColorPlanes, fReductionMatrix2)) return false; #if qDNGValidate if (gVerbose) { printf ("ReductionMatrix2:\n"); DumpMatrix (fReductionMatrix2); } #endif break; } case tcProfileCalibrationSignature: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fProfileCalibrationSignature, false, false); #if qDNGValidate if (gVerbose) { printf ("ProfileCalibrationSignature: "); DumpString (fProfileCalibrationSignature); printf ("\n"); } #endif break; } case tcProfileName: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fProfileName, false, false); #if qDNGValidate if (gVerbose) { printf ("ProfileName: "); DumpString (fProfileName); printf ("\n"); } #endif break; } case tcProfileCopyright: { CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); ParseStringTag (stream, parentCode, tagCode, tagCount, fProfileCopyright, false, false); #if qDNGValidate if (gVerbose) { printf ("ProfileCopyright: "); DumpString (fProfileCopyright); printf ("\n"); } #endif break; } case tcProfileEmbedPolicy: { CheckTagType (parentCode, tagCode, tagType, ttLong); CheckTagCount (parentCode, tagCode, tagCount, 1); fEmbedPolicy = stream.TagValue_uint32 (tagType); #if qDNGValidate if (gVerbose) { const char *policy; switch (fEmbedPolicy) { case pepAllowCopying: policy = "Allow copying"; break; case pepEmbedIfUsed: policy = "Embed if used"; break; case pepEmbedNever: policy = "Embed never"; break; case pepNoRestrictions: policy = "No restrictions"; break; default: policy = "INVALID VALUE"; } printf ("ProfileEmbedPolicy: %s\n", policy); } #endif break; } case tcProfileHueSatMapDims: { CheckTagType (parentCode, tagCode, tagType, ttLong); CheckTagCount (parentCode, tagCode, tagCount, 2, 3); fProfileHues = stream.TagValue_uint32 (tagType); fProfileSats = stream.TagValue_uint32 (tagType); if (tagCount > 2) fProfileVals = stream.TagValue_uint32 (tagType); else fProfileVals = 1; #if qDNGValidate if (gVerbose) { printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n", (unsigned) fProfileHues, (unsigned) fProfileSats, (unsigned) fProfileVals); } #endif break; } case tcProfileHueSatMapData1: { if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; bool skipSat0 = (tagCount == fProfileHues * (fProfileSats - 1) * fProfileVals * 3); if (!skipSat0) { if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues * fProfileSats * fProfileVals * 3)) return false; } fBigEndian = stream.BigEndian (); fHueSatDeltas1Offset = tagOffset; fHueSatDeltas1Count = tagCount; #if qDNGValidate if (gVerbose) { printf ("ProfileHueSatMapData1:\n"); DumpHueSatMap (stream, fProfileHues, fProfileSats, fProfileVals, skipSat0); } #endif break; } case tcProfileHueSatMapData2: { if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; bool skipSat0 = (tagCount == fProfileHues * (fProfileSats - 1) * fProfileVals * 3); if (!skipSat0) { if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues * fProfileSats * fProfileVals * 3)) return false; } fBigEndian = stream.BigEndian (); fHueSatDeltas2Offset = tagOffset; fHueSatDeltas2Count = tagCount; #if qDNGValidate if (gVerbose) { printf ("ProfileHueSatMapData2:\n"); DumpHueSatMap (stream, fProfileHues, fProfileSats, fProfileVals, skipSat0); } #endif break; } case tcProfileLookTableDims: { CheckTagType (parentCode, tagCode, tagType, ttLong); CheckTagCount (parentCode, tagCode, tagCount, 2, 3); fLookTableHues = stream.TagValue_uint32 (tagType); fLookTableSats = stream.TagValue_uint32 (tagType); if (tagCount > 2) fLookTableVals = stream.TagValue_uint32 (tagType); else fLookTableVals = 1; #if qDNGValidate if (gVerbose) { printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n", (unsigned) fLookTableHues, (unsigned) fLookTableSats, (unsigned) fLookTableVals); } #endif break; } case tcProfileLookTableData: { if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; bool skipSat0 = (tagCount == fLookTableHues * (fLookTableSats - 1) * fLookTableVals * 3); if (!skipSat0) { if (!CheckTagCount (parentCode, tagCode, tagCount, fLookTableHues * fLookTableSats * fLookTableVals * 3)) return false; } fBigEndian = stream.BigEndian (); fLookTableOffset = tagOffset; fLookTableCount = tagCount; #if qDNGValidate if (gVerbose) { printf ("ProfileLookTableData:\n"); DumpHueSatMap (stream, fLookTableHues, fLookTableSats, fLookTableVals, skipSat0); } #endif break; } case tcProfileToneCurve: { if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount)) return false; if ((tagCount & 1) != 0) { #if qDNGValidate { char message [256]; sprintf (message, "%s %s has odd count (%u)", LookupParentCode (parentCode), LookupTagCode (parentCode, tagCode), (unsigned) tagCount); ReportWarning (message); } #endif return false; } fBigEndian = stream.BigEndian (); fToneCurveOffset = tagOffset; fToneCurveCount = tagCount; #if qDNGValidate if (gVerbose) { DumpTagValues (stream, "Coord", parentCode, tagCode, tagType, tagCount); } #endif break; } case tcUniqueCameraModel: { // Note: This code is only used when parsing stand-alone // profiles. The embedded profiles are assumed to be restricted // to the model they are embedded in. CheckTagType (parentCode, tagCode, tagType, ttAscii); ParseStringTag (stream, parentCode, tagCode, tagCount, fUniqueCameraModel, false); bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); #if qDNGValidate if (didTrim) { ReportWarning ("UniqueCameraModel string has trailing blanks"); } if (gVerbose) { printf ("UniqueCameraModel: "); DumpString (fUniqueCameraModel); printf ("\n"); } #else (void) didTrim; // Unused #endif break; } default: { return false; } } return true; }