From bab89c1ba39268889a1c6cdafd33671b1c7fa995 Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Tue, 18 Apr 2006 12:26:48 +0000 Subject: [PATCH] TIFF parser checkpoint (experimental): Added support for more esoteric makernotes with different byte order, base offset and their own component factory. Added Fujifilm makernote to test the byte order and base offset features. Use TiffCreator as part of a 'state' class instead of as a templated policy to be able to change the factory during a parse run. --- src/Makefile | 4 +- src/fujimn2.cpp | 133 +++++++++++++++++++ src/fujimn2.hpp | 133 +++++++++++++++++++ src/makernote2.cpp | 17 ++- src/makernote2.hpp | 32 +++-- src/mnreg.cpp | 7 +- src/olympusmn2.cpp | 14 +- src/olympusmn2.hpp | 7 +- src/tiffcomposite.cpp | 1 + src/tiffcomposite.hpp | 31 +++-- src/tiffimage.cpp | 2 +- src/tiffparse.cpp | 18 ++- src/tiffparser.cpp | 39 ++++-- src/tiffparser.hpp | 59 ++------- src/tiffvisitor.cpp | 274 +++++++++++++++++++++++++++++++++++++- src/tiffvisitor.hpp | 107 +++++++++++---- src/tiffvisitor_tmpl.hpp | 277 --------------------------------------- 17 files changed, 747 insertions(+), 408 deletions(-) create mode 100644 src/fujimn2.cpp create mode 100644 src/fujimn2.hpp delete mode 100644 src/tiffvisitor_tmpl.hpp diff --git a/src/Makefile b/src/Makefile index a75a0f2d..7d9a76a8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -47,11 +47,11 @@ include $(top_srcdir)/config/config.mk # Source files # Add standalone C++ header files to this list -CCHDR = exv_conf.h exv_msvc.h mn.hpp rcsid.hpp tiffvisitor_tmpl.hpp +CCHDR = exv_conf.h exv_msvc.h mn.hpp rcsid.hpp # Add library C++ source files to this list CCSRC = basicio.cpp canonmn.cpp crwimage.cpp datasets.cpp error.cpp exif.cpp \ - futils.cpp fujimn.cpp ifd.cpp image.cpp imgreg.cpp iptc.cpp \ + futils.cpp fujimn.cpp fujimn2.cpp ifd.cpp image.cpp imgreg.cpp iptc.cpp \ jpgimage.cpp makernote.cpp makernote2.cpp metadatum.cpp mnreg.cpp \ nikonmn.cpp olympusmn.cpp olympusmn2.cpp panasonicmn.cpp sigmamn.cpp \ sonymn.cpp tags.cpp tiffcomposite.cpp tiffimage.cpp tiffparser.cpp \ diff --git a/src/fujimn2.cpp b/src/fujimn2.cpp new file mode 100644 index 00000000..043a5e56 --- /dev/null +++ b/src/fujimn2.cpp @@ -0,0 +1,133 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2006 Andreas Huggel + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: fujimn2.cpp + Version: $Rev$ + Author(s): Andreas Huggel (ahu) + History: 15-Apr-06, ahu: created + */ +// ***************************************************************************** +#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 makernote2.o +//#define DEBUG + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif + +#include "fujimn2.hpp" +#include "tiffcomposite.hpp" +#include "tiffparser.hpp" +#include "types.hpp" + +// + standard includes +#include +#include + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + const char* FujiMnHeader::signature_ = "FUJIFILM\12\0\0\0"; + const uint32_t FujiMnHeader::size_ = 12; + const ByteOrder FujiMnHeader::byteOrder_ = littleEndian; + + FujiMnHeader::FujiMnHeader() + { + read(reinterpret_cast(signature_), size_, byteOrder_); + } + + bool FujiMnHeader::read(const byte* pData, + uint32_t size, + ByteOrder /*byteOrder*/) + { + assert (pData != 0); + + if (size < size_) return false; + + header_.alloc(size_); + memcpy(header_.pData_, pData, header_.size_); + + // Read offset to the IFD relative to the start of the makernote + // from the header. Note that we ignore the byteOrder argument + start_ = getUShort(header_.pData_ + 8, byteOrder_); + + return true; + } // FujiMnHeader::read + + bool FujiMnHeader::check() const + { + if ( static_cast(header_.size_) < size_ + || 0 != memcmp(header_.pData_, signature_, 8)) { + return false; + } + return true; + } // FujiMnHeader::check + + bool TiffFujiMn::doReadHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder) + { + return header_.read(pData, size, byteOrder); + } + + bool TiffFujiMn::doCheckHeader() const + { + return header_.check(); + } + + uint32_t TiffFujiMn::doIfdOffset() const + { + return header_.ifdOffset(); + } + + TiffRwState::AutoPtr TiffFujiMn::doGetState(uint32_t mnOffset) const + { + // Byteorder: from the header (little endian) + // Offsets : relative to the start of the makernote + // Creator : standard TIFF component factory + return TiffRwState::AutoPtr( + new TiffRwState(header_.byteOrder(), + mnOffset, + TiffCreator::create)); + } + + // ************************************************************************* + // free functions + + TiffComponent* newFujiMn(uint16_t tag, + uint16_t group, + uint16_t mnGroup, + const byte* /*pData*/, + uint32_t /*size*/, + ByteOrder /*byteOrder*/) + { + return new TiffFujiMn(tag, group, mnGroup); + } + +} // namespace Exiv2 diff --git a/src/fujimn2.hpp b/src/fujimn2.hpp new file mode 100644 index 00000000..39dd3c90 --- /dev/null +++ b/src/fujimn2.hpp @@ -0,0 +1,133 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2006 Andreas Huggel + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file fujimn2.hpp + @brief TIFF Fujifilm makernote + @version $Rev$ + @author Andreas Huggel (ahu) + ahuggel@gmx.net + @date 15-Apr-06, ahu: created + */ +#ifndef FUJIMN2_HPP_ +#define FUJIMN2_HPP_ + +// ***************************************************************************** +// included header files +#include "makernote2.hpp" +#include "tiffcomposite.hpp" +#include "types.hpp" + +// + standard includes + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + namespace Group { + const uint16_t fujimn = 258; //!< Fujifilm makernote + } + + //! Header of a Fujifilm Makernote + class FujiMnHeader : public MnHeader { + public: + //! @name Creators + //@{ + //! Default constructor + FujiMnHeader(); + //! Virtual destructor. + virtual ~FujiMnHeader() {} + //@} + //! @name Manipulators + //@{ + virtual bool read(const byte* pData, + uint32_t size, + ByteOrder byteOrder); + //@} + //! @name Accessors + //@{ + virtual uint32_t size() const { return header_.size_; } + virtual uint32_t ifdOffset() const { return start_; } + virtual bool check() const; + //! Return the byte order for the header + ByteOrder byteOrder() const { return byteOrder_; } + //@} + + private: + DataBuf header_; //!< Data buffer for the makernote header + static const char* signature_; //!< Fujifilm makernote header signature + static const uint32_t size_; //!< Size of the signature + static const ByteOrder byteOrder_; //!< Byteorder for makernote (II) + uint32_t start_; //!< Start of the mn IFD rel. to mn start + + }; // class FujiMnHeader + + /*! + @brief Fujifilm Makernote + */ + class TiffFujiMn : public TiffIfdMakernote { + public: + //! @name Creators + //@{ + //! Default constructor + TiffFujiMn(uint16_t tag, uint16_t group, uint16_t mnGroup) + : TiffIfdMakernote(tag, group, mnGroup) {} + //! Virtual destructor + virtual ~TiffFujiMn() {} + //@} + + private: + //! @name Manipulators + //@{ + virtual bool doReadHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder); + //@} + + //! @name Accessors + //@{ + virtual bool doCheckHeader() const; + virtual uint32_t doIfdOffset() const; + virtual TiffRwState::AutoPtr doGetState(uint32_t mnOffset) const; + //@} + + private: + // DATA + FujiMnHeader header_; //!< Makernote header + + }; // TiffFujiMn + +// ***************************************************************************** +// template, inline and free functions + + //! Function to create a Fujifilm makernote + TiffComponent* newFujiMn(uint16_t tag, + uint16_t group, + uint16_t mnGroup, + const byte* pData, + uint32_t size, + ByteOrder byteOrder); + +} // namespace Exiv2 + +#endif // #ifndef FUJIMN2_HPP_ diff --git a/src/makernote2.cpp b/src/makernote2.cpp index 10fc4cee..a7c063b8 100644 --- a/src/makernote2.cpp +++ b/src/makernote2.cpp @@ -57,9 +57,11 @@ namespace Exiv2 { return make == key.make_.substr(0, make.length()); } - bool TiffIfdMakernote::readHeader(const byte* pData, uint32_t size) + bool TiffIfdMakernote::readHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder) { - return doReadHeader(pData, size); + return doReadHeader(pData, size, byteOrder); } bool TiffIfdMakernote::checkHeader() const @@ -72,6 +74,16 @@ namespace Exiv2 { return doIfdOffset(); } + TiffRwState::AutoPtr TiffIfdMakernote::getState(uint32_t mnOffset) const + { + return doGetState(mnOffset); + } + + TiffRwState::AutoPtr TiffIfdMakernote::doGetState(uint32_t mnOffset) const + { + return TiffRwState::AutoPtr(0); + } + void TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent) { ifd_.addChild(tiffComponent); @@ -86,6 +98,7 @@ namespace Exiv2 { { visitor.visitIfdMakernote(this); ifd_.accept(visitor); + visitor.visitIfdMakernoteEnd(this); } } // namespace Exiv2 diff --git a/src/makernote2.hpp b/src/makernote2.hpp index ab9123b8..bb8de2f1 100644 --- a/src/makernote2.hpp +++ b/src/makernote2.hpp @@ -20,7 +20,7 @@ */ /*! @file makernote2.hpp - @brief + @brief Makernote base classes, factory and registry @version $Rev$ @author Andreas Huggel (ahu) ahuggel@gmx.net @@ -32,6 +32,7 @@ // ***************************************************************************** // included header files #include "tiffcomposite.hpp" +#include "tiffvisitor.hpp" #include "types.hpp" // + standard includes @@ -41,11 +42,6 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - - template class TiffReader; - // ***************************************************************************** // class definitions @@ -122,7 +118,8 @@ namespace Exiv2 { //@{ //! Read the header from a data buffer, return true if successful virtual bool read(const byte* pData, - uint32_t size) =0; + uint32_t size, + ByteOrder byteOrder) =0; //@} //! @name Accessors //@{ @@ -145,7 +142,6 @@ namespace Exiv2 { the IFD entries. */ class TiffIfdMakernote : public TiffComponent { - template friend class TiffReader; public: //! @name Creators @@ -160,7 +156,7 @@ namespace Exiv2 { //! @name Manipulators //@{ //! Read the header from a data buffer, return true if successful - bool readHeader(const byte* pData, uint32_t size); + bool readHeader(const byte* pData, uint32_t size, ByteOrder byteOrder); //@} //! @name Accessors @@ -172,6 +168,18 @@ namespace Exiv2 { the start of the Makernote. */ uint32_t ifdOffset() const; + /*! + @brief Get status information relevant for the makernote. + + State includes byte order, offset and TIFF component factory. + This method allows the TiffReader to change state, i.e., change + these parameters, to parse the Makernote and its sub components + (if any). + + @param mnOffset Offset to the makernote from the start of the + TIFF header. + */ + TiffRwState::AutoPtr getState(uint32_t mnOffset) const; //@} protected: @@ -181,7 +189,9 @@ namespace Exiv2 { virtual void doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); //! Implements readHeader(); - virtual bool doReadHeader(const byte* pData, uint32_t size) =0; + virtual bool doReadHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder) =0; //@} //! @name Accessors @@ -190,6 +200,8 @@ namespace Exiv2 { virtual bool doCheckHeader() const =0; //! Implements ifdOffset() virtual uint32_t doIfdOffset() const =0; + //! Implements getState(). The default implementation returns a 0-pointer. + virtual TiffRwState::AutoPtr doGetState(uint32_t mnOffset) const; //@} private: diff --git a/src/mnreg.cpp b/src/mnreg.cpp index 6d19d094..0e1bdb33 100644 --- a/src/mnreg.cpp +++ b/src/mnreg.cpp @@ -33,6 +33,7 @@ EXIV2_RCSID("@(#) $Id$"); // included header files #include "makernote2.hpp" #include "olympusmn2.hpp" +#include "fujimn2.hpp" // + standard includes @@ -41,11 +42,12 @@ EXIV2_RCSID("@(#) $Id$"); namespace Exiv2 { const TiffMnRegistry TiffMnCreator::registry_[] = { - { "OLYMPUS", newOlympusMn, Group::olympmn } + { "OLYMPUS", newOlympusMn, Group::olympmn }, + { "FUJIFILM", newFujiMn, Group::fujimn } }; - // The find template needs to be in the same compilation unit as the array + // The find template needs to see the array from where it is called TiffComponent* TiffMnCreator::create(uint16_t tag, uint16_t group, std::string make, @@ -64,5 +66,4 @@ namespace Exiv2 { return tc; } // TiffMnCreator::create - } // namespace Exiv2 diff --git a/src/olympusmn2.cpp b/src/olympusmn2.cpp index 11165278..92a327c7 100644 --- a/src/olympusmn2.cpp +++ b/src/olympusmn2.cpp @@ -22,7 +22,7 @@ File: olympusmn2.cpp Version: $Rev$ Author(s): Andreas Huggel (ahu) - History: 11-Apr-06, ahu: created + History: 15-Apr-06, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" @@ -57,10 +57,12 @@ namespace Exiv2 { OlympusMnHeader::OlympusMnHeader() { - read(reinterpret_cast(signature_), size_); + read(reinterpret_cast(signature_), size_, invalidByteOrder); } - bool OlympusMnHeader::read(const byte* pData, uint32_t size) + bool OlympusMnHeader::read(const byte* pData, + uint32_t size, + ByteOrder /*byteOrder*/) { assert (pData != 0); @@ -80,9 +82,11 @@ namespace Exiv2 { return true; } // OlympusMnHeader::check - bool TiffOlympusMn::doReadHeader(const byte* pData, uint32_t size) + bool TiffOlympusMn::doReadHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder) { - return header_.read(pData, size); + return header_.read(pData, size, byteOrder); } bool TiffOlympusMn::doCheckHeader() const diff --git a/src/olympusmn2.hpp b/src/olympusmn2.hpp index 128df9a3..b37f0cb5 100644 --- a/src/olympusmn2.hpp +++ b/src/olympusmn2.hpp @@ -61,7 +61,8 @@ namespace Exiv2 { //! @name Manipulators //@{ virtual bool read(const byte* pData, - uint32_t size); + uint32_t size, + ByteOrder byteOrder); //@} //! @name Accessors //@{ @@ -94,7 +95,9 @@ namespace Exiv2 { private: //! @name Manipulators //@{ - virtual bool doReadHeader(const byte* pData, uint32_t size); + virtual bool doReadHeader(const byte* pData, + uint32_t size, + ByteOrder byteOrder); //@} //! @name Accessors diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp index e63e1f8e..2827823d 100644 --- a/src/tiffcomposite.cpp +++ b/src/tiffcomposite.cpp @@ -125,6 +125,7 @@ namespace Exiv2 { case 4: group = "GPSInfo"; break; case 5: group = "Iop"; break; case 257: group = "Olympus"; break; + case 258: group = "Fujifilm"; break; default: group = "Unknown"; break; } return group; diff --git a/src/tiffcomposite.hpp b/src/tiffcomposite.hpp index 5d2a33a5..32bd3af9 100644 --- a/src/tiffcomposite.hpp +++ b/src/tiffcomposite.hpp @@ -48,7 +48,7 @@ namespace Exiv2 { class Value; class TiffVisitor; - template class TiffReader; + class TiffReader; class TiffMetadataDecoder; class TiffPrinter; class TiffIfdMakernote; @@ -224,6 +224,12 @@ namespace Exiv2 { }; // class TiffComponent + /*! + Type for a factory function to create new TIFF components. + */ + typedef TiffComponent::AutoPtr (*TiffCompFactoryFct)(uint32_t extendedTag, + uint16_t group); + /*! @brief This abstract base class provides the common functionality of an IFD directory entry and defines an extended interface for derived @@ -231,7 +237,6 @@ namespace Exiv2 { entry. */ class TiffEntryBase : public TiffComponent { - template friend class TiffReader; public: //! @name Creators @@ -247,11 +252,14 @@ namespace Exiv2 { //! @name Accessors //@{ - //! Return the Exiv2 type which corresponds to the field type. + //! Return the Exiv2 type which corresponds to the field type TypeId typeId() const { return TypeId(type_); } - //! Return the number of components in this entry. + //! Return the number of components in this entry uint32_t count() const { return count_; } - //! Return the offset relative to the start of the TIFF header. + /*! + Return the offset to the data area relative to the base for + the component (usually the start of the TIFF header) + */ uint32_t offset() const { return offset_; } //! Return the size of this component in bytes uint32_t size() const { return size_; } @@ -265,7 +273,7 @@ namespace Exiv2 { // DATA uint16_t type_; //!< Field Type uint32_t count_; //!< The number of values of the indicated Type - uint32_t offset_; //!< Offset to data area from start of TIFF header + uint32_t offset_; //!< Offset to the data area /*! Size of the data buffer holding the value in bytes, there is no minimum size. @@ -337,7 +345,6 @@ namespace Exiv2 { GPS tags. */ class TiffSubIfd : public TiffEntryBase { - template friend class TiffReader; public: //! @name Creators @@ -365,14 +372,12 @@ namespace Exiv2 { /*! @brief This class is the basis for Makernote support in TIFF. It contains - a pointer to a concrete Makernote. The TiffReader - visitor has the responsibility to create the correct Make/Model - specific Makernote for a particular TIFF file. Calls to child - management methods are forwarded to the concrete Makernote, if - there is one. + a pointer to a concrete Makernote. The TiffReader visitor has the + responsibility to create the correct Make/Model specific Makernote + for a particular TIFF file. Calls to child management methods are + forwarded to the concrete Makernote, if there is one. */ class TiffMnEntry : public TiffEntryBase { - template friend class TiffReader; friend class TiffMetadataDecoder; friend class TiffPrinter; diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index 68e5a0e9..4209ea68 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -135,7 +135,7 @@ namespace Exiv2 { io_->read(buf.pData_, len); if (io_->error() || io_->eof()) throw Error(14); - TiffParser::decode(this, buf.pData_, buf.size_); + TiffParser::decode(this, buf.pData_, buf.size_, TiffCreator::create); } // TiffImage::readMetadata void TiffImage::writeMetadata() diff --git a/src/tiffparse.cpp b/src/tiffparse.cpp index 545bc73e..d6db126b 100644 --- a/src/tiffparse.cpp +++ b/src/tiffparse.cpp @@ -39,16 +39,22 @@ try { TiffHeade2 tiffHeader; if (!tiffHeader.read(buf.pData_, buf.size_)) throw Error(3, "TIFF"); - TiffComponent::AutoPtr rootDir = TiffCreator::create(Tag::root, Group::none); + TiffCompFactoryFct createFct = TiffCreator::create; + + TiffComponent::AutoPtr rootDir = createFct(Tag::root, Group::none); if (0 == rootDir.get()) { throw Error(1, "No root element defined in TIFF structure"); } - rootDir->setStart(buf.pData_ + tiffHeader.offset()); - TiffReader reader(buf.pData_, - buf.size_, - tiffHeader.byteOrder(), - rootDir.get()); + + TiffRwState::AutoPtr state( + new TiffRwState(tiffHeader.byteOrder(), 0, createFct)); + + TiffReader reader(buf.pData_, + buf.size_, + rootDir.get(), + state); + rootDir->accept(reader); tiffHeader.print(std::cerr); diff --git a/src/tiffparser.cpp b/src/tiffparser.cpp index b85c9776..e47339c8 100644 --- a/src/tiffparser.cpp +++ b/src/tiffparser.cpp @@ -54,20 +54,11 @@ EXIV2_RCSID("@(#) $Id$"); + Add further child mgmt stuff to TIFF composite: remove + Review boundary checking, is it better to check the offsets? + Define and implement consistent error handling for recursive hierarchy - + Add Makernote support + Make TiffImage a template StandardImage, which can be parametrized with a parser and the necessary checking functions to cover all types of images which need to be loaded completely. - + Decide what tag and group should be assigned to TiffMnEntry and - concrete Makernotes and which of them should derive from base-entry - - TiffMnEntry tag 0x927c, group exif, derives from tiffentry: because - create needs the entry - - ConcreteMn tag 0, group Mn, derives from component so that the plain entry - is only kept in one place, - if it contains an Ifd, that has a different group (create fct knows which) - + Implementation of concrete makernotes: Base class TiffIfdMakernote? - Why is the hierarchy MnHeader needed? - + TiffComponent: should it have end() and setEnd() or pData and size?? + + TiffComponent: should it have end() and setEnd() or pData and size? + + Can NewTiffCompFct and TiffCompFactoryFct be combined? in crwimage.* : @@ -124,6 +115,32 @@ namespace Exiv2 { return tc; } // TiffCreator::create + void TiffParser::decode(Image* pImage, + const byte* pData, + uint32_t size, + TiffCompFactoryFct createFct) + { + assert(pImage != 0); + assert(pData != 0); + + TiffHeade2 tiffHeader; + if (!tiffHeader.read(pData, size) || tiffHeader.offset() >= size) { + throw Error(3, "TIFF"); + } + TiffComponent::AutoPtr rootDir = createFct(Tag::root, Group::none); + if (0 == rootDir.get()) return; + rootDir->setStart(pData + tiffHeader.offset()); + + TiffRwState::AutoPtr state( + new TiffRwState(tiffHeader.byteOrder(), 0, createFct)); + TiffReader reader(pData, size, rootDir.get(), state); + rootDir->accept(reader); + + TiffMetadataDecoder decoder(pImage); + rootDir->accept(decoder); + + } // TiffParser::decode + // ************************************************************************* // free functions diff --git a/src/tiffparser.hpp b/src/tiffparser.hpp index 7545c0a3..75675d9f 100644 --- a/src/tiffparser.hpp +++ b/src/tiffparser.hpp @@ -33,7 +33,6 @@ // included header files #include "tiffcomposite.hpp" #include "tiffvisitor.hpp" -#include "tiffvisitor_tmpl.hpp" #include "error.hpp" #include "types.hpp" @@ -55,9 +54,7 @@ namespace Exiv2 { // class definitions /*! - Type for a function pointer for functions to create TIFF components. - Todo: This may eventually need to also have access to the image or parse tree - in order to make decisions based on the value of other tags. + Type for a function pointer for a function to create a TIFF component. */ typedef TiffComponent::AutoPtr (*NewTiffCompFct)(const TiffStructure* ts); @@ -90,8 +87,7 @@ namespace Exiv2 { }; /*! - @brief TIFF component factory for standard TIFF components. This class is - used as a policy class. + @brief TIFF component factory for standard TIFF components. */ class TiffCreator { public: @@ -105,9 +101,7 @@ namespace Exiv2 { */ static TiffComponent::AutoPtr create(uint32_t extendedTag, uint16_t group); - protected: - //! Prevent destruction - ~TiffCreator() {} + private: static const TiffStructure tiffStructure_[]; // - class TiffParser : public CreationPolicy { + class TiffParser { public: /*! @brief Decode TIFF metadata from a data buffer \em pData of length @@ -128,14 +121,16 @@ namespace Exiv2 { parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor hierarchies. - @param pImage Pointer to the image to hold the metadata - @param pData Pointer to the data buffer. Must point to data - in TIFF format; no checks are performed. - @param size Length of the data buffer. + @param pImage Pointer to the image to hold the metadata + @param pData Pointer to the data buffer. Must point to data + in TIFF format; no checks are performed. + @param size Length of the data buffer. + @param createFct Factory function to create new TIFF components. */ - static void decode( Image* pImage, - const byte* pData, - uint32_t size); + static void decode( Image* pImage, + const byte* pData, + uint32_t size, + TiffCompFactoryFct createFct); }; // class TiffParser // ***************************************************************************** @@ -150,34 +145,6 @@ namespace Exiv2 { //! Function to create and initialize a new TIFF makernote entry TiffComponent::AutoPtr newTiffMnEntry(const TiffStructure* ts); - template - void TiffParser::decode(Image* pImage, - const byte* pData, - uint32_t size) - { - assert(pImage != 0); - assert(pData != 0); - - TiffHeade2 tiffHeader; - if (!tiffHeader.read(pData, size) || tiffHeader.offset() >= size) { - throw Error(3, "TIFF"); - } - TiffComponent::AutoPtr rootDir = CreationPolicy::create(Tag::root, - Group::none); - if (0 == rootDir.get()) return; - rootDir->setStart(pData + tiffHeader.offset()); - - TiffReader reader(pData, - size, - tiffHeader.byteOrder(), - rootDir.get()); - rootDir->accept(reader); - - TiffMetadataDecoder decoder(pImage); - rootDir->accept(decoder); - - } // TiffParser::decode - } // namespace Exiv2 #endif // #ifndef TIFFPARSER_HPP_ diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp index 6ceaeedc..be4ea9a7 100644 --- a/src/tiffvisitor.cpp +++ b/src/tiffvisitor.cpp @@ -44,10 +44,14 @@ EXIV2_RCSID("@(#) $Id$"); #include "tiffcomposite.hpp" #include "makernote2.hpp" #include "exif.hpp" +#include "value.hpp" #include "image.hpp" // + standard includes #include +#include +#include +#include // ***************************************************************************** // class member definitions @@ -211,7 +215,273 @@ namespace Exiv2 { } // TiffPrinter::printTiffEntry - // ************************************************************************* - // free functions + TiffReader::TiffReader(const byte* pData, + uint32_t size, + TiffComponent* pRoot, + TiffRwState::AutoPtr state) + : pData_(pData), + size_(size), + pLast_(pData + size - 1), + pRoot_(pRoot), + pState_(state.release()), + pOrigState_(pState_) + { + assert(pData_); + assert(size_ > 0); + + } // TiffReader::TiffReader + + TiffReader::~TiffReader() + { + if (pOrigState_ != pState_) delete pOrigState_; + delete pState_; + } + + void TiffReader::resetState() { + if (pOrigState_ != pState_) delete pState_; + pState_ = pOrigState_; + } + + void TiffReader::changeState(TiffRwState::AutoPtr state) + { + if (state.get() != 0) { + if (pOrigState_ != pState_) delete pState_; + pState_ = state.release(); + } + } + + ByteOrder TiffReader::byteOrder() const + { + assert(pState_); + return pState_->byteOrder_; + } + + uint32_t TiffReader::baseOffset() const + { + assert(pState_); + return pState_->baseOffset_; + } + + TiffComponent::AutoPtr TiffReader::create(uint32_t extendedTag, + uint16_t group) const + { + assert(pState_); + assert(pState_->createFct_); + return pState_->createFct_(extendedTag, group); + } + + void TiffReader::visitEntry(TiffEntry* object) + { + readTiffEntry(object); + } + + void TiffReader::visitDirectory(TiffDirectory* object) + { + assert(object != 0); + + const byte* p = object->start(); + assert(p >= pData_); + + if (p + 2 > pLast_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: " + << "Directory " << object->groupName() << ": " + << " IFD exceeds data buffer, cannot read entry count.\n"; +#endif + return; + } + const uint16_t n = getUShort(p, byteOrder()); + p += 2; + for (uint16_t i = 0; i < n; ++i) { + if (p + 12 > pLast_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: " + << "Directory " << object->groupName() << ": " + << " IFD entry " << i + << " lies outside of the data buffer.\n"; +#endif + return; + } + uint16_t tag = getUShort(p, byteOrder()); + TiffComponent::AutoPtr tc = create(tag, object->group()); + tc->setStart(p); + object->addChild(tc); + p += 12; + } + + if (p + 4 > pLast_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: " + << "Directory " << object->groupName() << ": " + << " IFD exceeds data buffer, cannot read next pointer.\n"; +#endif + return; + } + uint32_t next = getLong(p, byteOrder()); + if (next) { + TiffComponent::AutoPtr tc = create(Tag::next, object->group()); + 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); + } + + } // TiffReader::visitDirectory + + void TiffReader::visitSubIfd(TiffSubIfd* object) + { + assert(object != 0); + + readTiffEntry(object); + if (object->typeId() == unsignedLong && object->count() >= 1) { + uint32_t offset = getULong(object->pData(), byteOrder()); + if (baseOffset() + offset > size_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: " + << "Directory " << object->groupName() + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " Sub-IFD pointer is out of bounds; ignoring it.\n"; +#endif + return; + } + object->ifd_.setStart(pData_ + baseOffset() + offset); + } +#ifndef SUPPRESS_WARNINGS + else { + std::cerr << "Warning: " + << "Directory " << object->groupName() + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " doesn't look like a sub-IFD."; + } +#endif + + } // TiffReader::visitSubIfd + + void TiffReader::visitMnEntry(TiffMnEntry* object) + { + assert(object != 0); + + readTiffEntry(object); + // Find camera make + TiffFinder finder(0x010f, Group::ifd0); + pRoot_->accept(finder); + TiffEntryBase* te = dynamic_cast(finder.result()); + std::string make; + if (te && te->pValue()) { + make = te->pValue()->toString(); + // create concrete makernote, based on make and makernote contents + object->mn_ = TiffMnCreator::create(object->tag(), + object->mnGroup_, + make, + object->pData(), + object->size(), + byteOrder()); + } + if (object->mn_) object->mn_->setStart(object->pData()); + + } // TiffReader::visitMnEntry + + void TiffReader::visitIfdMakernote(TiffIfdMakernote* object) + { + assert(object != 0); + + object->readHeader(object->start(), pLast_ - object->start(), byteOrder()); + if (!object->checkHeader()) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: IFD Makernote header check failed.\n"; +#endif + return; // todo: signal error to parent, delete object + } + // Modify reader for Makernote peculiarities, byte order, offset, + // component factory + changeState(object->getState(object->start() - pData_)); + object->ifd_.setStart(object->start() + object->ifdOffset()); + + } // TiffReader::visitIfdMakernote + + void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* object) + { + // Reset state (byte order, create function, offset) back to that + // for the image + resetState(); + } // TiffReader::visitIfdMakernoteEnd + + void TiffReader::readTiffEntry(TiffEntryBase* object) + { + assert(object != 0); + + const byte* p = object->start(); + assert(p >= pData_); + + if (p + 12 > pLast_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: Entry in directory " << object->groupName() + << "requests access to memory beyond the data buffer. " + << "Skipping entry.\n"; +#endif + return; + } + // Component already has tag + p += 2; + object->type_ = getUShort(p, byteOrder()); + // todo: check type + p += 2; + object->count_ = getULong(p, byteOrder()); + p += 4; + object->size_ = TypeInfo::typeSize(object->typeId()) * object->count(); + object->offset_ = getULong(p, byteOrder()); + object->pData_ = p; + if (object->size() > 4) { + if (baseOffset() + object->offset() >= size_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: Offset of " + << "directory " << object->groupName() << ", " + << " entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " is out of bounds:\n" + << "Offset = 0x" << std::setw(8) + << std::setfill('0') << std::hex << object->offset() + << "; truncating the entry\n"; +#endif + object->size_ = 0; + object->count_ = 0; + object->offset_ = 0; + return; + } + object->pData_ = pData_ + baseOffset() + object->offset(); + if (object->pData() + object->size() > pLast_) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Upper boundary of data for " + << "directory " << object->groupName() << ", " + << " entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << object->tag() + << " is out of bounds:\n" + << "Offset = 0x" << std::setw(8) + << std::setfill('0') << std::hex << object->offset() + << ", size = " << std::dec << object->size() + << ", exceeds buffer size by " + // cast to make MSVC happy + << static_cast(object->pData() + object->size() - pLast_) + << " Bytes; adjusting the size\n"; +#endif + object->size_ = pLast_ - object->pData() + 1; + // todo: adjust count_, make size_ a multiple of typeSize + } + } + Value::AutoPtr v = Value::create(object->typeId()); + if (v.get()) { + v->read(object->pData(), object->size(), byteOrder()); + object->pValue_ = v.release(); + } + + } // TiffReader::readTiffEntry } // namespace Exiv2 diff --git a/src/tiffvisitor.hpp b/src/tiffvisitor.hpp index 30e7f3e9..342e5d37 100644 --- a/src/tiffvisitor.hpp +++ b/src/tiffvisitor.hpp @@ -32,8 +32,10 @@ // ***************************************************************************** // included header files #include "types.hpp" +#include "tiffcomposite.hpp" // + standard includes +#include #include #include #include @@ -45,12 +47,6 @@ namespace Exiv2 { // ***************************************************************************** // class declarations - class TiffComponent; - class TiffEntryBase; - class TiffEntry; - class TiffDirectory; - class TiffSubIfd; - class TiffMnEntry; class TiffIfdMakernote; class Image; @@ -91,13 +87,13 @@ namespace Exiv2 { //! Operation to perform for a TIFF directory virtual void visitDirectory(TiffDirectory* object) =0; /*! - Operation to perform for a TIFF directory, after all components and - before the next entry is processed. + @brief Operation to perform for a TIFF directory, after all components + and before the next entry is processed. */ virtual void visitDirectoryNext(TiffDirectory* object) {} /*! - Operation to perform for a TIFF directory, at the end of the - processing. + @brief Operation to perform for a TIFF directory, at the end of the + processing. */ virtual void visitDirectoryEnd(TiffDirectory* object) {} //! Operation to perform for a TIFF sub-IFD @@ -106,6 +102,8 @@ namespace Exiv2 { virtual void visitMnEntry(TiffMnEntry* object) =0; //! Operation to perform for an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object) =0; + //! Operation to perform after processing an IFD makernote + virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object) {} //@} //! @name Accessors @@ -209,14 +207,52 @@ namespace Exiv2 { }; // class TiffMetadataDecoder + /*! + @brief Simple state class containing relevant state information for + the TIFF reader. This is in a separate class so that the + reader can change state if needed (e.g., to read certain complex + makernotes). + */ + struct TiffRwState { + //! TiffRWState auto_ptr type + typedef std::auto_ptr AutoPtr; + //! Constructor. + explicit TiffRwState(ByteOrder byteOrder, + uint32_t baseOffset, + TiffCompFactoryFct createFct) + : byteOrder_(byteOrder), + baseOffset_(baseOffset), + createFct_(createFct) {} + /*! + Applicable byte order. May be different for the Makernote and the + rest of the TIFF entries. + */ + const ByteOrder byteOrder_; + /*! + Base offset. TIFF standard format uses byte offsets which are + always relative to the start of the TIFF file, i.e., relative to the + start of the TIFF image header. In this case, the base offset is 0. + However, some camera vendors encode their makernotes in TIFF IFDs + using offsets relative to (somewhere near) the start of the makernote + data. In this case, base offset added to the start of the TIFF image + header points to the basis for such makernote offsets. + */ + const uint32_t baseOffset_; + /*! + Factory function to create new TIFF components. Different create + functions may use different lookup tables, so that makernotes + can independently use their own factory function and lookup table, + which can be defined together with the makernote implementation. + */ + TiffCompFactoryFct createFct_; + }; // TiffRwState + /*! @brief TIFF composite visitor to read the TIFF structure from a block of memory and build the composite from it (Visitor pattern). Used by - TiffParser to read the TIFF data from a block of memory. Uses - the policy class CreationPolicy for the creation of TIFF components. + TiffParser to read the TIFF data from a block of memory. */ - template - class TiffReader : public TiffVisitor, public CreationPolicy { + class TiffReader : public TiffVisitor { public: //! @name Creators //@{ @@ -225,16 +261,17 @@ namespace Exiv2 { structure of the data are set in the constructor. @param pData Pointer to the data buffer, starting with a TIFF header. @param size Number of bytes in the data buffer. - @param byteOrder Applicable byte order (little or big endian). @param pRoot Root element of the TIFF composite. + @param state State object for creation function, byteorder and + base offset. */ - TiffReader(const byte* pData, - uint32_t size, - ByteOrder byteOrder, - TiffComponent* pRoot); + TiffReader(const byte* pData, + uint32_t size, + TiffComponent* pRoot, + TiffRwState::AutoPtr state); //! Virtual destructor - virtual ~TiffReader() {} + virtual ~TiffReader(); //@} //! @name Manipulators @@ -249,18 +286,35 @@ namespace Exiv2 { virtual void visitMnEntry(TiffMnEntry* object); //! Read an IFD makernote from the data buffer virtual void visitIfdMakernote(TiffIfdMakernote* object); + //! Reset reader to its original state, undo makernote specific settings + virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Read a standard TIFF entry from the data buffer void readTiffEntry(TiffEntryBase* object); + //! Set the \em state class. Assumes ownership of the object passed in. + void changeState(TiffRwState::AutoPtr state); + //! Reset the state to the original state as set in the constructor. + void resetState(); + //@} + + //! @name Accessors + //@{ + //! Return the byte order. + ByteOrder byteOrder() const; + //! Return the base offset. See class TiffRwState for details + uint32_t baseOffset() const; + //! Create a TIFF component for \em extendedTag and group + TiffComponent::AutoPtr create(uint32_t extendedTag, uint16_t group) const; //@} private: // DATA - const byte* pData_; //!< Pointer to the memory buffer - const uint32_t size_; //!< Size of the buffer - const byte* pLast_; //!< Pointer to the last byte - const ByteOrder byteOrder_; //!< Byteorder for the image - TiffComponent* const pRoot_; //!< Root element of the composite + const byte* pData_; //!< Pointer to the memory buffer + const uint32_t size_; //!< Size of the buffer + const byte* pLast_; //!< Pointer to the last byte + TiffComponent* const pRoot_; //!< Root element of the composite + TiffRwState* pState_; //!< State class + TiffRwState* pOrigState_; //!< State class as set in the c'tor }; // class TiffReader @@ -319,9 +373,6 @@ namespace Exiv2 { static const std::string indent_; //!< Indent for one level }; // class TiffPrinter -// ***************************************************************************** -// template, inline and free functions - } // namespace Exiv2 #endif // #ifndef TIFFVISITOR_HPP_ diff --git a/src/tiffvisitor_tmpl.hpp b/src/tiffvisitor_tmpl.hpp deleted file mode 100644 index 38550534..00000000 --- a/src/tiffvisitor_tmpl.hpp +++ /dev/null @@ -1,277 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2006 Andreas Huggel - * - * This program is part of the Exiv2 distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -/*! - @file tiffvisitor_tmpl.hpp - @brief - @version $Rev$ - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 11-Apr-06, ahu: created - */ -#ifndef TIFFVISITOR_TMPL_HPP_ -#define TIFFVISITOR_TMPL_HPP_ - -// ***************************************************************************** -// included header files -#include "tiffvisitor.hpp" -#include "tiffcomposite.hpp" -#include "makernote2.hpp" -#include "value.hpp" -#include "types.hpp" - -// + standard includes -#include -#include -#include - -// ***************************************************************************** -// namespace extensions -namespace Exiv2 { - -// ***************************************************************************** -// template, inline and free functions - - template - TiffReader::TiffReader(const byte* pData, - uint32_t size, - ByteOrder byteOrder, - TiffComponent* pRoot) - : pData_(pData), - size_(size), - pLast_(pData + size - 1), - byteOrder_(byteOrder), - pRoot_(pRoot) - { - assert(pData); - assert(size > 0); - } // TiffReader::TiffReader - - template - void TiffReader::visitEntry(TiffEntry* object) - { - readTiffEntry(object); - } - - template - void TiffReader::visitDirectory(TiffDirectory* object) - { - assert(object != 0); - - const byte* p = object->start(); - assert(p >= pData_); - - if (p + 2 > pLast_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() << ": " - << " IFD exceeds data buffer, cannot read entry count.\n"; -#endif - return; - } - const uint16_t n = getUShort(p, byteOrder_); - p += 2; - for (uint16_t i = 0; i < n; ++i) { - if (p + 12 > pLast_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() << ": " - << " IFD entry " << i - << " lies outside of the data buffer.\n"; -#endif - return; - } - uint16_t tag = getUShort(p, byteOrder_); - TiffComponent::AutoPtr tc = CreationPolicy::create(tag, object->group()); - tc->setStart(p); - object->addChild(tc); - p += 12; - } - - if (p + 4 > pLast_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() << ": " - << " IFD exceeds data buffer, cannot read next pointer.\n"; -#endif - return; - } - uint32_t next = getLong(p, byteOrder_); - if (next) { - TiffComponent::AutoPtr tc = CreationPolicy::create(Tag::next, object->group()); - if (next > size_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() << ": " - << " Next pointer is out of bounds.\n"; -#endif - return; - } - tc->setStart(pData_ + next); - object->addNext(tc); - } - - } // TiffReader::visitDirectory - - template - void TiffReader::visitSubIfd(TiffSubIfd* object) - { - assert(object != 0); - - readTiffEntry(object); - if (object->typeId() == unsignedLong && object->count() >= 1) { - uint32_t offset = getULong(object->pData(), byteOrder_); - if (offset > size_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << object->groupName() - << ", entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << object->tag() - << " Sub-IFD pointer is out of bounds; ignoring it.\n"; -#endif - return; - } - object->ifd_.setStart(pData_ + offset); - } -#ifndef SUPPRESS_WARNINGS - else { - std::cerr << "Warning: " - << "Directory " << object->groupName() - << ", entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << object->tag() - << " doesn't look like a sub-IFD."; - } -#endif - - } // TiffReader::visitSubIfd - - template - void TiffReader::visitMnEntry(TiffMnEntry* object) - { - assert(object != 0); - - readTiffEntry(object); - // Find the camera model - TiffFinder finder(0x010f, Group::ifd0); - pRoot_->accept(finder); - TiffEntryBase* te = dynamic_cast(finder.result()); - std::string make; - if (te && te->pValue()) { - make = te->pValue()->toString(); - // create concrete makernote, based on model and makernote contents - object->mn_ = TiffMnCreator::create(object->tag(), - object->mnGroup_, - make, - object->pData(), - object->size(), - byteOrder_); - } - if (object->mn_) object->mn_->setStart(object->pData()); - - } // TiffReader::visitMnEntry - - template - void TiffReader::visitIfdMakernote(TiffIfdMakernote* object) - { - object->readHeader(object->start(), pLast_ - object->start()); - if (!object->checkHeader()) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: IFD Makernote header check failed.\n"; -#endif - return; // todo: signal error to parent, delete object - } - object->ifd_.setStart(object->start() + object->ifdOffset()); - - } // TiffReader::visitIfdMakernote - - template - void TiffReader::readTiffEntry(TiffEntryBase* object) - { - assert(object != 0); - - byte* p = const_cast(object->start()); - assert(p >= pData_); - - if (p + 12 > pLast_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Entry in directory " << object->groupName() - << "requests access to memory beyond the data buffer. " - << "Skipping entry.\n"; -#endif - return; - } - // Component already has tag - p += 2; - object->type_ = getUShort(p, byteOrder_); - // todo: check type - p += 2; - object->count_ = getULong(p, byteOrder_); - p += 4; - object->size_ = TypeInfo::typeSize(object->typeId()) * object->count(); - object->offset_ = getULong(p, byteOrder_); - object->pData_ = p; - if (object->size() > 4) { - if (object->offset() >= size_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Offset of " - << "directory " << object->groupName() << ", " - << " entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << object->tag() - << " is out of bounds:\n" - << "Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex << object->offset() - << "; truncating the entry\n"; -#endif - object->size_ = 0; - object->count_ = 0; - object->offset_ = 0; - return; - } - object->pData_ = pData_ + object->offset(); - if (object->pData() + object->size() > pLast_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Upper boundary of data for " - << "directory " << object->groupName() << ", " - << " entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << object->tag() - << " is out of bounds:\n" - << "Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex << object->offset() - << ", size = " << std::dec << object->size() - << ", exceeds buffer size by " - // cast to make MSVC happy - << static_cast(object->pData() + object->size() - pLast_) - << " Bytes; adjusting the size\n"; -#endif - object->size_ = size_ - object->offset(); - // todo: adjust count_, make size_ a multiple of typeSize - } - } - Value::AutoPtr v = Value::create(object->typeId()); - if (v.get()) { - v->read(object->pData(), object->size(), byteOrder_); - object->pValue_ = v.release(); - } - - } // TiffReader::readTiffEntry - -} // namespace Exiv2 - -#endif // #ifndef TIFFVISITOR_TMPL_HPP_