From 5b57a1749bf0904505e5ef3dea92ceaa4fb0a3a6 Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Sun, 23 Apr 2006 08:05:55 +0000 Subject: [PATCH] TIFF parser checkpoint (experimental): Improved CR2 support (changes in the TIFF structure table), added support for Jpeg thumbnails, enhanced TiffDirectory so that the next pointer is optional. --- src/canonmn2.cpp | 6 +- src/exif.cpp | 4 ++ src/imgreg.cpp | 2 + src/tiffcomposite.cpp | 76 +++++++++----------- src/tiffcomposite.hpp | 157 ++++++++++++++++++++++++++---------------- src/tiffimage.cpp | 42 +++++++++-- src/tiffimage.hpp | 59 ++++++++++++++++ src/tiffparser.cpp | 24 ++++--- src/tiffvisitor.cpp | 134 +++++++++++++++++++++++++++++++---- src/tiffvisitor.hpp | 20 ++++++ 10 files changed, 389 insertions(+), 135 deletions(-) diff --git a/src/canonmn2.cpp b/src/canonmn2.cpp index fcccace2..0350b2a7 100644 --- a/src/canonmn2.cpp +++ b/src/canonmn2.cpp @@ -64,14 +64,14 @@ namespace Exiv2 { TiffComponent::AutoPtr TiffCanonCreator::create(uint32_t extendedTag, uint16_t group) { - const TiffStructure* ts = find(tiffStructure_, - TiffStructure::Key(extendedTag, group)); TiffComponent::AutoPtr tc(0); uint16_t tag = static_cast(extendedTag & 0xffff); + const TiffStructure* ts = find(tiffStructure_, + TiffStructure::Key(extendedTag, group)); if (ts && ts->newTiffCompFct_) { tc = ts->newTiffCompFct_(tag, ts); } - if (!ts) { + if (!ts && extendedTag != Tag::next) { tc = TiffComponent::AutoPtr(new TiffEntry(tag, group)); } return tc; diff --git a/src/exif.cpp b/src/exif.cpp index 5107604c..ac65fbbc 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -988,6 +988,10 @@ namespace Exiv2 { thumbnail = Thumbnail::AutoPtr(new TiffThumbnail); } } + else { + pos = findKey(ExifKey("Exif.Thumbnail.JPEGInterchangeFormat")); + if (pos != end()) thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); + } return thumbnail; } // ExifData::getThumbnail diff --git a/src/imgreg.cpp b/src/imgreg.cpp index e0bfed68..0f524d8d 100644 --- a/src/imgreg.cpp +++ b/src/imgreg.cpp @@ -33,6 +33,7 @@ EXIV2_RCSID("@(#) $Id$"); // included header files #include "image.hpp" #include "jpgimage.hpp" +//#include "cr2image.hpp" #include "crwimage.hpp" #include "tiffimage.hpp" @@ -45,6 +46,7 @@ namespace Exiv2 { ImageFactory::Registry ImageFactory::registry_[] = { Registry(ImageType::jpeg, newJpegInstance, isJpegType), Registry(ImageType::exv, newExvInstance, isExvType), +// Registry(ImageType::cr2, newCr2Instance, isCr2Type), Registry(ImageType::crw, newCrwInstance, isCrwType), Registry(ImageType::tiff, newTiffInstance, isTiffType) }; diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp index 8d7f476d..3be23d74 100644 --- a/src/tiffcomposite.cpp +++ b/src/tiffcomposite.cpp @@ -28,10 +28,6 @@ #include "rcsid.hpp" EXIV2_RCSID("@(#) $Id$"); -// Define DEBUG to output debug information to std::cerr, e.g, by calling make -// like this: make DEFS=-DDEBUG tiffcomposite.o -//#define DEBUG - // ***************************************************************************** // included header files #ifdef _MSC_VER @@ -60,21 +56,6 @@ namespace Exiv2 { || Tag::all == extendedTag_ && key.g_ == group_; } - void TiffHeade2::print(std::ostream& os, const std::string& prefix) const - { - os << prefix - << "Header, offset = 0x" << std::setw(8) << std::setfill('0') - << std::hex << std::right << offset_; - - switch (byteOrder_) { - case littleEndian: os << ", little endian encoded"; break; - case bigEndian: os << ", big endian encoded"; break; - case invalidByteOrder: break; - } - os << "\n"; - - } // TiffHeade2::print - TiffDirectory::~TiffDirectory() { Components::iterator b = components_.begin(); @@ -107,27 +88,6 @@ namespace Exiv2 { } } // TiffArrayEntry::~TiffArrayEntry - const uint16_t TiffHeade2::tag_ = 42; - - bool TiffHeade2::read(const byte* pData, uint32_t size) - { - if (size < 8) return false; - - if (pData[0] == 0x49 && pData[1] == 0x49) { - byteOrder_ = littleEndian; - } - else if (pData[0] == 0x4d && pData[1] == 0x4d) { - byteOrder_ = bigEndian; - } - else { - return false; - } - if (tag_ != getUShort(pData + 2, byteOrder_)) return false; - offset_ = getULong(pData + 4, byteOrder_); - - return true; - } // TiffHeade2::read - std::string TiffComponent::groupName() const { // Todo: This mapping should be a table and it belongs somewhere else @@ -182,7 +142,7 @@ namespace Exiv2 { void TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent) { - pNext_ = tiffComponent.release(); + if (hasNext_) pNext_ = tiffComponent.release(); } // TiffDirectory::doAddNext void TiffSubIfd::doAddNext(TiffComponent::AutoPtr tiffComponent) @@ -205,6 +165,16 @@ namespace Exiv2 { visitor.visitEntry(this); } // TiffEntry::doAccept + void TiffDataEntry::doAccept(TiffVisitor& visitor) + { + visitor.visitDataEntry(this); + } // TiffDataEntry::doAccept + + void TiffSizeEntry::doAccept(TiffVisitor& visitor) + { + visitor.visitSizeEntry(this); + } // TiffSizeEntry::doAccept + void TiffDirectory::doAccept(TiffVisitor& visitor) { visitor.visitDirectory(this); @@ -214,9 +184,7 @@ namespace Exiv2 { (*i)->accept(visitor); } if (visitor.go()) visitor.visitDirectoryNext(this); - if (pNext_) { - pNext_->accept(visitor); - } + if (pNext_) pNext_->accept(visitor); if (visitor.go()) visitor.visitDirectoryEnd(this); } // TiffDirectory::doAccept @@ -293,4 +261,24 @@ namespace Exiv2 { ts->group_)); } + TiffComponent::AutoPtr newTiffThumbData(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr(new TiffDataEntry(tag, + ts->group_, + 0x0202, + Group::ifd1)); + } + + TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr(new TiffSizeEntry(tag, + ts->group_, + 0x0201, + Group::ifd1)); + } + } // namespace Exiv2 diff --git a/src/tiffcomposite.hpp b/src/tiffcomposite.hpp index c7cbd73b..4494ece0 100644 --- a/src/tiffcomposite.hpp +++ b/src/tiffcomposite.hpp @@ -72,6 +72,7 @@ namespace Exiv2 { const uint16_t gps = 4; //!< GPS IFD const uint16_t iop = 5; //!< Interoperability IFD const uint16_t mn = 256; //!< Makernote + const uint16_t ignr = 511; //!< Read but do not decode } /*! @@ -86,65 +87,6 @@ namespace Exiv2 { const uint32_t all = 0x40000; //!< Special tag: all tags in a group } - /*! - @brief This class models a TIFF header structure. - */ - class TiffHeade2 { - public: - //! @name Creators - //@{ - //! Default constructor - TiffHeade2() - : byteOrder_ (littleEndian), - offset_ (0x00000008) - {} - //@} - - //! @name Manipulators - //@{ - /*! - @brief Read the TIFF header from a data buffer. Return false if the - data buffer does not contain a TIFF header, else true. - - @param pData Pointer to the data buffer. - @param size Number of bytes in the data buffer. - */ - bool read(const byte* pData, uint32_t size); - //@} - - //! @name Accessors - //@{ - /*! - @brief Write the TIFF header to the binary image \em blob. - This method appends to the blob. - - @param blob Binary image to add to. - - @throw Error If the header cannot be written. - */ - void write(Blob& blob) const; - /*! - @brief Print debug info for the TIFF header to \em os. - - @param os Output stream to write to. - @param prefix Prefix to be written before each line of output. - */ - void print(std::ostream& os, const std::string& prefix ="") const; - //! Return the byte order (little or big endian). - ByteOrder byteOrder() const { return byteOrder_; } - //! Return the offset to the start of the root directory - uint32_t offset() const { return offset_; } - //@} - - private: - // DATA - ByteOrder byteOrder_; //!< Applicable byte order - uint32_t offset_; //!< Offset to the start of the root dir - - static const uint16_t tag_; //!< 42, identifies the buffer as TIFF data - - }; // class TiffHeade2 - /*! @brief Interface class for components of a TIFF directory hierarchy (Composite pattern). Both TIFF directories as well as entries @@ -342,6 +284,84 @@ namespace Exiv2 { }; // class TiffEntry + /*! + @brief A standard TIFF IFD entry consisting of a value which is an offset + to a data area and the data area. The size of the data area is + provided in a related TiffSizeEntry, tag and group of which are set + in the constructor. This component is used, e.g., for + \em Exif.Thumbnail.JPEGInterchangeFormat for which the size is + provided in \em Exif.Thumbnail.JPEGInterchangeFormatLength. + */ + class TiffDataEntry : public TiffEntryBase { + public: + //! @name Creators + //@{ + //! Constructor + TiffDataEntry(uint16_t tag, uint16_t group, uint16_t szTag, uint16_t szGroup) + : TiffEntryBase(tag, group), szTag_(szTag), szGroup_(szGroup) {} + //! Virtual destructor. + virtual ~TiffDataEntry() {} + //@} + + //! @name Accessors + //@{ + //! Return the group of the entry which has the size + uint16_t szTag() const { return szTag_; } + //! Return the group of the entry which has the size + uint16_t szGroup() const { return szGroup_; } + //@} + + private: + //! @name Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + //@} + + private: + // DATA + const uint16_t szTag_; //!< Tag of the entry with the size + const uint16_t szGroup_; //!< Group of the entry with the size + + }; // class TiffDataEntry + + /*! + @brief A TIFF IFD entry containing the size of a data area of a related + TiffDataEntry. This component is used, e.g. for + \em Exif.Thumbnail.JPEGInterchangeFormatLength, which contains the + size of \em Exif.Thumbnail.JPEGInterchangeFormat. + */ + class TiffSizeEntry : public TiffEntryBase { + public: + //! @name Creators + //@{ + //! Constructor + TiffSizeEntry(uint16_t tag, uint16_t group, uint16_t dtTag, uint16_t dtGroup) + : TiffEntryBase(tag, group), dtTag_(dtTag), dtGroup_(dtGroup) {} + //! Virtual destructor. + virtual ~TiffSizeEntry() {} + //@} + + //! @name Accessors + //@{ + //! Return the group of the related entry which has the data area + uint16_t dtTag() const { return dtTag_; } + //! Return the group of the related entry which has the data area + uint16_t dtGroup() const { return dtGroup_; } + //@} + + private: + //! @name Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + //@} + + private: + // DATA + const uint16_t dtTag_; //!< Tag of the entry with the data area + const uint16_t dtGroup_; //!< Group of the entry with the data area + + }; // class TiffSizeEntry + /*! @brief This class models a TIFF directory (%Ifd). It is a composite component of the TIFF tree. @@ -352,12 +372,18 @@ namespace Exiv2 { //! @name Creators //@{ //! Default constructor - TiffDirectory(uint16_t tag, uint16_t group) - : TiffComponent(tag, group), pNext_(0) {} + TiffDirectory(uint16_t tag, uint16_t group, bool hasNext =true) + : TiffComponent(tag, group), hasNext_(hasNext), pNext_(0) {} //! Virtual destructor virtual ~TiffDirectory(); //@} + //! @name Manipulators + //@{ + //! Return true if the directory has a next pointer + bool hasNext() const { return hasNext_; } + //@} + private: //! @name Manipulators //@{ @@ -369,6 +395,7 @@ namespace Exiv2 { private: // DATA Components components_; //!< List of components in this directory + const bool hasNext_; //!< True if the directory has a next pointer TiffComponent* pNext_; //!< Pointer to the next IFD }; // class TiffDirectory @@ -525,6 +552,14 @@ namespace Exiv2 { TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag, const TiffStructure* ts); + //! Function to create and initialize a new TIFF entry for a Jpeg thumbnail (data) + TiffComponent::AutoPtr newTiffThumbData(uint16_t tag, + const TiffStructure* ts); + + //! Function to create and initialize a new TIFF entry for a Jpeg thumbnail (size) + TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag, + const TiffStructure* ts); + } // namespace Exiv2 #endif // #ifndef TIFFCOMPOSITE_HPP_ diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index 4209ea68..2f8dcdee 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -29,10 +29,6 @@ #include "rcsid.hpp" EXIV2_RCSID("@(#) $Id$"); -// Define DEBUG to output debug information to std::cerr, e.g, by calling make -// like this: make DEFS=-DDEBUG tiffparser.o -//#define DEBUG - // ***************************************************************************** // included header files #ifdef _MSC_VER @@ -48,7 +44,9 @@ EXIV2_RCSID("@(#) $Id$"); #include "futils.hpp" // + standard includes +#include #include +#include #include // ***************************************************************************** @@ -185,6 +183,42 @@ namespace Exiv2 { return isTiffType(iIo, advance); } + const uint16_t TiffHeade2::tag_ = 42; + + bool TiffHeade2::read(const byte* pData, uint32_t size) + { + if (size < 8) return false; + + if (pData[0] == 0x49 && pData[1] == 0x49) { + byteOrder_ = littleEndian; + } + else if (pData[0] == 0x4d && pData[1] == 0x4d) { + byteOrder_ = bigEndian; + } + else { + return false; + } + if (tag_ != getUShort(pData + 2, byteOrder_)) return false; + offset_ = getULong(pData + 4, byteOrder_); + + return true; + } // TiffHeade2::read + + void TiffHeade2::print(std::ostream& os, const std::string& prefix) const + { + os << prefix + << "Header, offset = 0x" << std::setw(8) << std::setfill('0') + << std::hex << std::right << offset_; + + switch (byteOrder_) { + case littleEndian: os << ", little endian encoded"; break; + case bigEndian: os << ", big endian encoded"; break; + case invalidByteOrder: break; + } + os << "\n"; + + } // TiffHeade2::print + // ************************************************************************* // free functions diff --git a/src/tiffimage.hpp b/src/tiffimage.hpp index 0a910393..926d82a1 100644 --- a/src/tiffimage.hpp +++ b/src/tiffimage.hpp @@ -161,6 +161,65 @@ namespace Exiv2 { }; // class TiffImage + /*! + @brief This class models a TIFF header structure. + */ + class TiffHeade2 { + public: + //! @name Creators + //@{ + //! Default constructor + TiffHeade2() + : byteOrder_ (littleEndian), + offset_ (0x00000008) + {} + //@} + + //! @name Manipulators + //@{ + /*! + @brief Read the TIFF header from a data buffer. Return false if the + data buffer does not contain a TIFF header, else true. + + @param pData Pointer to the data buffer. + @param size Number of bytes in the data buffer. + */ + bool read(const byte* pData, uint32_t size); + //@} + + //! @name Accessors + //@{ + /*! + @brief Write the TIFF header to the binary image \em blob. + This method appends to the blob. + + @param blob Binary image to add to. + + @throw Error If the header cannot be written. + */ + void write(Blob& blob) const; + /*! + @brief Print debug info for the TIFF header to \em os. + + @param os Output stream to write to. + @param prefix Prefix to be written before each line of output. + */ + void print(std::ostream& os, const std::string& prefix ="") const; + //! Return the byte order (little or big endian). + ByteOrder byteOrder() const { return byteOrder_; } + //! Return the offset to the start of the root directory + uint32_t offset() const { return offset_; } + //@} + + private: + // DATA + ByteOrder byteOrder_; //!< Applicable byte order + uint32_t offset_; //!< Offset to the start of the root dir + + static const uint16_t tag_; //!< 42, identifies the buffer as TIFF data + + }; // class TiffHeade2 + // ***************************************************************************** // template, inline and free functions diff --git a/src/tiffparser.cpp b/src/tiffparser.cpp index 61285661..9c0bf239 100644 --- a/src/tiffparser.cpp +++ b/src/tiffparser.cpp @@ -29,10 +29,6 @@ #include "rcsid.hpp" EXIV2_RCSID("@(#) $Id$"); -// Define DEBUG to output debug information to std::cerr, e.g, by calling make -// like this: make DEFS=-DDEBUG tiffparser.o -//#define DEBUG - // ***************************************************************************** // included header files #ifdef _MSC_VER @@ -44,6 +40,7 @@ EXIV2_RCSID("@(#) $Id$"); #include "tiffparser.hpp" #include "tiffcomposite.hpp" #include "tiffvisitor.hpp" +#include "tiffimage.hpp" #include "error.hpp" // + standard includes @@ -61,6 +58,9 @@ EXIV2_RCSID("@(#) $Id$"); images which need to be loaded completely. + TiffComponent: should it have end() and setEnd() or pData and size? + Can NewTiffCompFct and TiffCompFactoryFct be combined? + + Create function is repeated when actually only the table changes. Fix it. + + CR2 Makernotes don't seem to have a next pointer but Canon Jpeg Makernotes + do. What a mess. (That'll become an issue when it comes to writing to CR2) in crwimage.* : @@ -93,27 +93,31 @@ namespace Exiv2 { { 0x8825, Group::ifd0, newTiffSubIfd, Group::gps }, { 0xa005, Group::exif, newTiffSubIfd, Group::iop }, { 0x927c, Group::exif, newTiffMnEntry, Group::mn }, - { Tag::next, Group::ifd0, newTiffDirectory, Group::ifd0 } + { 0x0201, Group::ifd1, newTiffThumbData, Group::ifd1 }, + { 0x0202, Group::ifd1, newTiffThumbSize, Group::ifd1 }, + { Tag::next, Group::ifd0, newTiffDirectory, Group::ifd1 }, + { Tag::next, Group::ifd1, newTiffDirectory, Group::ignr }, + { Tag::next, Group::ignr, newTiffDirectory, Group::ignr } }; TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag, uint16_t group) { - const TiffStructure* ts = find(tiffStructure_, - TiffStructure::Key(extendedTag, group)); TiffComponent::AutoPtr tc(0); uint16_t tag = static_cast(extendedTag & 0xffff); + const TiffStructure* ts = find(tiffStructure_, + TiffStructure::Key(extendedTag, group)); if (ts && ts->newTiffCompFct_) { tc = ts->newTiffCompFct_(tag, ts); } - if (!ts) { + if (!ts && extendedTag != Tag::next) { tc = TiffComponent::AutoPtr(new TiffEntry(tag, group)); } return tc; } // TiffCreator::create - void TiffParser::decode(Image* pImage, - const byte* pData, + void TiffParser::decode(Image* pImage, + const byte* pData, uint32_t size, TiffCompFactoryFct createFct) { diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp index 48738c53..a95a4e73 100644 --- a/src/tiffvisitor.cpp +++ b/src/tiffvisitor.cpp @@ -77,6 +77,16 @@ namespace Exiv2 { findObject(object); } + void TiffFinder::visitDataEntry(TiffDataEntry* object) + { + findObject(object); + } + + void TiffFinder::visitSizeEntry(TiffSizeEntry* object) + { + findObject(object); + } + void TiffFinder::visitDirectory(TiffDirectory* object) { findObject(object); @@ -112,6 +122,16 @@ namespace Exiv2 { decodeTiffEntry(object); } + void TiffMetadataDecoder::visitDataEntry(TiffDataEntry* object) + { + decodeTiffEntry(object); + } + + void TiffMetadataDecoder::visitSizeEntry(TiffSizeEntry* object) + { + decodeTiffEntry(object); + } + void TiffMetadataDecoder::visitDirectory(TiffDirectory* object) { // Nothing to do @@ -136,11 +156,14 @@ namespace Exiv2 { { assert(object != 0); + if (object->group() == Group::ignr) return; + // Todo: ExifKey should have an appropriate c'tor, it should not be // necessary to use groupName here ExifKey k(object->tag(), object->groupName()); assert(pImage_ != 0); pImage_->exifData().add(k, object->pValue()); + } // TiffMetadataDecoder::decodeTiffEntry void TiffMetadataDecoder::visitArrayEntry(TiffArrayEntry* object) @@ -177,6 +200,21 @@ namespace Exiv2 { printTiffEntry(object, prefix()); } // TiffPrinter::visitEntry + void TiffPrinter::visitDataEntry(TiffDataEntry* object) + { + printTiffEntry(object, prefix()); + if (object->pValue()) { + os_ << prefix() << "Data area " + << object->pValue()->sizeDataArea() + << " bytes.\n"; + } + } // TiffPrinter::visitEntry + + void TiffPrinter::visitSizeEntry(TiffSizeEntry* object) + { + printTiffEntry(object, prefix()); + } + void TiffPrinter::visitDirectory(TiffDirectory* object) { assert(object != 0); @@ -193,8 +231,10 @@ namespace Exiv2 { void TiffPrinter::visitDirectoryNext(TiffDirectory* object) { decIndent(); - if (object->pNext_) os_ << prefix() << "Next directory:\n"; - else os_ << prefix() << "No next directory\n"; + if (object->hasNext()) { + if (object->pNext_) os_ << prefix() << "Next directory:\n"; + else os_ << prefix() << "No next directory\n"; + } } // TiffPrinter::visitDirectoryNext void TiffPrinter::visitDirectoryEnd(TiffDirectory* object) @@ -318,6 +358,60 @@ namespace Exiv2 { readTiffEntry(object); } + void TiffReader::visitDataEntry(TiffDataEntry* object) + { + assert(object != 0); + + readTiffEntry(object); + TiffFinder finder(object->szTag(), object->szGroup()); + pRoot_->accept(finder); + TiffEntryBase* te = dynamic_cast(finder.result()); + if (te && te->pValue()) { + long size = te->pValue()->toLong(); + long offset = object->pValue()->toLong(); + if (baseOffset() + offset + size <= size_) { + object->pValue_->setDataArea(pData_ + baseOffset() + offset, size); + } +#ifndef SUPPRESS_WARNINGS + else { + std::cerr << "Warning: " + << "Directory " << object->groupName() + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " Data area exceeds data buffer, ignoring it.\n"; + } +#endif + } + + } + + void TiffReader::visitSizeEntry(TiffSizeEntry* object) + { + assert(object != 0); + + readTiffEntry(object); + TiffFinder finder(object->dtTag(), object->dtGroup()); + pRoot_->accept(finder); + TiffEntryBase* te = dynamic_cast(finder.result()); + if (te && te->pValue()) { + long offset = te->pValue()->toLong(); + long size = object->pValue()->toLong(); + if (baseOffset() + offset + size <= size_) { + te->pValue_->setDataArea(pData_ + baseOffset() + offset, size); + } +#ifndef SUPPRESS_WARNINGS + else { + std::cerr << "Warning: " + << "Directory " << object->groupName() + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " Data area exceeds data buffer, ignoring it.\n"; + } +#endif + } + + } + void TiffReader::visitDirectory(TiffDirectory* object) { assert(object != 0); @@ -347,6 +441,7 @@ namespace Exiv2 { } uint16_t tag = getUShort(p, byteOrder()); TiffComponent::AutoPtr tc = create(tag, object->group()); + assert(tc.get()); tc->setStart(p); object->addChild(tc); p += 12; @@ -360,20 +455,32 @@ namespace Exiv2 { #endif return; } - uint32_t next = getLong(p, byteOrder()); - if (next) { - TiffComponent::AutoPtr tc = create(Tag::next, object->group()); - if (baseOffset() + next > size_) { + if (object->hasNext()) { + TiffComponent::AutoPtr tc(0); + uint32_t next = getLong(p, byteOrder()); + if (next) { + tc = create(Tag::next, object->group()); #ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() << ": " - << " Next pointer is out of bounds.\n"; + if (tc.get() == 0) { + std::cerr << "Warning: " + << "Directory " << object->groupName() + << " has an unhandled next pointer.\n"; + } #endif - return; } - tc->setStart(pData_ + baseOffset() + next); - object->addNext(tc); - } + if (tc.get()) { + if (baseOffset() + next > size_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: " + << "Directory " << object->groupName() << ": " + << " Next pointer is out of bounds.\n"; +#endif + return; + } + tc->setStart(pData_ + baseOffset() + next); + object->addNext(tc); + } + } // object->hasNext() } // TiffReader::visitDirectory @@ -539,6 +646,7 @@ namespace Exiv2 { for (uint16_t i = 0; i < static_cast(object->count()); ++i) { uint16_t tag = i; TiffComponent::AutoPtr tc = create(tag, object->elGroup()); + assert(tc.get()); tc->setStart(object->pData() + i * 2); object->addChild(tc); } diff --git a/src/tiffvisitor.hpp b/src/tiffvisitor.hpp index 0a25d034..b8085098 100644 --- a/src/tiffvisitor.hpp +++ b/src/tiffvisitor.hpp @@ -84,6 +84,10 @@ namespace Exiv2 { void setGo(bool go) { go_ = go; } //! Operation to perform for a TIFF entry virtual void visitEntry(TiffEntry* object) =0; + //! Operation to perform for a TIFF data entry + virtual void visitDataEntry(TiffDataEntry* object) =0; + //! Operation to perform for a TIFF size entry + virtual void visitSizeEntry(TiffSizeEntry* object) =0; //! Operation to perform for a TIFF directory virtual void visitDirectory(TiffDirectory* object) =0; /*! @@ -142,6 +146,10 @@ namespace Exiv2 { //@{ //! Find tag and group in a TIFF entry virtual void visitEntry(TiffEntry* object); + //! Find tag and group in a TIFF data entry + virtual void visitDataEntry(TiffDataEntry* object); + //! Find tag and group in a TIFF size entry + virtual void visitSizeEntry(TiffSizeEntry* object); //! Find tag and group in a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Find tag and group in a TIFF sub-IFD @@ -196,6 +204,10 @@ namespace Exiv2 { //@{ //! Decode a TIFF entry virtual void visitEntry(TiffEntry* object); + //! Decode a TIFF data entry + virtual void visitDataEntry(TiffDataEntry* object); + //! Decode a TIFF size entry + virtual void visitSizeEntry(TiffSizeEntry* object); //! Decode a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Decode a TIFF sub-IFD @@ -290,6 +302,10 @@ namespace Exiv2 { //@{ //! Read a TIFF entry from the data buffer virtual void visitEntry(TiffEntry* object); + //! Read a TIFF data entry from the data buffer + virtual void visitDataEntry(TiffDataEntry* object); + //! Read a TIFF size entry from the data buffer + virtual void visitSizeEntry(TiffSizeEntry* object); //! Read a TIFF directory from the data buffer virtual void visitDirectory(TiffDirectory* object); //! Read a TIFF sub-IFD from the data buffer @@ -353,6 +369,10 @@ namespace Exiv2 { //@{ //! Print a TIFF entry. virtual void visitEntry(TiffEntry* object); + //! Print a TIFF data entry. + virtual void visitDataEntry(TiffDataEntry* object); + //! Print a TIFF size entry. + virtual void visitSizeEntry(TiffSizeEntry* object); //! Print a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Print header before next directory