TIFF parser (experimental): Distributed the code across multiple files, added Olympus makernote

This commit is contained in:
Andreas Huggel 2006-04-15 02:59:54 +00:00
parent ac89e046f1
commit 41424cdfd4
11 changed files with 1849 additions and 912 deletions

View File

@ -47,14 +47,15 @@ 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
CCHDR = exv_conf.h exv_msvc.h mn.hpp rcsid.hpp tiffvisitor_tmpl.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 jpgimage.cpp \
makernote.cpp metadatum.cpp nikonmn.cpp olympusmn.cpp panasonicmn.cpp \
sigmamn.cpp sonymn.cpp tags.cpp tiffimage.cpp tiffparser.cpp types.cpp \
value.cpp
futils.cpp fujimn.cpp ifd.cpp image.cpp imgreg.cpp iptc.cpp \
jpgimage.cpp makernote.cpp makernote2.cpp metadatum.cpp nikonmn.cpp \
olympusmn.cpp panasonicmn.cpp sigmamn.cpp sonymn.cpp tags.cpp \
tiffcomposite.cpp tiffimage.cpp tiffparser.cpp tiffvisitor.cpp \
types.cpp value.cpp
# Add library C source files to this list
ifndef HAVE_TIMEGM
@ -65,7 +66,7 @@ endif
BINSRC = addmoddel.cpp crwedit.cpp crwparse.cpp dataarea-test.cpp \
exifcomment.cpp exifdata-test.cpp exifprint.cpp ifd-test.cpp iotest.cpp \
iptceasy.cpp iptcprint.cpp iptctest.cpp key-test.cpp makernote-test.cpp \
taglist.cpp write-test.cpp write2-test.cpp tiffparse.cpp
taglist.cpp write-test.cpp write2-test.cpp tiffparse.cpp
# Main source file of the Exiv2 application
EXIV2MAIN = exiv2.cpp

134
src/makernote2.cpp Normal file
View File

@ -0,0 +1,134 @@
// ***************************************************************** -*- 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: makernote2.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 11-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 "makernote2.hpp"
#include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
// + standard includes
#include <string>
#include <cstring>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
const TiffMnRegistry TiffMnCreator::registry_[] = {
{ "OLYMPUS", newOlympusMn }
};
bool TiffMnRegistry::operator==(const TiffMnRegistry::Key& key) const
{
std::string make(make_);
return make == key.make_.substr(0, make.length());
}
TiffComponent* TiffMnCreator::create(uint16_t tag,
uint16_t group,
std::string make,
const byte* pData,
uint32_t size,
ByteOrder byteOrder)
{
TiffComponent* tc = 0;
const TiffMnRegistry* tmr = find(registry_, TiffMnRegistry::Key(make));
if (tmr) tc = tmr->newMnFct_(tag, group, pData, size, byteOrder);
return tc;
} // TiffMnCreator::create
const char* OlympusMnHeader::signature_ = "OLYMP\0\1\0";
const uint32_t OlympusMnHeader::size_ = 8;
OlympusMnHeader::OlympusMnHeader()
{
read(reinterpret_cast<const byte*>(signature_), size_);
}
bool OlympusMnHeader::read(const byte* pData, uint32_t size)
{
assert (pData != 0);
if (size < size_) return false;
header_.alloc(size_);
memcpy(header_.pData_, pData, header_.size_);
return true;
} // OlympusMnHeader::read
bool OlympusMnHeader::check() const
{
if ( static_cast<uint32_t>(header_.size_) < size_
|| 0 != memcmp(header_.pData_, signature_, 5)) {
return false;
}
return true;
} // OlympusMnHeader::check
void TiffOlympusMn::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addChild(tiffComponent);
}
void TiffOlympusMn::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addNext(tiffComponent);
}
void TiffOlympusMn::doAccept(TiffVisitor& visitor)
{
visitor.visitOlympusMn(this);
ifd_.accept(visitor);
}
// *************************************************************************
// free functions
TiffComponent* newOlympusMn(uint16_t tag,
uint16_t group,
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return new TiffOlympusMn(tag, group);
}
} // namespace Exiv2

211
src/makernote2.hpp Normal file
View File

