TIFF parser (experimental): Distributed the code across multiple files, added Olympus makernote
This commit is contained in:
parent
ac89e046f1
commit
41424cdfd4
13
src/Makefile
13
src/Makefile
@ -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
134
src/makernote2.cpp
Normal 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
211
src/makernote2.hpp
Normal 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
214
src/tiffcomposite.cpp
Normal 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
408
src/tiffcomposite.hpp
Normal 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_
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
217
src/tiffvisitor.cpp
Normal 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
327
src/tiffvisitor.hpp
Normal 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
277
src/tiffvisitor_tmpl.hpp
Normal 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_
|
||||
Loading…
Reference in New Issue
Block a user