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.

v0.27.3
Andreas Huggel 19 years ago
parent e1eedc0f26
commit bab89c1ba3

@ -47,11 +47,11 @@ include $(top_srcdir)/config/config.mk
# Source files # Source files
# Add standalone C++ header files to this list # 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 # Add library C++ source files to this list
CCSRC = basicio.cpp canonmn.cpp crwimage.cpp datasets.cpp error.cpp exif.cpp \ 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 \ jpgimage.cpp makernote.cpp makernote2.cpp metadatum.cpp mnreg.cpp \
nikonmn.cpp olympusmn.cpp olympusmn2.cpp panasonicmn.cpp sigmamn.cpp \ nikonmn.cpp olympusmn.cpp olympusmn2.cpp panasonicmn.cpp sigmamn.cpp \
sonymn.cpp tags.cpp tiffcomposite.cpp tiffimage.cpp tiffparser.cpp \ sonymn.cpp tags.cpp tiffcomposite.cpp tiffimage.cpp tiffparser.cpp \

@ -0,0 +1,133 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* 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) <ahuggel@gmx.net>
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 <cstring>
#include <cassert>
// *****************************************************************************
// 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<const byte*>(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<uint32_t>(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

@ -0,0 +1,133 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* 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)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@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_

@ -57,9 +57,11 @@ namespace Exiv2 {
return make == key.make_.substr(0, make.length()); 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 bool TiffIfdMakernote::checkHeader() const
@ -72,6 +74,16 @@ namespace Exiv2 {
return doIfdOffset(); 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) void TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent)
{ {
ifd_.addChild(tiffComponent); ifd_.addChild(tiffComponent);
@ -86,6 +98,7 @@ namespace Exiv2 {
{ {
visitor.visitIfdMakernote(this); visitor.visitIfdMakernote(this);
ifd_.accept(visitor); ifd_.accept(visitor);
visitor.visitIfdMakernoteEnd(this);
} }
} // namespace Exiv2 } // namespace Exiv2

@ -20,7 +20,7 @@
*/ */
/*! /*!
@file makernote2.hpp @file makernote2.hpp
@brief @brief Makernote base classes, factory and registry
@version $Rev$ @version $Rev$
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@ -32,6 +32,7 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "tiffcomposite.hpp" #include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes // + standard includes
@ -41,11 +42,6 @@
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {
// *****************************************************************************
// class declarations
template<typename CreationPolicy> class TiffReader;
// ***************************************************************************** // *****************************************************************************
// class definitions // class definitions
@ -122,7 +118,8 @@ namespace Exiv2 {
//@{ //@{
//! Read the header from a data buffer, return true if successful //! Read the header from a data buffer, return true if successful
virtual bool read(const byte* pData, virtual bool read(const byte* pData,
uint32_t size) =0; uint32_t size,
ByteOrder byteOrder) =0;
//@} //@}
//! @name Accessors //! @name Accessors
//@{ //@{
@ -145,7 +142,6 @@ namespace Exiv2 {
the IFD entries. the IFD entries.
*/ */
class TiffIfdMakernote : public TiffComponent { class TiffIfdMakernote : public TiffComponent {
template<typename CreationPolicy>
friend class TiffReader; friend class TiffReader;
public: public:
//! @name Creators //! @name Creators
@ -160,7 +156,7 @@ namespace Exiv2 {
//! @name Manipulators //! @name Manipulators
//@{ //@{
//! Read the header from a data buffer, return true if successful //! 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 //! @name Accessors
@ -172,6 +168,18 @@ namespace Exiv2 {
the start of the Makernote. the start of the Makernote.
*/ */
uint32_t ifdOffset() const; 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: protected:
@ -181,7 +189,9 @@ namespace Exiv2 {
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor); virtual void doAccept(TiffVisitor& visitor);
//! Implements readHeader(); //! 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 //! @name Accessors
@ -190,6 +200,8 @@ namespace Exiv2 {
virtual bool doCheckHeader() const =0; virtual bool doCheckHeader() const =0;
//! Implements ifdOffset() //! Implements ifdOffset()
virtual uint32_t doIfdOffset() const =0; virtual uint32_t doIfdOffset() const =0;
//! Implements getState(). The default implementation returns a 0-pointer.
virtual TiffRwState::AutoPtr doGetState(uint32_t mnOffset) const;
//@} //@}
private: private:

@ -33,6 +33,7 @@ EXIV2_RCSID("@(#) $Id$");
// included header files // included header files
#include "makernote2.hpp" #include "makernote2.hpp"
#include "olympusmn2.hpp" #include "olympusmn2.hpp"
#include "fujimn2.hpp"
// + standard includes // + standard includes
@ -41,11 +42,12 @@ EXIV2_RCSID("@(#) $Id$");
namespace Exiv2 { namespace Exiv2 {
const TiffMnRegistry TiffMnCreator::registry_[] = { 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, TiffComponent* TiffMnCreator::create(uint16_t tag,
uint16_t group, uint16_t group,
std::string make, std::string make,
@ -64,5 +66,4 @@ namespace Exiv2 {
return tc; return tc;
} // TiffMnCreator::create } // TiffMnCreator::create
} // namespace Exiv2 } // namespace Exiv2

@ -22,7 +22,7 @@
File: olympusmn2.cpp File: olympusmn2.cpp
Version: $Rev$ Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 11-Apr-06, ahu: created History: 15-Apr-06, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
@ -57,10 +57,12 @@ namespace Exiv2 {
OlympusMnHeader::OlympusMnHeader() OlympusMnHeader::OlympusMnHeader()
{ {
read(reinterpret_cast<const byte*>(signature_), size_); read(reinterpret_cast<const byte*>(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); assert (pData != 0);
@ -80,9 +82,11 @@ namespace Exiv2 {
return true; return true;
} // OlympusMnHeader::check } // 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 bool TiffOlympusMn::doCheckHeader() const

@ -61,7 +61,8 @@ namespace Exiv2 {
//! @name Manipulators //! @name Manipulators
//@{ //@{
virtual bool read(const byte* pData, virtual bool read(const byte* pData,
uint32_t size); uint32_t size,
ByteOrder byteOrder);
//@} //@}
//! @name Accessors //! @name Accessors
//@{ //@{
@ -94,7 +95,9 @@ namespace Exiv2 {
private: private:
//! @name Manipulators //! @name Manipulators
//@{ //@{
virtual bool doReadHeader(const byte* pData, uint32_t size); virtual bool doReadHeader(const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//@} //@}
//! @name Accessors //! @name Accessors

@ -125,6 +125,7 @@ namespace Exiv2 {
case 4: group = "GPSInfo"; break; case 4: group = "GPSInfo"; break;
case 5: group = "Iop"; break; case 5: group = "Iop"; break;
case 257: group = "Olympus"; break; case 257: group = "Olympus"; break;
case 258: group = "Fujifilm"; break;
default: group = "Unknown"; break; default: group = "Unknown"; break;
} }
return group; return group;

@ -48,7 +48,7 @@ namespace Exiv2 {
class Value; class Value;
class TiffVisitor; class TiffVisitor;
template<typename CreationPolicy> class TiffReader; class TiffReader;
class TiffMetadataDecoder; class TiffMetadataDecoder;
class TiffPrinter; class TiffPrinter;
class TiffIfdMakernote; class TiffIfdMakernote;
@ -224,6 +224,12 @@ namespace Exiv2 {
}; // class TiffComponent }; // 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 @brief This abstract base class provides the common functionality of an
IFD directory entry and defines an extended interface for derived IFD directory entry and defines an extended interface for derived
@ -231,7 +237,6 @@ namespace Exiv2 {
entry. entry.
*/ */
class TiffEntryBase : public TiffComponent { class TiffEntryBase : public TiffComponent {
template<typename CreationPolicy>
friend class TiffReader; friend class TiffReader;
public: public:
//! @name Creators //! @name Creators
@ -247,11 +252,14 @@ namespace Exiv2 {
//! @name Accessors //! @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_); } 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_; } 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_; } uint32_t offset() const { return offset_; }
//! Return the size of this component in bytes //! Return the size of this component in bytes
uint32_t size() const { return size_; } uint32_t size() const { return size_; }
@ -265,7 +273,7 @@ namespace Exiv2 {
// DATA // DATA
uint16_t type_; //!< Field Type uint16_t type_; //!< Field Type
uint32_t count_; //!< The number of values of the indicated 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 Size of the data buffer holding the value in bytes, there is no
minimum size. minimum size.
@ -337,7 +345,6 @@ namespace Exiv2 {
GPS tags. GPS tags.
*/ */
class TiffSubIfd : public TiffEntryBase { class TiffSubIfd : public TiffEntryBase {
template<typename CreationPolicy>
friend class TiffReader; friend class TiffReader;
public: public:
//! @name Creators //! @name Creators
@ -365,14 +372,12 @@ namespace Exiv2 {
/*! /*!
@brief This class is the basis for Makernote support in TIFF. It contains @brief This class is the basis for Makernote support in TIFF. It contains
a pointer to a concrete Makernote. The TiffReader<CreationPolicy> a pointer to a concrete Makernote. The TiffReader visitor has the
visitor has the responsibility to create the correct Make/Model responsibility to create the correct Make/Model specific Makernote
specific Makernote for a particular TIFF file. Calls to child for a particular TIFF file. Calls to child management methods are
management methods are forwarded to the concrete Makernote, if forwarded to the concrete Makernote, if there is one.
there is one.
*/ */
class TiffMnEntry : public TiffEntryBase { class TiffMnEntry : public TiffEntryBase {
template<typename CreationPolicy>
friend class TiffReader; friend class TiffReader;
friend class TiffMetadataDecoder; friend class TiffMetadataDecoder;
friend class TiffPrinter; friend class TiffPrinter;

@ -135,7 +135,7 @@ namespace Exiv2 {
io_->read(buf.pData_, len); io_->read(buf.pData_, len);
if (io_->error() || io_->eof()) throw Error(14); if (io_->error() || io_->eof()) throw Error(14);
TiffParser<TiffCreator>::decode(this, buf.pData_, buf.size_); TiffParser::decode(this, buf.pData_, buf.size_, TiffCreator::create);
} // TiffImage::readMetadata } // TiffImage::readMetadata
void TiffImage::writeMetadata() void TiffImage::writeMetadata()

@ -39,16 +39,22 @@ try {
TiffHeade2 tiffHeader; TiffHeade2 tiffHeader;
if (!tiffHeader.read(buf.pData_, buf.size_)) throw Error(3, "TIFF"); 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()) { if (0 == rootDir.get()) {
throw Error(1, "No root element defined in TIFF structure"); throw Error(1, "No root element defined in TIFF structure");
} }
rootDir->setStart(buf.pData_ + tiffHeader.offset()); rootDir->setStart(buf.pData_ + tiffHeader.offset());
TiffReader<TiffCreator> reader(buf.pData_,
buf.size_, TiffRwState::AutoPtr state(
tiffHeader.byteOrder(), new TiffRwState(tiffHeader.byteOrder(), 0, createFct));
rootDir.get());
TiffReader reader(buf.pData_,
buf.size_,
rootDir.get(),
state);
rootDir->accept(reader); rootDir->accept(reader);
tiffHeader.print(std::cerr); tiffHeader.print(std::cerr);

@ -54,20 +54,11 @@ EXIV2_RCSID("@(#) $Id$");
+ Add further child mgmt stuff to TIFF composite: remove + Add further child mgmt stuff to TIFF composite: remove
+ Review boundary checking, is it better to check the offsets? + Review boundary checking, is it better to check the offsets?
+ Define and implement consistent error handling for recursive hierarchy + Define and implement consistent error handling for recursive hierarchy
+ Add Makernote support
+ Make TiffImage a template StandardImage, which can be parametrized with + Make TiffImage a template StandardImage, which can be parametrized with
a parser and the necessary checking functions to cover all types of a parser and the necessary checking functions to cover all types of
images which need to be loaded completely. images which need to be loaded completely.
+ Decide what tag and group should be assigned to TiffMnEntry and + TiffComponent: should it have end() and setEnd() or pData and size?
concrete Makernotes and which of them should derive from base-entry + Can NewTiffCompFct and TiffCompFactoryFct be combined?
- 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??
in crwimage.* : in crwimage.* :
@ -124,6 +115,32 @@ namespace Exiv2 {
return tc; return tc;
} // TiffCreator::create } // 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 // free functions

@ -33,7 +33,6 @@
// included header files // included header files
#include "tiffcomposite.hpp" #include "tiffcomposite.hpp"
#include "tiffvisitor.hpp" #include "tiffvisitor.hpp"
#include "tiffvisitor_tmpl.hpp"
#include "error.hpp" #include "error.hpp"
#include "types.hpp" #include "types.hpp"
@ -55,9 +54,7 @@ namespace Exiv2 {
// class definitions // class definitions
/*! /*!
Type for a function pointer for functions to create TIFF components. Type for a function pointer for a function to create a TIFF component.
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.
*/ */
typedef TiffComponent::AutoPtr (*NewTiffCompFct)(const TiffStructure* ts); typedef TiffComponent::AutoPtr (*NewTiffCompFct)(const TiffStructure* ts);
@ -90,8 +87,7 @@ namespace Exiv2 {
}; };
/*! /*!
@brief TIFF component factory for standard TIFF components. This class is @brief TIFF component factory for standard TIFF components.
used as a policy class.
*/ */
class TiffCreator { class TiffCreator {
public: public:
@ -105,9 +101,7 @@ namespace Exiv2 {
*/ */
static TiffComponent::AutoPtr create(uint32_t extendedTag, static TiffComponent::AutoPtr create(uint32_t extendedTag,
uint16_t group); uint16_t group);
protected:
//! Prevent destruction
~TiffCreator() {}
private: private:
static const TiffStructure tiffStructure_[]; //<! TIFF structure static const TiffStructure tiffStructure_[]; //<! TIFF structure
}; // class TiffCreator }; // class TiffCreator
@ -117,8 +111,7 @@ namespace Exiv2 {
class to decode and encode TIFF-based data. Uses class class to decode and encode TIFF-based data. Uses class
CreationPolicy for the creation of TIFF components. CreationPolicy for the creation of TIFF components.
*/ */
template<typename CreationPolicy> class TiffParser {
class TiffParser : public CreationPolicy {
public: public:
/*! /*!
@brief Decode TIFF metadata from a data buffer \em pData of length @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 parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
hierarchies. hierarchies.
@param pImage Pointer to the image to hold the metadata @param pImage Pointer to the image to hold the metadata
@param pData Pointer to the data buffer. Must point to data @param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed. in TIFF format; no checks are performed.
@param size Length of the data buffer. @param size Length of the data buffer.
@param createFct Factory function to create new TIFF components.
*/ */
static void decode( Image* pImage, static void decode( Image* pImage,
const byte* pData, const byte* pData,
uint32_t size); uint32_t size,
TiffCompFactoryFct createFct);
}; // class TiffParser }; // class TiffParser
// ***************************************************************************** // *****************************************************************************
@ -150,34 +145,6 @@ namespace Exiv2 {
//! Function to create and initialize a new TIFF makernote entry //! Function to create and initialize a new TIFF makernote entry
TiffComponent::AutoPtr newTiffMnEntry(const TiffStructure* ts); TiffComponent::AutoPtr newTiffMnEntry(const TiffStructure* ts);
template<typename CreationPolicy>
void TiffParser<CreationPolicy>::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<CreationPolicy> reader(pData,
size,
tiffHeader.byteOrder(),
rootDir.get());
rootDir->accept(reader);
TiffMetadataDecoder decoder(pImage);
rootDir->accept(decoder);
} // TiffParser::decode
} // namespace Exiv2 } // namespace Exiv2
#endif // #ifndef TIFFPARSER_HPP_ #endif // #ifndef TIFFPARSER_HPP_

@ -44,10 +44,14 @@ EXIV2_RCSID("@(#) $Id$");
#include "tiffcomposite.hpp" #include "tiffcomposite.hpp"
#include "makernote2.hpp" #include "makernote2.hpp"
#include "exif.hpp" #include "exif.hpp"
#include "value.hpp"
#include "image.hpp" #include "image.hpp"
// + standard includes // + standard includes
#include <string> #include <string>
#include <iostream>
#include <iomanip>
#include <cassert>
// ***************************************************************************** // *****************************************************************************
// class member definitions // class member definitions
@ -211,7 +215,273 @@ namespace Exiv2 {
} // TiffPrinter::printTiffEntry } // TiffPrinter::printTiffEntry
// ************************************************************************* TiffReader::TiffReader(const byte* pData,
// free functions 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<TiffEntryBase*>(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<uint32_t>(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 } // namespace Exiv2

@ -32,8 +32,10 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "types.hpp" #include "types.hpp"
#include "tiffcomposite.hpp"
// + standard includes // + standard includes
#include <memory>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <cassert> #include <cassert>
@ -45,12 +47,6 @@ namespace Exiv2 {
// ***************************************************************************** // *****************************************************************************
// class declarations // class declarations
class TiffComponent;
class TiffEntryBase;
class TiffEntry;
class TiffDirectory;
class TiffSubIfd;
class TiffMnEntry;
class TiffIfdMakernote; class TiffIfdMakernote;
class Image; class Image;
@ -91,13 +87,13 @@ namespace Exiv2 {
//! Operation to perform for a TIFF directory //! Operation to perform for a TIFF directory
virtual void visitDirectory(TiffDirectory* object) =0; virtual void visitDirectory(TiffDirectory* object) =0;
/*! /*!
Operation to perform for a TIFF directory, after all components and @brief Operation to perform for a TIFF directory, after all components
before the next entry is processed. and before the next entry is processed.
*/ */
virtual void visitDirectoryNext(TiffDirectory* object) {} virtual void visitDirectoryNext(TiffDirectory* object) {}
/*! /*!
Operation to perform for a TIFF directory, at the end of the @brief Operation to perform for a TIFF directory, at the end of the
processing. processing.
*/ */
virtual void visitDirectoryEnd(TiffDirectory* object) {} virtual void visitDirectoryEnd(TiffDirectory* object) {}
//! Operation to perform for a TIFF sub-IFD //! Operation to perform for a TIFF sub-IFD
@ -106,6 +102,8 @@ namespace Exiv2 {
virtual void visitMnEntry(TiffMnEntry* object) =0; virtual void visitMnEntry(TiffMnEntry* object) =0;
//! Operation to perform for an IFD makernote //! Operation to perform for an IFD makernote
virtual void visitIfdMakernote(TiffIfdMakernote* object) =0; virtual void visitIfdMakernote(TiffIfdMakernote* object) =0;
//! Operation to perform after processing an IFD makernote
virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object) {}
//@} //@}
//! @name Accessors //! @name Accessors
@ -209,14 +207,52 @@ namespace Exiv2 {
}; // class TiffMetadataDecoder }; // 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<TiffRwState> 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 @brief TIFF composite visitor to read the TIFF structure from a block of
memory and build the composite from it (Visitor pattern). Used by memory and build the composite from it (Visitor pattern). Used by
TiffParser to read the TIFF data from a block of memory. Uses TiffParser to read the TIFF data from a block of memory.
the policy class CreationPolicy for the creation of TIFF components.
*/ */
template<typename CreationPolicy> class TiffReader : public TiffVisitor {
class TiffReader : public TiffVisitor, public CreationPolicy {
public: public:
//! @name Creators //! @name Creators
//@{ //@{
@ -225,16 +261,17 @@ namespace Exiv2 {
structure of the data are set in the constructor. structure of the data are set in the constructor.
@param pData Pointer to the data buffer, starting with a TIFF header. @param pData Pointer to the data buffer, starting with a TIFF header.
@param size Number of bytes in the data buffer. @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 pRoot Root element of the TIFF composite.
@param state State object for creation function, byteorder and
base offset.
*/ */
TiffReader(const byte* pData, TiffReader(const byte* pData,
uint32_t size, uint32_t size,
ByteOrder byteOrder, TiffComponent* pRoot,
TiffComponent* pRoot); TiffRwState::AutoPtr state);
//! Virtual destructor //! Virtual destructor
virtual ~TiffReader() {} virtual ~TiffReader();
//@} //@}
//! @name Manipulators //! @name Manipulators
@ -249,18 +286,35 @@ namespace Exiv2 {
virtual void visitMnEntry(TiffMnEntry* object); virtual void visitMnEntry(TiffMnEntry* object);
//! Read an IFD makernote from the data buffer //! Read an IFD makernote from the data buffer
virtual void visitIfdMakernote(TiffIfdMakernote* object); 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 //! Read a standard TIFF entry from the data buffer
void readTiffEntry(TiffEntryBase* object); 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: private:
// DATA // DATA
const byte* pData_; //!< Pointer to the memory buffer const byte* pData_; //!< Pointer to the memory buffer
const uint32_t size_; //!< Size of the buffer const uint32_t size_; //!< Size of the buffer
const byte* pLast_; //!< Pointer to the last byte const byte* pLast_; //!< Pointer to the last byte
const ByteOrder byteOrder_; //!< Byteorder for the image TiffComponent* const pRoot_; //!< Root element of the composite
TiffComponent* const pRoot_; //!< Root element of the composite TiffRwState* pState_; //!< State class
TiffRwState* pOrigState_; //!< State class as set in the c'tor
}; // class TiffReader }; // class TiffReader
@ -319,9 +373,6 @@ namespace Exiv2 {
static const std::string indent_; //!< Indent for one level static const std::string indent_; //!< Indent for one level
}; // class TiffPrinter }; // class TiffPrinter
// *****************************************************************************
// template, inline and free functions
} // namespace Exiv2 } // namespace Exiv2
#endif // #ifndef TIFFVISITOR_HPP_ #endif // #ifndef TIFFVISITOR_HPP_

@ -1,277 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* 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)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@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 <iostream>
#include <iomanip>
#include <cassert>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// template, inline and free functions
template<typename CreationPolicy>
TiffReader<CreationPolicy>::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<typename CreationPolicy>
void TiffReader<CreationPolicy>::visitEntry(TiffEntry* object)
{
readTiffEntry(object);
}
template<typename CreationPolicy>
void TiffReader<CreationPolicy>::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<typename CreationPolicy>
void TiffReader<CreationPolicy>::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<typename CreationPolicy>
void TiffReader<CreationPolicy>::visitMnEntry(TiffMnEntry* object)
{
assert(object != 0);
readTiffEntry(object);
// Find the camera model
TiffFinder finder(0x010f, Group::ifd0);
pRoot_->accept(finder);
TiffEntryBase* te = dynamic_cast<TiffEntryBase*>(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<typename CreationPolicy>
void TiffReader<CreationPolicy>::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<typename CreationPolicy>
void TiffReader<CreationPolicy>::readTiffEntry(TiffEntryBase* object)
{
assert(object != 0);
byte* p = const_cast<byte*>(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<uint32_t>(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_
Loading…
Cancel
Save