@ -0,0 +1,211 @@
// ***************************************************************** -*- 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 makernote2.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 MAKERNOTE2_HPP_
#define MAKERNOTE2_HPP_
// *****************************************************************************
// included header files
#include "tiffcomposite.hpp"
#include "types.hpp"
// + standard includes
#include <string>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class TiffComponent;
template<typename CreationPolicy> class TiffReader;
// *****************************************************************************
// class definitions
namespace Group {
const uint16_t olympmn = 257; //!< Olympus makernote
}
//! Type for a pointer to a function creating a makernote
typedef TiffComponent* (*NewMnFct)(uint16_t tag,
uint16_t group,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Makernote registry
struct TiffMnRegistry {
struct Key;
//! Compare a TiffMnRegistry structure with a TiffMnRegistry::Key
bool operator==(const Key& key) const;
// DATA
const char* make_; //!< Camera make
NewMnFct newMnFct_; //!< Makernote create function
};
//! Search key for TIFF structure.
struct TiffMnRegistry::Key {
//! Constructor
Key(const std::string& make) : make_(make) {}
std::string make_; //!< Camera make
};
/*!
@brief TIFF makernote factory for concrete TIFF makernotes.
*/
class TiffMnCreator {
public:
/*!
@brief Create the Makernote for camera \em make and details from
the makernote entry itself if needed. Return a pointer to
the newly created TIFF component. Set tag and group of the
new component to \em tag and \em group.
@note Ownership for the component is transferred to the caller,
who is responsible to delete the component. No smart pointer
is used to indicate this transfer here in order to reduce
file dependencies.
*/
static TiffComponent* create(uint16_t tag,
uint16_t group,
std::string make,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
protected:
//! Prevent destruction (needed if used as a policy class)
~TiffMnCreator() {}
private:
static const TiffMnRegistry registry_[]; //<! List of makernotes
}; // class TiffMnCreator
//! Makernote header interface. This class is used with TIFF makernotes.
class MnHeader {
public:
//! @name Creators
//@{
//! Virtual destructor.
virtual ~MnHeader() {}
//@}
//! @name Manipulators
//@{
//! Read the header from a data buffer, return true if successful
virtual bool read(const byte* pData,
uint32_t size) =0;
//@}
//! @name Accessors
//@{
//! Size of the header
virtual uint32_t size() const =0;
/*!
@brief Start of the makernote directory relative to the start of the
header.
*/
virtual uint32_t offset() const =0;
//! Check the header, return true if ok
virtual bool check() const =0;
//@}
}; // class MnHeader
//! Header of an Olympus Makernote
class OlympusMnHeader : public MnHeader {
public:
//! @name Creators
//@{
//! Default constructor
OlympusMnHeader();
//! Virtual destructor.
virtual ~OlympusMnHeader() {}
//@}
//! @name Manipulators
//@{
virtual bool read(const byte* pData,
uint32_t size);
//@}
//! @name Accessors
//@{
virtual uint32_t size() const { return header_.size_; }
virtual uint32_t offset() const { return size_; }
virtual bool check() const;
//@}
private:
DataBuf header_; //!< Data buffer for the makernote header
static const char* signature_; //!< Olympus makernote header signature
static const uint32_t size_; //!< Size of the signature
}; // class OlympusMnHeader
/*!
@brief Olympus Makernote
*/
class TiffOlympusMn : public TiffComponent {
template<typename CreationPolicy>
friend class TiffReader;
public:
//! @name Creators
//@{
//! Default constructor
TiffOlympusMn(uint16_t tag, uint16_t group)
: TiffComponent(tag, group), ifd_(tag, Group::olympmn) {}
//! Virtual destructor
virtual ~TiffOlympusMn() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
OlympusMnHeader header_; //!< Makernote header
TiffDirectory ifd_; //!< Makernote IFD
}; // TiffOlympusMn
// *****************************************************************************
// template, inline and free functions
//! Function to create an Olympus makernote
TiffComponent* newOlympusMn(uint16_t tag,
uint16_t group,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
} // namespace Exiv2
#endif // #ifndef MAKERNOTE2_HPP_

214
src/tiffcomposite.cpp Normal file
View File

@ -0,0 +1,214 @@
// ***************************************************************** -*- 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: tiffcomposite.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 11-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 tiffcomposite.o
//#define DEBUG
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
#include "value.hpp"
// + standard includes
#include <string>
#include <iostream>
#include <iomanip>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
void TiffHeade2::print(std::ostream& os, const std::string& prefix) const
{
os << prefix
<< "Header, offset = 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << offset_;
switch (byteOrder_) {
case littleEndian: os << ", little endian encoded"; break;
case bigEndian: os << ", big endian encoded"; break;
case invalidByteOrder: break;
}
os << "\n";
} // TiffHeade2::print
TiffDirectory::~TiffDirectory()
{
Components::iterator b = components_.begin();
Components::iterator e = components_.end();
for (Components::iterator i = b; i != e; ++i) {
delete *i;
}
delete pNext_;
} // TiffDirectory::~TiffDirectory
TiffEntryBase::~TiffEntryBase()
{
if (isAllocated_) {
delete[] pData_;
}
delete pValue_;
} // TiffEntryBase::~TiffEntryBase
TiffMakernote::~TiffMakernote()
{
delete mn_;
} // TiffMakernote::~TiffMakernote
const uint16_t TiffHeade2::tag_ = 42;
bool TiffHeade2::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
byteOrder_ = littleEndian;
}
else if (pData[0] == 0x4d && pData[1] == 0x4d) {
byteOrder_ = bigEndian;
}
else {
return false;
}
if (tag_ != getUShort(pData + 2, byteOrder_)) return false;
offset_ = getULong(pData + 4, byteOrder_);
return true;
} // TiffHeade2::read
std::string TiffComponent::groupName() const
{
// Todo: This mapping should be a table and it belongs somewhere else
// Possibly the whole function shouldn't be in this class...
std::string group;
switch (group_) {
case 1: group = "Image"; break;
case 2: group = "Thumbnail"; break;
case 3: group = "Photo"; break;
case 4: group = "GPSInfo"; break;
case 5: group = "Iop"; break;
case 257: group = "Olympus"; break;
default: group = "Unknown"; break;
}
return group;
}
void TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent)
{
doAddChild(tiffComponent);
} // TiffComponent::addChild
void TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
components_.push_back(tiffComponent.release());
} // TiffDirectory::doAddChild
void TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addChild(tiffComponent);
} // TiffSubIfd::doAddChild
void TiffMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
if (mn_) mn_->addChild(tiffComponent);
} // TiffMakernote::doAddChild
void TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent)
{
doAddNext(tiffComponent);
} // TiffComponent::addNext
void TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
pNext_ = tiffComponent.release();
} // TiffDirectory::doAddNext
void TiffSubIfd::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addNext(tiffComponent);
} // TiffSubIfd::doAddNext
void TiffMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
if (mn_) mn_->addNext(tiffComponent);
} // TiffMakernote::doAddNext
void TiffComponent::accept(TiffVisitor& visitor)
{
if (visitor.go()) doAccept(visitor); // one for NVI :)
} // TiffComponent::accept
void TiffEntry::doAccept(TiffVisitor& visitor)
{
visitor.visitEntry(this);
} // TiffEntry::doAccept
void TiffDirectory::doAccept(TiffVisitor& visitor)
{
visitor.visitDirectory(this);
Components::const_iterator b = components_.begin();
Components::const_iterator e = components_.end();
for (Components::const_iterator i = b; visitor.go() && i != e; ++i) {
(*i)->accept(visitor);
}
if (visitor.go()) visitor.visitDirectoryNext(this);
if (pNext_) {
pNext_->accept(visitor);
}
if (visitor.go()) visitor.visitDirectoryEnd(this);
} // TiffDirectory::doAccept
void TiffSubIfd::doAccept(TiffVisitor& visitor)
{
visitor.visitSubIfd(this);
ifd_.accept(visitor);
} // TiffSubIfd::doAccept
void TiffMakernote::doAccept(TiffVisitor& visitor)
{
visitor.visitMakernote(this);
if (mn_) mn_->accept(visitor);
} // TiffMakernote::doAccept
// *************************************************************************
// free functions
} // namespace Exiv2

408
src/tiffcomposite.hpp Normal file
View File

@ -0,0 +1,408 @@
// ***************************************************************** -*- 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 tiffcomposite.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 TIFFCOMPOSITE_HPP_
#define TIFFCOMPOSITE_HPP_
// *****************************************************************************
// included header files
#include "image.hpp" // for Blob
#include "types.hpp"
// + standard includes
#include <iosfwd>
#include <vector>
#include <string>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
class TiffVisitor;
template<typename CreationPolicy> class TiffReader;
class TiffMetadataDecoder;
class TiffPrinter;
// *****************************************************************************
// class definitions
/*!
Known TIFF groups
Todo: what exactly are these and where should they go?
Are they going to be mapped to the second part of an Exif key or are they
the second part of the key?
*/
namespace Group {
const uint16_t none = 0; //!< Dummy group
const uint16_t ifd0 = 1; //!< Exif IFD0
const uint16_t ifd1 = 2; //!< Thumbnail IFD
const uint16_t exif = 3; //!< Exif IFD
const uint16_t gps = 4; //!< GPS IFD
const uint16_t iop = 5; //!< Interoperability IFD
const uint16_t mn = 256; //!< Makernote
}
/*!
Special TIFF tags for the use in TIFF structures only
Todo: Same Q as above...
*/
namespace Tag {
const uint32_t none = 0x10000; //!< Dummy tag
const uint32_t root = 0x20000; //!< Special tag: root IFD
const uint32_t next = 0x30000; //!< Special tag: next IFD
}
/*!
@brief This class models a TIFF header structure.
*/
class TiffHeade2 {
public:
//! @name Creators
//@{
//! Default constructor
TiffHeade2()
: byteOrder_ (littleEndian),
offset_ (0x00000008)
{}
//@}
//! @name Manipulators
//@{
/*!
@brief Read the TIFF header from a data buffer. Return false if the
data buffer does not contain a TIFF header, else true.
@param pData Pointer to the data buffer.
@param size Number of bytes in the data buffer.
*/
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
/*!
@brief Write the TIFF header to the binary image \em blob.
This method appends to the blob.
@param blob Binary image to add to.
@throw Error If the header cannot be written.
*/
void write(Blob& blob) const;
/*!
@brief Print debug info for the TIFF header to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; }
//! Return the offset to the start of the root directory
uint32_t offset() const { return offset_; }
//@}
private:
// DATA
ByteOrder byteOrder_; //!< Applicable byte order
uint32_t offset_; //!< Offset to the start of the root dir
static const uint16_t tag_; //!< 42, identifies the buffer as TIFF data
}; // class TiffHeade2
/*!
@brief Interface class for components of a TIFF directory hierarchy
(Composite pattern). Both TIFF directories as well as entries
implement this interface. A component can be un iquely identified
by a tag, group tupel. This class is implemented as a NVI
(Non-Virtual Interface) and it has an interface for visitors (Visitor
pattern).
*/
class TiffComponent {
public:
//! TiffComponent auto_ptr type
typedef std::auto_ptr<TiffComponent> AutoPtr;
//! Container type to hold all metadata
typedef std::vector<TiffComponent*> Components;
//! @name Creators
//@{
//! Constructor
TiffComponent(uint16_t tag, uint16_t group)
: tag_(tag), group_(group), pData_(0) {}
//! Virtual destructor.
virtual ~TiffComponent() {}
//@}
//! @name Manipulators
//@{
//! Add a child to the component. Default is to do nothing.
void addChild(AutoPtr tiffComponent);
//! Add a "next" component to the component. Default is to do nothing.
void addNext(AutoPtr tiffComponent);
/*!
@brief Interface to accept visitors (Visitor pattern).
@param visitor The visitor.
*/
void accept(TiffVisitor& visitor);
/*!
@brief Set a pointer to the start of the binary representation of the
component in a memory buffer. The buffer must be allocated and
freed outside of this class.
*/
void setStart(const byte* pData) { pData_ = const_cast<byte*>(pData); }
//@}
//! @name Accessors
//@{
//! Return the tag of this entry.
uint16_t tag() const { return tag_; }
//! Return the group id of this component
uint16_t group() const { return group_; }
//! Return the group name of this component
std::string groupName() const;
//! Return a pointer to the start of the binary representation of the component
const byte* start() const { return pData_; }
protected:
//! @name Manipulators
//@{
//! Implements addChild().
virtual void doAddChild(AutoPtr tiffComponent) {}
//! Implements addNext().
virtual void doAddNext(AutoPtr tiffComponent) {}
//! Implements accept()
virtual void doAccept(TiffVisitor& visitor) =0;
//@}
private:
// DATA
uint16_t tag_; //!< Tag that identifies the component
uint16_t group_; //!< Group id for this component
/*!
Pointer to the start of the binary representation of the component in
a memory buffer. The buffer is allocated and freed outside of this class.
*/
byte* pData_;
}; // class TiffComponent
/*!
@brief This abstract base class provides the common functionality of an
IFD directory entry and defines an extended interface for derived
concrete entries, which allows access to the attributes of the
entry.
*/
class TiffEntryBase : public TiffComponent {
template<typename CreationPolicy>
friend class TiffReader;
public:
//! @name Creators
//@{
//! Default constructor
TiffEntryBase(uint16_t tag, uint16_t group)
: TiffComponent(tag, group),
type_(0), count_(0), offset_(0),
size_(0), pData_(0), isAllocated_(false), pValue_(0) {}
//! Virtual destructor.
virtual ~TiffEntryBase();
//@}
//! @name Accessors
//@{
//! Return the Exiv2 type which corresponds to the field type.
TypeId typeId() const { return TypeId(type_); }
//! 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.
uint32_t offset() const { return offset_; }
//! Return the size of this component in bytes
uint32_t size() const { return size_; }
//! Return a pointer to the data area of this component
const byte* pData() const { return pData_; }
//! Return a pointer to the converted value of this component
const Value* pValue() const { return pValue_; }
//@}
private:
// 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
/*!
Size of the data buffer holding the value in bytes, there is no
minimum size.
*/
uint32_t size_;
const byte* pData_; //!< Pointer to the data area
bool isAllocated_; //!< True if this entry owns the value data
Value* pValue_; //!< Converted data value
}; // class TiffEntryBase
/*!
@brief A standard TIFF IFD entry.
*/
class TiffEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffEntry(uint16_t tag, uint16_t group) : TiffEntryBase(tag, group) {}
//! Virtual destructor.
virtual ~TiffEntry() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
}; // class TiffEntry
/*!
@brief This class models a TIFF directory (%Ifd). It is a composite
component of the TIFF tree.
*/
class TiffDirectory : public TiffComponent {
friend class TiffPrinter;
public:
//! @name Creators
//@{
//! Default constructor
TiffDirectory(uint16_t tag, uint16_t group)
: TiffComponent(tag, group), pNext_(0) {}
//! Virtual destructor
virtual ~TiffDirectory();
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
Components components_; //!< List of components in this directory
TiffComponent* pNext_; //!< Pointer to the next IFD
}; // class TiffDirectory
/*!
@brief This class models a TIFF sub-directory (sub-IFD). A sub-IFD
is an entry with a value that is a pointer to an IFD
structure and contains this IFD. The TIFF standard defines
some important tags to be sub-IFDs, including the %Exif and
GPS tags.
*/
class TiffSubIfd : public TiffEntryBase {
template<typename CreationPolicy>
friend class TiffReader;
public:
//! @name Creators
//@{
//! Default constructor
TiffSubIfd(uint16_t tag, uint16_t group, uint16_t newGroup)
: TiffEntryBase(tag, group), ifd_(tag, newGroup) {}
//! Virtual destructor
virtual ~TiffSubIfd() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
TiffDirectory ifd_; //!< The subdirectory
}; // class TiffSubIfd
/*!
@brief This class is the basis for Makernote support in TIFF. It contains
a pointer to a concrete Makernote. The TiffReader<CreationPolicy>
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 TiffMakernote : public TiffEntryBase {
template<typename CreationPolicy>
friend class TiffReader;
friend class TiffMetadataDecoder;
friend class TiffPrinter;
public:
//! @name Creators
//@{
//! Default constructor
TiffMakernote(uint16_t tag, uint16_t group, uint16_t newGroup)
: TiffEntryBase(tag, group), newGroup_(newGroup), mn_(0) {}
//! Virtual destructor
virtual ~TiffMakernote();
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
uint16_t newGroup_; //!< New group for concrete mn
TiffComponent* mn_; //!< The Makernote
}; // class TiffMakernote
// *****************************************************************************
// template, inline and free functions
} // namespace Exiv2
#endif // #ifndef TIFFCOMPOSITE_HPP_

View File

@ -43,13 +43,17 @@ try {
if (0 == rootDir.get()) {
throw Error(1, "No root element defined in TIFF structure");
}
TiffReader<TiffCreator> reader(buf.pData_, buf.size_, tiffHeader.byteOrder());
rootDir->setStart(buf.pData_ + tiffHeader.offset());
TiffReader<TiffCreator> reader(buf.pData_,
buf.size_,
tiffHeader.byteOrder(),
rootDir.get());
rootDir->accept(reader);
tiffHeader.print(std::cerr);
rootDir->print(std::cerr, tiffHeader.byteOrder());
TiffPrinter tiffPrinter(std::cerr);
rootDir->accept(tiffPrinter);
return 0;
}

View File

@ -42,28 +42,32 @@ EXIV2_RCSID("@(#) $Id$");
#endif
#include "tiffparser.hpp"
#include "image.hpp"
#include "exif.hpp"
#include "tags.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "tiffcomposite.hpp"
// + standard includes
#include <iostream>
#include <iomanip>
#include <cassert>
/* --------------------------------------------------------------------------
Todo:
+ Add further child mgmt stuff to TIFF composite: remove, find
+ 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 TiffMakernote and
concrete Makernotes and which of them should derive from base-entry
- TiffMakernote 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.* :
@ -79,11 +83,23 @@ EXIV2_RCSID("@(#) $Id$");
// class member definitions
namespace Exiv2 {
/*
This table describes the standard TIFF layout and determines the
corresponding Exiv2 TIFF components. The key of the table consists of the
first two attributes, (extended) tag and group. Tag is the TIFF tag or one
of a few extended tags, group identifies the IFD or any other composite
TIFF component. Each entry of the table defines for a particular tag and
group combination, which create function is used and what the group of the
new component is.
*/
const TiffStructure TiffCreator::tiffStructure_[] = {
// ext. tag group create function new group
//--------- ----------- ---------------- -----------
{ Tag::root, Group::none, newTiffDirectory, Group::ifd0 },
{ 0x8769, Group::ifd0, newTiffSubIfd, Group::exif },
{ 0x8825, Group::ifd0, newTiffSubIfd, Group::gps },
{ 0xa005, Group::exif, newTiffSubIfd, Group::iop },
{ 0x927c, Group::exif, newTiffMakernote, Group::mn },
{ Tag::next, Group::ifd0, newTiffDirectory, Group::ifd0 }
};
@ -108,229 +124,6 @@ namespace Exiv2 {
return tc;
} // TiffCreator::create
TiffDirectory::~TiffDirectory()
{
Components::iterator b = components_.begin();
Components::iterator e = components_.end();
for (Components::iterator i = b; i != e; ++i) {
delete *i;
}
delete pNext_;
} // TiffDirectory::~TiffDirectory
TiffEntryBase::~TiffEntryBase()
{
if (isAllocated_) {
delete[] pData_;
}
delete pValue_;
} // TiffEntryBase::~TiffEntryBase
const uint16_t TiffHeade2::tag_ = 42;
bool TiffHeade2::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
byteOrder_ = littleEndian;
}
else if (pData[0] == 0x4d && pData[1] == 0x4d) {
byteOrder_ = bigEndian;
}
else {
return false;
}
if (tag_ != getUShort(pData + 2, byteOrder_)) return false;
offset_ = getULong(pData + 4, byteOrder_);
return true;
} // TiffHeade2::read
std::string TiffComponent::groupName() const
{
// Todo: This mapping should be a table and it belongs somewhere else
// Possibly the whole function shouldn't be in this class...
std::string group;
switch (group_) {
case 1: group = "Image"; break;
case 2: group = "Thumbnail"; break;
case 3: group = "Photo"; break;
case 4: group = "GPSInfo"; break;
case 5: group = "Iop"; break;
default: group = "Unknown"; break;
}
return group;
}
void TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent)
{
doAddChild(tiffComponent);
} // TiffComponent::addChild
void TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
components_.push_back(tiffComponent.release());
} // TiffDirectory::doAddChild
void TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addChild(tiffComponent);
} // TiffSubIfd::doAddChild
void TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent)
{
doAddNext(tiffComponent);
} // TiffComponent::addNext
void TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
pNext_ = tiffComponent.release();
} // TiffDirectory::doAddNext
void TiffSubIfd::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addNext(tiffComponent);
} // TiffSubIfd::doAddNext
void TiffHeade2::print(std::ostream& os, const std::string& prefix) const
{
os << prefix
<< "Header, offset = 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << offset_;
switch (byteOrder_) {
case littleEndian: os << ", little endian encoded"; break;
case bigEndian: os << ", big endian encoded"; break;
case invalidByteOrder: break;
}
os << "\n";
} // TiffHeade2::print
void TiffComponent::print(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
doPrint(os, byteOrder, prefix);
} // TiffComponent::print
void TiffEntryBase::printEntry(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
os << prefix
<< "tag 0x" << std::setw(4) << std::setfill('0')
<< std::hex << std::right << tag()
<< ", type " << TypeInfo::typeName(typeId())
<< ", " << std::dec << count() << " component";
if (count() > 1) os << "s";
os <<" in " << size() << " bytes";
if (size() > 4) os << ", offset " << offset();
os << "\n";
if (pValue_ && pValue_->count() < 100) os << prefix << *pValue_;
else os << prefix << "...";
os << "\n";
} // TiffEntryBase::printEntry
void TiffEntry::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
TiffEntryBase::printEntry(os, byteOrder, prefix);
} // TiffEntry::doPrint
void TiffDirectory::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
os << prefix << groupName() << " directory with "
// cast to make MSVC happy
<< std::dec << static_cast<unsigned int>(components_.size());
if (components_.size() == 1) os << " entry:\n";
else os << " entries:\n";
Components::const_iterator b = components_.begin();
Components::const_iterator e = components_.end();
for (Components::const_iterator i = b; i != e; ++i) {
(*i)->print(os, byteOrder, prefix + " ");
}
if (pNext_) {
os << prefix << "Next directory:\n";
pNext_->print(os, byteOrder, prefix);
}
else {
os << prefix << "No next directory.\n";
}
} // TiffDirectory::doPrint
void TiffSubIfd::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
TiffEntryBase::printEntry(os, byteOrder, prefix);
ifd_.print(os, byteOrder, prefix);
} // TiffSubIfd::doPrint
void TiffComponent::accept(TiffVisitor& visitor)
{
doAccept(visitor);
} // TiffComponent::accept
void TiffEntry::doAccept(TiffVisitor& visitor)
{
visitor.visitEntry(this);
} // TiffEntry::doAccept
void TiffDirectory::doAccept(TiffVisitor& visitor)
{
visitor.visitDirectory(this);
Components::const_iterator b = components_.begin();
Components::const_iterator e = components_.end();
for (Components::const_iterator i = b; i != e; ++i) {
(*i)->accept(visitor);
}
if (pNext_) {
pNext_->accept(visitor);
}
} // TiffDirectory::doAccept
void TiffSubIfd::doAccept(TiffVisitor& visitor)
{
visitor.visitSubIfd(this);
ifd_.accept(visitor);
} // TiffSubIfd::doAccept
void TiffMetadataDecoder::visitEntry(TiffEntry* object)
{
decodeTiffEntry(object);
}
void TiffMetadataDecoder::visitDirectory(TiffDirectory* object)
{
// Nothing to do
}
void TiffMetadataDecoder::visitSubIfd(TiffSubIfd* object)
{
decodeTiffEntry(object);
}
void TiffMetadataDecoder::decodeTiffEntry(const TiffEntryBase* object)
{
assert(object != 0);
// Todo: ExifKey should have an appropriate c'tor, it should not be
// necessary to use groupName here
ExifKey k(object->tag(), object->groupName());
assert(pImage_ != 0);
pImage_->exifData().add(k, object->pValue());
} // TiffMetadataDecoder::decodeTiffEntry
// *************************************************************************
// free functions
@ -348,4 +141,12 @@ namespace Exiv2 {
ts->newGroup_));
}
TiffComponent::AutoPtr newTiffMakernote(const TiffStructure* ts)
{
assert(ts);
return TiffComponent::AutoPtr(new TiffMakernote(ts->tag(),
ts->group_,
ts->newGroup_));
}
} // namespace Exiv2

View File

@ -31,17 +31,14 @@
// *****************************************************************************
// included header files
#include "image.hpp"
#include "exif.hpp"
#include "iptc.hpp"
#include "types.hpp"
#include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
#include "tiffvisitor_tmpl.hpp"
#include "error.hpp"
#include "types.hpp"
// + standard includes
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <iosfwd>
#include <cassert>
// *****************************************************************************
@ -52,487 +49,11 @@ namespace Exiv2 {
// class declarations
struct TiffStructure;
class TiffDirectory;
class TiffEntryBase;
class TiffEntry;
class TiffSubIfd;
// *****************************************************************************
// type definitions
class Image;
// *****************************************************************************
// class definitions
/*!
Known TIFF groups
Todo: what exactly are these and where should they go?
Are they going to be mapped to the second part of an Exif key or are they
the second part of the key?
*/
namespace Group {
const uint16_t none = 0; //!< Dummy group
const uint16_t ifd0 = 1; //!< Exif IFD0
const uint16_t ifd1 = 2; //!< Thumbnail IFD
const uint16_t exif = 3; //!< Exif IFD
const uint16_t gps = 4; //!< GPS IFD
const uint16_t iop = 5; //!< Interoperability IFD
const uint16_t makernote = 256; //!< Makernote
const uint16_t canonmn = 257; //!< Canon makernote
}
/*!
Special TIFF tags for the use in TIFF structures only
Todo: Same Q as above...
*/
namespace Tag {
const uint32_t none = 0x10000; //!< Dummy tag
const uint32_t root = 0x20000; //!< Special tag: root IFD
const uint32_t next = 0x30000; //!< Special tag: next IFD
}
/*!
@brief This class models a TIFF header structure.
*/
class TiffHeade2 {
public:
//! @name Creators
//@{
//! Default constructor
TiffHeade2()
: byteOrder_ (littleEndian),
offset_ (0x00000008)
{}
//@}
//! @name Manipulators
//@{
/*!
@brief Read the TIFF header from a data buffer. Return false if the
data buffer does not contain a TIFF header, else true.
@param pData Pointer to the data buffer.
@param size Number of bytes in the data buffer.
*/
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
/*!
@brief Write the TIFF header to the binary image \em blob.
This method appends to the blob.
@param blob Binary image to add to.
@throw Error If the header cannot be written.
*/
void write(Blob& blob) const;
/*!
@brief Print debug info for the TIFF header to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; }
//! Return the offset to the start of the root directory
uint32_t offset() const { return offset_; }
//@}
private:
// DATA
ByteOrder byteOrder_; //!< Applicable byte order
uint32_t offset_; //!< Offset to the start of the root dir
static const uint16_t tag_; //!< 42, identifies the buffer as TIFF data
}; // class TiffHeade2
/*!
@brief Abstract base class for TIFF composite vistors (Visitor pattern)
A concrete visitor class is used as shown in the example below. Accept()
will invoke the member function corresponding to the concrete type of each
component in the composite.
@code
void visitorExample(Exiv2::TiffComponent* tiffComponent, Exiv2::TiffVisitor& visitor)
{
tiffComponent->accept(visitor);
}
@endcode
*/
class TiffVisitor {
public:
//! @name Creators
//@{
virtual ~TiffVisitor() {}
//@}
//! @name Manipulators
//@{
//! Operation to perform for a TIFF entry
virtual void visitEntry(TiffEntry* object) =0;
//! Operation to perform for a TIFF directory
virtual void visitDirectory(TiffDirectory* object) =0;
//! Operation to perform for a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object) =0;
//@}
}; // class TiffVisitor
/*!
@brief TIFF composite visitor to decode metadata from the TIFF tree and
add it to an Image, which is supplied in the constructor (Visitor
pattern). Used by TiffParser to decode the metadata from a
TIFF composite.
*/
class TiffMetadataDecoder : public TiffVisitor {
public:
//! @name Creators
//@{
//! Constructor, taking the image to add the metadata to
TiffMetadataDecoder(Image* pImage) : pImage_(pImage) {}
//! Virtual destructor
virtual ~TiffMetadataDecoder() {}
//@}
//! @name Manipulators
//@{
//! Decode a TIFF entry
virtual void visitEntry(TiffEntry* object);
//! Decode a TIFF directory
virtual void visitDirectory(TiffDirectory* object);
//! Decode a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object);
//! Decode a standard TIFF entry
void decodeTiffEntry(const TiffEntryBase* object);
//@}
private:
// DATA
Image* pImage_; //!< Pointer to the image to which the metadata is added
}; // class TiffMetadataDecoder
/*!
@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.
*/
template<typename CreationPolicy>
class TiffReader : public TiffVisitor, public CreationPolicy {
public:
//! @name Creators
//@{
/*!
@brief Constructor. The data buffer and table describing the TIFF
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).
*/
TiffReader(const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Virtual destructor
virtual ~TiffReader() {}
//@}
//! @name Manipulators
//@{
//! Read a TIFF entry from the data buffer
virtual void visitEntry(TiffEntry* object);
//! Read a TIFF directory from the data buffer
virtual void visitDirectory(TiffDirectory* object);
//! Read a TIFF sub-IFD from the data buffer
virtual void visitSubIfd(TiffSubIfd* object);
//! Read a standard TIFF entry from the data buffer
void readTiffEntry(TiffEntryBase* object);
//@}
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
}; // class TiffReader
/*!
@brief Interface class for components of a TIFF directory hierarchy
(Composite pattern). Both TIFF directories as well as entries
implement this interface. A component can be un iquely identified
by a tag, group tupel. This class is implemented as a NVI
(Non-Virtual Interface) and it has an interface for visitors (Visitor
pattern).
*/
class TiffComponent {
public:
//! TiffComponent auto_ptr type
typedef std::auto_ptr<TiffComponent> AutoPtr;
//! Container type to hold all metadata
typedef std::vector<TiffComponent*> Components;
//! @name Creators
//@{
//! Constructor
TiffComponent(uint16_t tag, uint16_t group)
: tag_(tag), group_(group), pData_(0) {}
//! Virtual destructor.
virtual ~TiffComponent() {}
//@}
//! @name Manipulators
//@{
//! Add a child to the component. Default is to do nothing.
void addChild(AutoPtr tiffComponent);
//! Add a "next" component to the component. Default is to do nothing.
void addNext(AutoPtr tiffComponent);
/*!
@brief Interface to accept visitors (Visitor pattern).
@param visitor The visitor.
*/
void accept(TiffVisitor& visitor);
/*!
@brief Set a pointer to the start of the binary representation of the
component in a memory buffer. The buffer must be allocated and
freed outside of this class.
*/
void setStart(const byte* pData) { pData_ = const_cast<byte*>(pData); }
//@}
//! @name Accessors
//@{
//! Return the tag of this entry.
uint16_t tag() const { return tag_; }
//! Return the group id of this component
uint16_t group() const { return group_; }
//! Return the group name of this component
std::string groupName() const;
//! Return a pointer to the start of the binary representation of the component
const byte* start() const { return pData_; }
/*!
@brief Print debug info about a component to \em os.
@param os Output stream to write to
@param byteOrder Byte order
@param prefix Prefix to be written before each line of output
*/
void print(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix ="") const;
//@}
protected:
//! @name Manipulators
//@{
//! Implements addChild().
virtual void doAddChild(AutoPtr tiffComponent) {}
//! Implements addNext().
virtual void doAddNext(AutoPtr tiffComponent) {}
//! Implements accept()
virtual void doAccept(TiffVisitor& visitor) =0;
//@}
//! @name Accessors
//@{
//! Implements print()
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const =0;
//@}
private:
// DATA
uint16_t tag_; //!< Tag that identifies the component
uint16_t group_; //!< Group id for this component
/*!
Pointer to the start of the binary representation of the component in
a memory buffer. The buffer is allocated and freed outside of this class.
*/
byte* pData_;
}; // class TiffComponent
/*!
@brief This abstract base class provides the common functionality of an
IFD directory entry and defines an extended interface for derived
concrete entries, which allows access to the attributes of the
entry.
*/
class TiffEntryBase : public TiffComponent {
template<typename CreationPolicy>
friend void TiffReader<CreationPolicy>::readTiffEntry(TiffEntryBase* object);
public:
//! @name Creators
//@{
//! Default constructor
TiffEntryBase(uint16_t tag, uint16_t group)
: TiffComponent(tag, group),
type_(0), count_(0), offset_(0),
size_(0), pData_(0), isAllocated_(false), pValue_(0) {}
//! Virtual destructor.
virtual ~TiffEntryBase();
//@}
//! @name Accessors
//@{
//! Return the Exiv2 type which corresponds to the field type.
TypeId typeId() const { return TypeId(type_); }
//! 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.
uint32_t offset() const { return offset_; }
//! Return the size of this component in bytes
uint32_t size() const { return size_; }
//! Return a pointer to the data area of this component
const byte* pData() const { return pData_; }
//! Return a pointer to the converted value of this component
const Value* pValue() const { return pValue_; }
//! Print base entry
void printEntry(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// 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
/*!
Size of the data buffer holding the value in bytes, there is no
minimum size.
*/
uint32_t size_;
const byte* pData_; //!< Pointer to the data area
bool isAllocated_; //!< True if this entry owns the value data
Value* pValue_; //!< Converted data value
}; // class TiffEntryBase
/*!
@brief A standard TIFF IFD entry.
*/
class TiffEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffEntry(uint16_t tag, uint16_t group) : TiffEntryBase(tag, group) {}
//! Virtual destructor.
virtual ~TiffEntry() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
//! @name Accessors
//@{
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
}; // class TiffEntry
/*!
@brief This class models a TIFF directory (%Ifd). It is a composite
component of the TIFF tree.
*/
class TiffDirectory : public TiffComponent {
public:
//! @name Creators
//@{
//! Default constructor
TiffDirectory(uint16_t tag, uint16_t group)
: TiffComponent(tag, group), pNext_(0) {}
//! Virtual destructor
virtual ~TiffDirectory();
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
//! @name Accessors
//@{
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// DATA
Components components_; //!< List of components in this directory
TiffComponent* pNext_; //!< Pointer to the next IFD
}; // class TiffDirectory
/*!
@brief This class models a TIFF sub-directory (sub-IFD). A sub-IFD
is an entry with a value that is a pointer to an IFD
structure and contains this IFD. The TIFF standard defines
some important tags to be sub-IFDs, including the %Exif and
GPS tags.
*/
class TiffSubIfd : public TiffEntryBase {
template<typename CreationPolicy>
friend void TiffReader<CreationPolicy>::visitSubIfd(TiffSubIfd* object);
public:
//! @name Creators
//@{
//! Default constructor
TiffSubIfd(uint16_t tag, uint16_t group, uint16_t newGroup)
: TiffEntryBase(tag, group), ifd_(tag, newGroup) {}
//! Virtual destructor
virtual ~TiffSubIfd() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
//! @name Accessors
//@{
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// DATA
TiffDirectory ifd_; //!< The subdirectory
}; // class TiffSubIfd
/*!
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
@ -547,17 +68,17 @@ namespace Exiv2 {
based image formats.
*/
struct TiffStructure {
struct Key;
//! Comparison operator to compare a TiffStructure with a TiffStructure::Key
bool operator==(const Key& key) const;
//! Return the tag corresponding to the extended tag
uint16_t tag() const { return static_cast<uint16_t>(extendedTag_ & 0xffff); }
// DATA
uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags)
uint16_t group_; //!< Group that contains the tag
NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component
uint16_t newGroup_; //!< Group of the newly created component
struct Key;
//! Comparison operator to compare a TiffStructure with a TiffStructure::Key
bool operator==(const Key& key) const;
};
//! Search key for TIFF structure.
@ -570,7 +91,7 @@ namespace Exiv2 {
/*!
@brief TIFF component factory for standard TIFF components. This class is
meant to be used as a policy class.
used as a policy class.
*/
class TiffCreator {
public:
@ -626,6 +147,9 @@ namespace Exiv2 {
//! Function to create and initialize a new TIFF sub-directory
TiffComponent::AutoPtr newTiffSubIfd(const TiffStructure* ts);
//! Function to create and initialize a new TIFF makernote
TiffComponent::AutoPtr newTiffMakernote(const TiffStructure* ts);
template<typename CreationPolicy>
void TiffParser<CreationPolicy>::decode(Image* pImage,
const byte* pData,
@ -645,7 +169,8 @@ namespace Exiv2 {
TiffReader<CreationPolicy> reader(pData,
size,
tiffHeader.byteOrder());
tiffHeader.byteOrder(),
rootDir.get());
rootDir->accept(reader);
TiffMetadataDecoder decoder(pImage);
@ -653,188 +178,6 @@ namespace Exiv2 {
} // TiffParser::decode
template<typename CreationPolicy>
TiffReader<CreationPolicy>::TiffReader(const byte* pData,
uint32_t size,
ByteOrder byteOrder)
: pData_(pData),
size_(size),
pLast_(pData + size - 1),
byteOrder_(byteOrder)
{
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);
byte* p = const_cast<byte*>(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>::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 TIFFPARSER_HPP_

217
src/tiffvisitor.cpp Normal file
View File

@ -0,0 +1,217 @@
// ***************************************************************** -*- 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.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 11-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 tiffvisitor.o
//#define DEBUG
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "tiffvisitor.hpp"
#include "tiffcomposite.hpp"
#include "makernote2.hpp"
#include "exif.hpp"
#include "image.hpp"
// + standard includes
#include <string>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
void TiffFinder::init(uint16_t tag, uint16_t group)
{
tag_ = tag;
group_ = group;
tiffComponent_ = 0;
}
void TiffFinder::findObject(TiffComponent* object)
{
if (object->tag() == tag_ && object->group() == group_) {
tiffComponent_ = object;
setGo(false);
}
}
void TiffFinder::visitEntry(TiffEntry* object)
{
findObject(object);
}
void TiffFinder::visitDirectory(TiffDirectory* object)
{
findObject(object);
}
void TiffFinder::visitSubIfd(TiffSubIfd* object)
{
findObject(object);
}
void TiffFinder::visitMakernote(TiffMakernote* object)
{
findObject(object);
}
void TiffFinder::visitOlympusMn(TiffOlympusMn* object)
{
findObject(object);
}
void TiffMetadataDecoder::visitEntry(TiffEntry* object)
{
decodeTiffEntry(object);
}
void TiffMetadataDecoder::visitDirectory(TiffDirectory* object)
{
// Nothing to do
}
void TiffMetadataDecoder::visitSubIfd(TiffSubIfd* object)
{
decodeTiffEntry(object);
}
void TiffMetadataDecoder::visitMakernote(TiffMakernote* object)
{
if (!object->mn_) decodeTiffEntry(object);
}
void TiffMetadataDecoder::visitOlympusMn(TiffOlympusMn* object)
{
// Nothing to do
}
void TiffMetadataDecoder::decodeTiffEntry(const TiffEntryBase* object)
{
assert(object != 0);
// Todo: ExifKey should have an appropriate c'tor, it should not be
// necessary to use groupName here
ExifKey k(object->tag(), object->groupName());
assert(pImage_ != 0);
pImage_->exifData().add(k, object->pValue());
} // TiffMetadataDecoder::decodeTiffEntry
const std::string TiffPrinter::indent_(" ");
void TiffPrinter::incIndent()
{
prefix_ += indent_;
} // TiffPrinter::incIndent
void TiffPrinter::decIndent()
{
if (prefix_.length() >= indent_.length()) {
prefix_.erase(prefix_.length() - indent_.length(), indent_.length());
}
} // TiffPrinter::decIndent
void TiffPrinter::visitEntry(TiffEntry* object)
{
printTiffEntry(object, prefix());
} // TiffPrinter::visitEntry
void TiffPrinter::visitDirectory(TiffDirectory* object)
{
assert(object != 0);
os_ << prefix() << object->groupName() << " directory with "
// cast to make MSVC happy
<< std::dec << static_cast<unsigned int>(object->components_.size());
if (object->components_.size() == 1) os_ << " entry:\n";
else os_ << " entries:\n";
incIndent();
} // TiffPrinter::visitDirectory
void TiffPrinter::visitDirectoryNext(TiffDirectory* object)
{
decIndent();
if (object->pNext_) os_ << prefix() << "Next directory:\n";
else os_ << prefix() << "No next directory\n";
} // TiffPrinter::visitDirectoryNext
void TiffPrinter::visitDirectoryEnd(TiffDirectory* object)
{
// Nothing to do
} // TiffPrinter::visitDirectoryEnd
void TiffPrinter::visitSubIfd(TiffSubIfd* object)
{
os_ << prefix() << "Sub-IFD ";
printTiffEntry(object);
} // TiffPrinter::visitSubIfd
void TiffPrinter::visitMakernote(TiffMakernote* object)
{
if (!object->mn_) printTiffEntry(object, prefix());
else os_ << prefix() << "Makernote ";
} // TiffPrinter::visitMakernote
void TiffPrinter::visitOlympusMn(TiffOlympusMn* object)
{
os_ << prefix() << "Todo: Olympus Makernote header\n";
} // TiffPrinter::visitOlympusMn
void TiffPrinter::printTiffEntry(TiffEntryBase* object,
const std::string& px) const
{
assert(object != 0);
os_ << px << object->groupName()
<< " tag 0x" << std::setw(4) << std::setfill('0')
<< std::hex << std::right << object->tag()
<< ", type " << TypeInfo::typeName(object->typeId())
<< ", " << std::dec << object->count() << " component";
if (object->count() > 1) os_ << "s";
os_ << " in " << object->size() << " bytes";
if (object->size() > 4) os_ << ", offset " << object->offset();
os_ << "\n";
const Value* vp = object->pValue();
if (vp && vp->count() < 100) os_ << prefix() << *vp;
else os_ << prefix() << "...";
os_ << "\n";
} // TiffPrinter::printTiffEntry
// *************************************************************************
// free functions
} // namespace Exiv2

327
src/tiffvisitor.hpp Normal file
View File

@ -0,0 +1,327 @@
// ***************************************************************** -*- 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.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_HPP_
#define TIFFVISITOR_HPP_
// *****************************************************************************
// included header files
#include "types.hpp"
// + standard includes
#include <iostream>
#include <iomanip>
#include <cassert>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class TiffComponent;
class TiffEntryBase;
class TiffEntry;
class TiffDirectory;
class TiffSubIfd;
class TiffMakernote;
class TiffOlympusMn;
class Image;
// *****************************************************************************
// class definitions
/*!
@brief Abstract base class defining the interface for TIFF composite
vistors (Visitor pattern)
A concrete visitor class is used as shown in the example below. Accept()
will invoke the member function corresponding to the concrete type of each
component in the composite.
@code
void visitorExample(Exiv2::TiffComponent* tiffComponent, Exiv2::TiffVisitor& visitor)
{
tiffComponent->accept(visitor);
}
@endcode
*/
class TiffVisitor {
public:
//! @name Creators
//@{
//! Default constructor
TiffVisitor() : go_(true) {}
//! Virtual destructor
virtual ~TiffVisitor() {}
//@}
//! @name Manipulators
//@{
//! Set the stop/go flag: true for go, false for stop
void setGo(bool go) { go_ = go; }
//! Operation to perform for a TIFF entry
virtual void visitEntry(TiffEntry* object) =0;
//! Operation to perform for a TIFF directory
virtual void visitDirectory(TiffDirectory* object) =0;
/*!
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.
*/
virtual void visitDirectoryEnd(TiffDirectory* object) {}
//! Operation to perform for a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object) =0;
//! Operation to perform for the makernote component
virtual void visitMakernote(TiffMakernote* object) =0;
//! Operation to perform for an Olympus makernote
virtual void visitOlympusMn(TiffOlympusMn* object) =0;
//@}
//! @name Accessors
//@{
//! Check if stop flag is clear, return true if it's clear.
bool go() { return go_; }
//@}
private:
bool go_; //!< Set this to false to abort the iteration
}; // class TiffVisitor
/*!
@brief Search the composite for a component with \em tag and \em group.
Return a pointer to the component or 0, if not found. The class
is ready for a first search after construction and can be
re-initialized with init().
*/
class TiffFinder : public TiffVisitor {
public:
//! @name Creators
//@{
//! Constructor, taking the image to add the metadata to
TiffFinder(uint16_t tag, uint16_t group)
: tag_(tag), group_(group), tiffComponent_(0) {}
//! Virtual destructor
virtual ~TiffFinder() {}
//@}
//! @name Manipulators
//@{
//! Find tag and group in a TIFF entry
virtual void visitEntry(TiffEntry* object);
//! Find tag and group in a TIFF directory
virtual void visitDirectory(TiffDirectory* object);
//! Find tag and group in a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object);
//! Find tag and group in a TIFF makernote
virtual void visitMakernote(TiffMakernote* object);
//! Find tag and group in an Olympus makernote
virtual void visitOlympusMn(TiffOlympusMn* object);
//! Check if \em object matches \em tag and \em group
void findObject(TiffComponent* object);
//! Initialize the Finder for a new search.
void init(uint16_t tag, uint16_t group);
//@}
//! @name Accessors
//@{
/*!
@brief Return the search result. 0 if no TIFF component was found
for the tag and group combination.
*/
TiffComponent* result() const { return tiffComponent_; }
//@}
private:
uint16_t tag_;
uint16_t group_;
TiffComponent* tiffComponent_;
}; // class TiffFinder
/*!
@brief TIFF composite visitor to decode metadata from the TIFF tree and
add it to an Image, which is supplied in the constructor (Visitor
pattern). Used by TiffParser to decode the metadata from a
TIFF composite.
*/
class TiffMetadataDecoder : public TiffVisitor {
public:
//! @name Creators
//@{
//! Constructor, taking the image to add the metadata to
TiffMetadataDecoder(Image* pImage) : pImage_(pImage) {}
//! Virtual destructor
virtual ~TiffMetadataDecoder() {}
//@}
//! @name Manipulators
//@{
//! Decode a TIFF entry
virtual void visitEntry(TiffEntry* object);
//! Decode a TIFF directory
virtual void visitDirectory(TiffDirectory* object);
//! Decode a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object);
//! Decode a TIFF makernote
virtual void visitMakernote(TiffMakernote* object);
//! Decode an Olympus makernote
virtual void visitOlympusMn(TiffOlympusMn* object);
//! Decode a standard TIFF entry
void decodeTiffEntry(const TiffEntryBase* object);
//@}
private:
// DATA
Image* pImage_; //!< Pointer to the image to which the metadata is added
}; // class TiffMetadataDecoder
/*!
@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.
*/
template<typename CreationPolicy>
class TiffReader : public TiffVisitor, public CreationPolicy {
public:
//! @name Creators
//@{
/*!
@brief Constructor. The data buffer and table describing the TIFF
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.
*/
TiffReader(const byte* pData,
uint32_t size,
ByteOrder byteOrder,
TiffComponent* pRoot);
//! Virtual destructor
virtual ~TiffReader() {}
//@}
//! @name Manipulators
//@{
//! Read a TIFF entry from the data buffer
virtual void visitEntry(TiffEntry* object);
//! Read a TIFF directory from the data buffer
virtual void visitDirectory(TiffDirectory* object);
//! Read a TIFF sub-IFD from the data buffer
virtual void visitSubIfd(TiffSubIfd* object);
//! Read a TIFF makernote entry from the data buffer
virtual void visitMakernote(TiffMakernote* object);
//! Read an Olympus makernote from the data buffer
virtual void visitOlympusMn(TiffOlympusMn* object);
//! Read a standard TIFF entry from the data buffer
void readTiffEntry(TiffEntryBase* object);
//@}
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
}; // class TiffReader
/*!
@brief TIFF composite visitor to print the TIFF structure to an output
stream.
*/
class TiffPrinter : public TiffVisitor {
public:
//! @name Creators
//@{
//! Constructor, takes an output stream to write to.
TiffPrinter(std::ostream& os, const std::string& prefix ="")
: os_(os), prefix_(prefix) {}
//! Virtual destructor
virtual ~TiffPrinter() {}
//@}
//! @name Manipulators
//@{
//! Print a TIFF entry.
virtual void visitEntry(TiffEntry* object);
//! Print a TIFF directory
virtual void visitDirectory(TiffDirectory* object);
//! Print header before next directory
virtual void visitDirectoryNext(TiffDirectory* object);
//! Cleanup before leaving this directory
virtual void visitDirectoryEnd(TiffDirectory* object);
//! Print a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object);
//! Print a TIFF makernote
virtual void visitMakernote(TiffMakernote* object);
//! Print an Olympus makernote
virtual void visitOlympusMn(TiffOlympusMn* object);
//! Increment the indent by one level
void incIndent();
//! Decrement the indent by one level
void decIndent();
//@}
//! @name Accessors
//@{
//! Print a standard TIFF entry.
void printTiffEntry(TiffEntryBase* object,
const std::string& prefix ="") const;
//! Return the current prefix
std::string prefix() const { return prefix_; }
//@}
private:
// DATA
std::ostream& os_; //!< Output stream to write to
std::string prefix_; //!< Current prefix
static const std::string indent_; //!< Indent for one level
}; // class TiffPrinter
// *****************************************************************************
// template, inline and free functions
} // namespace Exiv2
#endif // #ifndef TIFFVISITOR_HPP_

277
src/tiffvisitor_tmpl.hpp Normal file
View File

@ -0,0 +1,277 @@
// ***************************************************************** -*- 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>::visitMakernote(TiffMakernote* 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->newGroup_,
make,
object->pData(),
object->size(),
byteOrder_);
}
if (object->mn_) object->mn_->setStart(object->pData());
} // TiffReader::visitMakernote
template<typename CreationPolicy>
void TiffReader<CreationPolicy>::visitOlympusMn(TiffOlympusMn* object)
{
object->header_.read(object->start(), pLast_ - object->start());
if (!object->header_.check()) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: Olympus Makernote header check failed.\n";
#endif
return; // todo: signal error to parent, delete object
}
object->ifd_.setStart(object->start() + object->header_.offset());
} // TiffReader::visitOlympusMn
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_