Experimental TIFF read-only support, without Makernotes. As a side-effect, the parser also handles NEF images. Only tried on Linux so far.

v0.27.3
Andreas Huggel 19 years ago
parent bec3e47dfe
commit 70695ded92

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

@ -43,10 +43,8 @@ namespace Exiv2 {
ErrMsg( -1, "Error %0: arg1=%1, arg2=%2, arg3=%3."), ErrMsg( -1, "Error %0: arg1=%1, arg2=%2, arg3=%3."),
ErrMsg( 0, "Success"), ErrMsg( 0, "Success"),
ErrMsg( 1, "%1"), // %1=error message ErrMsg( 1, "%1"), // %1=error message
ErrMsg( 2, "%1: %2 (%3)"), // %1=path, %2=strerror, %3=function that failed ErrMsg( 2, "%1: %2 (%3)"), // %1=path, %2=strerror, %3=function that failed
// ErrMsg( 3, ""), ErrMsg( 3, "This does not look like a %1 image"), // %1=Image type
ErrMsg( 4, "Invalid dataset name `%1'"), // %1=dataset name ErrMsg( 4, "Invalid dataset name `%1'"), // %1=dataset name
ErrMsg( 5, "Invalid record name `%1'"), // %1=record name ErrMsg( 5, "Invalid record name `%1'"), // %1=record name
ErrMsg( 6, "Invalid key `%1'"), // %1=key ErrMsg( 6, "Invalid key `%1'"), // %1=key

@ -34,6 +34,7 @@ EXIV2_RCSID("@(#) $Id$");
#include "image.hpp" #include "image.hpp"
#include "jpgimage.hpp" #include "jpgimage.hpp"
#include "crwimage.hpp" #include "crwimage.hpp"
#include "tiffimage.hpp"
// + standard includes // + standard includes
@ -44,7 +45,8 @@ namespace Exiv2 {
ImageFactory::Registry ImageFactory::registry_[] = { ImageFactory::Registry ImageFactory::registry_[] = {
Registry(ImageType::jpeg, newJpegInstance, isJpegType), Registry(ImageType::jpeg, newJpegInstance, isJpegType),
Registry(ImageType::exv, newExvInstance, isExvType), Registry(ImageType::exv, newExvInstance, isExvType),
Registry(ImageType::crw, newCrwInstance, isCrwType) Registry(ImageType::crw, newCrwInstance, isCrwType),
Registry(ImageType::tiff, newTiffInstance, isTiffType)
}; };
} // namespace Exiv2 } // namespace Exiv2

@ -54,7 +54,13 @@ try {
if (0 == rootDir.get()) { if (0 == rootDir.get()) {
throw Error(1, "No root element defined in TIFF structure"); throw Error(1, "No root element defined in TIFF structure");
} }
rootDir->read(buf.pData_, buf.size_, tiffHeader.offset(), tiffHeader.byteOrder()); TiffReader reader(buf.pData_,
buf.size_,
tiffHeader.byteOrder(),
tiffStructure);
rootDir->setStart(buf.pData_ + tiffHeader.offset());
rootDir->accept(reader);
tiffHeader.print(std::cerr); tiffHeader.print(std::cerr);
rootDir->print(std::cerr, tiffHeader.byteOrder()); rootDir->print(std::cerr, tiffHeader.byteOrder());

@ -58,10 +58,9 @@ EXIV2_RCSID("@(#) $Id$");
Todo: Todo:
+ Add child mgmt stuff to TIFF composite: add, remove, find + Add further child mgmt stuff to TIFF composite: remove, find
+ Better encapsulate TiffStructure + Better handling of TiffStructure
+ Remove read methods from Composite and turn them into a visitor + Add Makernote support
+ Remove TiffStructure from Composite
in crwimage.* : in crwimage.* :
@ -92,7 +91,13 @@ namespace Exiv2 {
TiffComponent::AutoPtr rootDir TiffComponent::AutoPtr rootDir
= TiffParser::create(Tag::root, Group::none, pTiffStructure); = TiffParser::create(Tag::root, Group::none, pTiffStructure);
if (0 == rootDir.get()) return; if (0 == rootDir.get()) return;
rootDir->read(pData, size, tiffHeader.offset(), tiffHeader.byteOrder());
TiffReader reader(pData,
size,
tiffHeader.byteOrder(),
pTiffStructure);
rootDir->setStart(pData + tiffHeader.offset());
rootDir->accept(reader);
#ifdef DEBUG #ifdef DEBUG
tiffHeader.print(std::cerr); tiffHeader.print(std::cerr);
@ -119,7 +124,7 @@ namespace Exiv2 {
TiffComponent::AutoPtr tc(0); TiffComponent::AutoPtr tc(0);
if (ts && ts->newTiffCompFct_) { if (ts && ts->newTiffCompFct_) {
tc = ts->newTiffCompFct_(pTiffStructure, idx); tc = ts->newTiffCompFct_(ts);
} }
if (!ts) { if (!ts) {
uint16_t tag = static_cast<uint16_t>(extendedTag & 0xffff); uint16_t tag = static_cast<uint16_t>(extendedTag & 0xffff);
@ -167,142 +172,49 @@ namespace Exiv2 {
return true; return true;
} // TiffHeade2::read } // TiffHeade2::read
void TiffComponent::read(const byte* pData, void TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent)
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{ {
doRead(pData, size, start, byteOrder); doAddChild(tiffComponent);
} // TiffComponent::read } // TiffComponent::addChild
void TiffEntryBase::readEntry(const byte* pData, void TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent)
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{ {
if (size - start < 12) throw Error(3, "TIFF"); components_.push_back(tiffComponent.release());
const byte* p = pData + start; } // TiffDirectory::doAddChild
// Component already has tag
p += 2;
type_ = getUShort(p, byteOrder);
// todo: check type
p += 2;
count_ = getULong(p, byteOrder);
p += 4;
offset_ = getULong(p, byteOrder);
size_ = TypeInfo::typeSize(typeId()) * count();
if (size_ > 4) {
if (size < offset() + size_) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Upper boundary of data for "
<< "directory " << group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " entry 0x" << std::setw(4)
<< std::setfill('0') << std::hex << tag()
<< " is out of bounds:\n"
<< " Offset = 0x" << std::setw(8)
<< std::setfill('0') << std::hex << offset()
<< ", size = " << std::dec << size_
<< ", exceeds buffer size by "
<< offset() + size_ - size
<< " Bytes; adjusting the size\n";
#endif
size_ = size - offset();
// todo: adjust count_, make size_ a multiple of typeSize
}
pData_ = pData + offset();
}
else {
pData_ = pData + start + 8;
}
pValue_ = Value::create(typeId()).release();
if (pValue_) pValue_->read(pData_, size_, byteOrder);
} // TiffEntryBase::readEntry
void TiffEntry::doRead(const byte* pData, void TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent)
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{ {
TiffEntryBase::readEntry(pData, size, start, byteOrder); ifd_.addChild(tiffComponent);
} // TiffEntry::doRead } // TiffSubIfd::doAddChild
void TiffDirectory::doRead(const byte* pData, void TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent)
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{ {
if (size < start + 2) { doAddNext(tiffComponent);
#ifndef SUPPRESS_WARNINGS } // TiffComponent::addNext
std::cerr << "Error: "
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD exceeds data buffer, cannot read entry count.\n";
#endif
return;
}
uint32_t o = start;
const uint16_t n = getUShort(pData + o, byteOrder);
o += 2;
for (uint16_t i = 0; i < n; ++i) { void TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent)
if (size < o + 12) { {
#ifndef SUPPRESS_WARNINGS pNext_ = tiffComponent.release();
std::cerr << "Error: " } // TiffDirectory::doAddNext
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD entry " << i
<< " lies outside of the data buffer.\n";
#endif
return;
}
uint16_t tag = getUShort(pData + o, byteOrder);
TiffComponent::AutoPtr tc
= TiffParser::create(tag, group(), pTiffStructure());
tc->read(pData, size, o, byteOrder);
components_.push_back(tc.release());
o += 12;
}
if (size < o + 4) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD exceeds data buffer, cannot read next pointer.\n";
#endif
return;
}
uint32_t next = getLong(pData + o, byteOrder);
if (next) {
pNext_ = TiffParser::create(Tag::next, group(), pTiffStructure()).release();
pNext_->read(pData, size, next, byteOrder);
}
} // TiffDirectory::doRead
void TiffSubIfd::doRead(const byte* pData, void TiffSubIfd::doAddNext(TiffComponent::AutoPtr tiffComponent)
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{ {
TiffEntryBase::readEntry(pData, size, start, byteOrder); ifd_.addNext(tiffComponent);
if (typeId() == unsignedLong && count() >= 1) { } // TiffSubIfd::doAddNext
uint32_t offset = getULong(this->pData(), byteOrder);
ifd_.read(pData, size, offset, byteOrder);
}
#ifndef SUPPRESS_WARNINGS
else {
std::cerr << "Warning: "
<< "Directory " << group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " entry 0x" << std::setw(4)
<< std::setfill('0') << std::hex << tag()
<< " doesn't look like a sub-IFD.";
}
#endif
} // TiffSubIfd::read
void TiffHeade2::print(std::ostream& os, const std::string& prefix) const void TiffHeade2::print(std::ostream& os, const std::string& prefix) const
{ {
os << prefix os << prefix
<< "Header, offset = 0x" << std::setw(8) << std::setfill('0') << "Header, offset = 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << offset_ << "\n"; << 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 } // TiffHeade2::print
void TiffComponent::print(std::ostream& os, void TiffComponent::print(std::ostream& os,
@ -317,15 +229,17 @@ namespace Exiv2 {
const std::string& prefix) const const std::string& prefix) const
{ {
os << prefix os << prefix
<< "tag = 0x" << std::setw(4) << std::setfill('0') << "tag 0x" << std::setw(4) << std::setfill('0')
<< std::hex << std::right << tag() << std::hex << std::right << tag()
<< ", type = " << TypeInfo::typeName(typeId()) << ", type " << TypeInfo::typeName(typeId())
<< ", count = " << std::dec << count() << ", " << std::dec << count() << " component";
<< ", offset = " << offset() << "\n"; if (count() > 1) os << "s";
os <<" in " << size() << " bytes";
if (pValue_ && pValue_->size() < 100) { if (size() > 4) os << ", offset " << offset();
os << prefix << *pValue_ << "\n"; os << "\n";
} if (pValue_ && pValue_->count() < 100) os << prefix << *pValue_;
else os << prefix << "...";
os << "\n";
} // TiffEntryBase::printEntry } // TiffEntryBase::printEntry
@ -365,17 +279,17 @@ namespace Exiv2 {
ifd_.print(os, byteOrder, prefix); ifd_.print(os, byteOrder, prefix);
} // TiffSubIfd::doPrint } // TiffSubIfd::doPrint
void TiffComponent::accept(TiffVisitor& visitor) const void TiffComponent::accept(TiffVisitor& visitor)
{ {
doAccept(visitor); doAccept(visitor);
} // TiffComponent::accept } // TiffComponent::accept
void TiffEntry::doAccept(TiffVisitor& visitor) const void TiffEntry::doAccept(TiffVisitor& visitor)
{ {
visitor.visitEntry(this); visitor.visitEntry(this);
} // TiffEntry::doAccept } // TiffEntry::doAccept
void TiffDirectory::doAccept(TiffVisitor& visitor) const void TiffDirectory::doAccept(TiffVisitor& visitor)
{ {
visitor.visitDirectory(this); visitor.visitDirectory(this);
@ -390,29 +304,31 @@ namespace Exiv2 {
} // TiffDirectory::doAccept } // TiffDirectory::doAccept
void TiffSubIfd::doAccept(TiffVisitor& visitor) const void TiffSubIfd::doAccept(TiffVisitor& visitor)
{ {
visitor.visitSubIfd(this); visitor.visitSubIfd(this);
ifd_.accept(visitor); ifd_.accept(visitor);
} // TiffSubIfd::doAccept } // TiffSubIfd::doAccept
void TiffMetadataDecoder::visitEntry(const TiffEntry* object) void TiffMetadataDecoder::visitEntry(TiffEntry* object)
{ {
decodeTiffEntry(object); decodeTiffEntry(object);
} }
void TiffMetadataDecoder::visitDirectory(const TiffDirectory* object) void TiffMetadataDecoder::visitDirectory(TiffDirectory* object)
{ {
// Nothing to do // Nothing to do
} }
void TiffMetadataDecoder::visitSubIfd(const TiffSubIfd* object) void TiffMetadataDecoder::visitSubIfd(TiffSubIfd* object)
{ {
decodeTiffEntry(object); decodeTiffEntry(object);
} }
void TiffMetadataDecoder::decodeTiffEntry(const TiffEntryBase* object) void TiffMetadataDecoder::decodeTiffEntry(const TiffEntryBase* object)
{ {
assert(object != 0);
// Todo: ExifKey should have an appropriate c'tor, this mapping should // Todo: ExifKey should have an appropriate c'tor, this mapping should
// be a table and it belongs somewhere else // be a table and it belongs somewhere else
std::string group; std::string group;
@ -427,22 +343,172 @@ namespace Exiv2 {
ExifKey k(object->tag(), group); ExifKey k(object->tag(), group);
assert(pImage_ != 0); assert(pImage_ != 0);
pImage_->exifData().add(k, object->pValue()); pImage_->exifData().add(k, object->pValue());
} // TiffEntryBase::decodeTiffEntry } // TiffMetadataDecoder::decodeTiffEntry
TiffReader::TiffReader(const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const TiffStructure* pTiffStructure)
: pData_(pData),
size_(size),
pLast_(pData + size - 1),
byteOrder_(byteOrder),
pTiffStructure_(pTiffStructure)
{
assert(pData);
assert(size > 0);
assert(pTiffStructure);
} // TiffReader::TiffReader
void TiffReader::visitEntry(TiffEntry* object)
{
readTiffEntry(object);
}
void TiffReader::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->group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " 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->group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD entry " << i
<< " lies outside of the data buffer.\n";
#endif
return;
}
uint16_t tag = getUShort(p, byteOrder_);
TiffComponent::AutoPtr tc
= TiffParser::create(tag, object->group(), pTiffStructure_);
tc->setStart(p);
object->addChild(tc);
p += 12;
}
if (p + 4 > pLast_) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << object->group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD exceeds data buffer, cannot read next pointer.\n";
#endif
return;
}
uint32_t next = getLong(p, byteOrder_);
if (next) {
TiffComponent::AutoPtr tc
= TiffParser::create(Tag::next, object->group(), pTiffStructure_);
tc->setStart(p);
object->addNext(tc);
}
} // TiffReader::visitDirectory
void TiffReader::visitSubIfd(TiffSubIfd* object)
{
assert(object != 0);
readTiffEntry(object);
if (object->typeId() == unsignedLong && object->count() >= 1) {
uint32_t offset = getULong(object->pData(), byteOrder_);
object->ifd_.setStart(pData_ + offset);
}
#ifndef SUPPRESS_WARNINGS
else {
std::cerr << "Warning: "
<< "Directory " << object->group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " entry 0x" << std::setw(4)
<< std::setfill('0') << std::hex << object->tag()
<< " doesn't look like a sub-IFD.";
}
#endif
} // TiffReader::visitSubIfd
void TiffReader::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->group() // todo: ExifTags::ifdName(ifdId_)
<< "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->offset_ = getULong(p, byteOrder_);
object->size_ = TypeInfo::typeSize(object->typeId()) * object->count();
object->pData_ = p;
if (object->size() > 4) {
object->pData_ = pData_ + object->offset();
if (object->pData() + object->size() > pLast_) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Upper boundary of data for "
<< "directory " << object->group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " 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 "
<< 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
// ************************************************************************* // *************************************************************************
// free functions // free functions
TiffComponent::AutoPtr newTiffDirectory(const TiffStructure* ts, int i) TiffComponent::AutoPtr newTiffDirectory(const TiffStructure* ts)
{ {
return TiffComponent::AutoPtr(new TiffDirectory(ts[i].tag(), ts[i].newGroup_, ts)); assert(ts);
return TiffComponent::AutoPtr(new TiffDirectory(ts->tag(), ts->newGroup_));
} }
TiffComponent::AutoPtr newTiffSubIfd(const TiffStructure* ts, int i) TiffComponent::AutoPtr newTiffSubIfd(const TiffStructure* ts)
{ {
return TiffComponent::AutoPtr(new TiffSubIfd(ts[i].tag(), assert(ts);
ts[i].group_, return TiffComponent::AutoPtr(new TiffSubIfd(ts->tag(),
ts[i].newGroup_, ts->group_,
ts)); ts->newGroup_));
} }
} // namespace Exiv2 } // namespace Exiv2

@ -50,7 +50,10 @@ namespace Exiv2 {
// class declarations // class declarations
struct TiffStructure; struct TiffStructure;
class TiffVisitor; class TiffDirectory;
class TiffEntryBase;
class TiffEntry;
class TiffSubIfd;
// ***************************************************************************** // *****************************************************************************
// type definitions // type definitions
@ -87,12 +90,187 @@ namespace Exiv2 {
const uint32_t next = 0x30000; //!< Special tag: next 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.
*/
class TiffReader : public TiffVisitor {
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 pTiffStructure Pointer to a table describing the TIFF structure
used to decode the data.
*/
TiffReader(const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const TiffStructure* pTiffStructure);
//! 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
const TiffStructure* pTiffStructure_; //!< Pointer to the TIFF structure
}; // class TiffReader
/*! /*!
@brief Interface class for components of a TIFF directory hierarchy @brief Interface class for components of a TIFF directory hierarchy
(Composite pattern). Both TIFF directories as well as entries (Composite pattern). Both TIFF directories as well as entries
implement this interface. A component can be un iquely identified implement this interface. A component can be un iquely identified
by a tag, group tupel. This class is implemented as a NVI by a tag, group tupel. This class is implemented as a NVI
(Non-Virtual Interface). It has an interface for visitors (Visitor (Non-Virtual Interface) and it has an interface for visitors (Visitor
pattern). pattern).
*/ */
class TiffComponent { class TiffComponent {
@ -105,10 +283,8 @@ namespace Exiv2 {
//! @name Creators //! @name Creators
//@{ //@{
//! Constructor //! Constructor
TiffComponent(uint16_t tag, TiffComponent(uint16_t tag, uint16_t group)
uint16_t group, : tag_(tag), group_(group), pData_(0) {}
const TiffStructure* pTiffStructure)
: tag_(tag), group_(group), pTiffStructure_(pTiffStructure) {}
//! Virtual destructor. //! Virtual destructor.
virtual ~TiffComponent() {} virtual ~TiffComponent() {}
@ -116,20 +292,22 @@ namespace Exiv2 {
//! @name Manipulators //! @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 Read a component from a data buffer @brief Interface to accept visitors (Visitor pattern).
@param pData Pointer to the data buffer, starting with a TIFF header.
@param size Number of bytes in the data buffer.
@param start Component starts at \em pData + \em start.
@param byteOrder Applicable byte order (little or big endian).
@throw Error If the component cannot be parsed. @param visitor The visitor.
*/ */
void read(const byte* pData, void accept(TiffVisitor& visitor);
uint32_t size, /*!
uint32_t start, @brief Set a pointer to the start of the binary representation of the
ByteOrder byteOrder); 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 //! @name Accessors
@ -138,8 +316,8 @@ namespace Exiv2 {
uint16_t tag() const { return tag_; } uint16_t tag() const { return tag_; }
//! Return the group id of this component //! Return the group id of this component
uint16_t group() const { return group_; } uint16_t group() const { return group_; }
//! Return the TIFF structure //! Return a pointer to the start of the binary representation of the component
const TiffStructure* pTiffStructure() const { return pTiffStructure_; } const byte* start() const { return pData_; }
/*! /*!
@brief Print debug info about a component to \em os. @brief Print debug info about a component to \em os.
@ -150,22 +328,19 @@ namespace Exiv2 {
void print(std::ostream& os, void print(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix ="") const; const std::string& prefix ="") const;
/*!
@brief Interface to accept visitors (Visitor pattern).
@param visitor The visitor.
*/
void accept(TiffVisitor& visitor) const;
//@} //@}
protected: protected:
//! @name Manipulators //! @name Manipulators
//@{ //@{
//! Implements read(). //! Implements addChild().
virtual void doRead(const byte* pData, virtual void doAddChild(AutoPtr tiffComponent) {}
uint32_t size,
uint32_t start, //! Implements addNext().
ByteOrder byteOrder) =0; virtual void doAddNext(AutoPtr tiffComponent) {}
//! Implements accept()
virtual void doAccept(TiffVisitor& visitor) =0;
//@} //@}
//! @name Accessors //! @name Accessors
@ -174,31 +349,34 @@ namespace Exiv2 {
virtual void doPrint(std::ostream& os, virtual void doPrint(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix) const =0; const std::string& prefix) const =0;
//! Implements accept()
virtual void doAccept(TiffVisitor& visitor) const =0;
//@} //@}
private: private:
// DATA // DATA
uint16_t tag_; //!< Tag that identifies the component uint16_t tag_; //!< Tag that identifies the component
uint16_t group_; //!< Group id for this component uint16_t group_; //!< Group id for this component
const TiffStructure* pTiffStructure_; //!< TIFF structure 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 }; // class TiffComponent
/*! /*!
@brief This baseclass provides the common functionality of an IFD @brief This abstract base class provides the common functionality of an
directory entry and defines the interface for derived concrete IFD directory entry and defines an extended interface for derived
entries. concrete entries, which allows access to the attributes of the
entry.
*/ */
class TiffEntryBase : public TiffComponent { class TiffEntryBase : public TiffComponent {
friend void TiffReader::readTiffEntry(TiffEntryBase* object);
public: public:
//! @name Creators //! @name Creators
//@{ //@{
//! Default constructor //! Default constructor
TiffEntryBase(uint16_t tag, uint16_t group) TiffEntryBase(uint16_t tag, uint16_t group)
: TiffComponent(tag, group, 0), : TiffComponent(tag, group),
type_(0), count_(0), offset_(0), type_(0), count_(0), offset_(0),
size_(0), pData_(0), isAllocated_(false), pValue_(0) {} size_(0), pData_(0), isAllocated_(false), pValue_(0) {}
//! Virtual destructor. //! Virtual destructor.
@ -226,15 +404,6 @@ namespace Exiv2 {
const std::string& prefix) const; const std::string& prefix) const;
//@} //@}
//! @name Manipulators
//@{
//! Read base entry
void readEntry(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
private: private:
// DATA // DATA
uint16_t type_; //!< Field Type uint16_t type_; //!< Field Type
@ -252,7 +421,7 @@ namespace Exiv2 {
}; // class TiffEntryBase }; // class TiffEntryBase
/*! /*!
@brief A standard TIFF IFD entry. The value is kept in a data buffer. @brief A standard TIFF IFD entry.
*/ */
class TiffEntry : public TiffEntryBase { class TiffEntry : public TiffEntryBase {
public: public:
@ -267,11 +436,7 @@ namespace Exiv2 {
private: private:
//! @name Manipulators //! @name Manipulators
//@{ //@{
//! Implements read(). virtual void doAccept(TiffVisitor& visitor);
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@} //@}
//! @name Accessors //! @name Accessors
@ -279,19 +444,21 @@ namespace Exiv2 {
virtual void doPrint(std::ostream& os, virtual void doPrint(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix) const; const std::string& prefix) const;
virtual void doAccept(TiffVisitor& visitor) const;
//@} //@}
}; // class TiffEntry }; // class TiffEntry
//! This class models a TIFF directory (%Ifd). /*!
@brief This class models a TIFF directory (%Ifd). It is a composite
component of the TIFF tree.
*/
class TiffDirectory : public TiffComponent { class TiffDirectory : public TiffComponent {
public: public:
//! @name Creators //! @name Creators
//@{ //@{
//! Default constructor //! Default constructor
TiffDirectory(uint16_t tag, uint16_t group, const TiffStructure* pTiffStructure) TiffDirectory(uint16_t tag, uint16_t group)
: TiffComponent(tag, group, pTiffStructure), pNext_(0) {} : TiffComponent(tag, group), pNext_(0) {}
//! Virtual destructor //! Virtual destructor
virtual ~TiffDirectory(); virtual ~TiffDirectory();
//@} //@}
@ -299,10 +466,11 @@ namespace Exiv2 {
private: private:
//! @name Manipulators //! @name Manipulators
//@{ //@{
virtual void doRead(const byte* pData, virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
uint32_t size,
uint32_t start, virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
ByteOrder byteOrder);
virtual void doAccept(TiffVisitor& visitor);
//@} //@}
//! @name Accessors //! @name Accessors
@ -310,8 +478,6 @@ namespace Exiv2 {
virtual void doPrint(std::ostream& os, virtual void doPrint(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix) const; const std::string& prefix) const;
virtual void doAccept(TiffVisitor& visitor) const;
//@} //@}
private: private:
@ -321,17 +487,21 @@ namespace Exiv2 {
}; // class TiffDirectory }; // class TiffDirectory
//! This class models a TIFF sub-directory (%SubIfd). /*!
@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 { class TiffSubIfd : public TiffEntryBase {
friend void TiffReader::visitSubIfd(TiffSubIfd* object);
public: public:
//! @name Creators //! @name Creators
//@{ //@{
//! Default constructor //! Default constructor
TiffSubIfd(uint16_t tag, TiffSubIfd(uint16_t tag, uint16_t group, uint16_t newGroup)
uint16_t group, : TiffEntryBase(tag, group), ifd_(tag, newGroup) {}
uint16_t newGroup,
const TiffStructure* pTiffStructure)
: TiffEntryBase(tag, group), ifd_(tag, newGroup, pTiffStructure) {}
//! Virtual destructor //! Virtual destructor
virtual ~TiffSubIfd() {} virtual ~TiffSubIfd() {}
//@} //@}
@ -339,10 +509,11 @@ namespace Exiv2 {
private: private:
//! @name Manipulators //! @name Manipulators
//@{ //@{
virtual void doRead(const byte* pData, virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
uint32_t size,
uint32_t start, virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
ByteOrder byteOrder);
virtual void doAccept(TiffVisitor& visitor);
//@} //@}
//! @name Accessors //! @name Accessors
@ -350,86 +521,26 @@ namespace Exiv2 {
virtual void doPrint(std::ostream& os, virtual void doPrint(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix) const; const std::string& prefix) const;
virtual void doAccept(TiffVisitor& visitor) const;
//@} //@}
private: private:
// DATA // DATA
TiffDirectory ifd_; //!< The subdirectory TiffDirectory ifd_; //!< The subdirectory
}; // class TiffDirectory }; // class TiffSubIfd
/*!
@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
/*! /*!
Type for a function pointer for functions to create TIFF components. 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 Todo: This may eventually need to also have access to the image or parse tree
in order to make decisions based on the value of other tags. in order to make decisions based on the value of other tags.
*/ */
typedef TiffComponent::AutoPtr (*NewTiffCompFct)(const TiffStructure* ts, int i); typedef TiffComponent::AutoPtr (*NewTiffCompFct)(const TiffStructure* ts);
/*! /*!
This structure is meant to be used as an entry (row) of a table describing @brief Data structure used as a row (element) of a table (array)
the TIFF structure of an image format for reading and writing. Different describing the TIFF structure of an image format for reading and
tables can be used to support different TIFF based image formats. writing. Different tables can be used to support different TIFF
based image formats.
*/ */
struct TiffStructure { struct TiffStructure {
//! Return the tag corresponding to the extended tag //! Return the tag corresponding to the extended tag
@ -441,57 +552,9 @@ namespace Exiv2 {
uint16_t newGroup_; //!< Group of the newly created component uint16_t newGroup_; //!< Group of the newly created component
}; };
//! Abstract base class for TIFF composite vistors (Visitor pattern)
class TiffVisitor {
public:
//! @name Creators
//@{
virtual ~TiffVisitor() {}
//@}
//! @name Manipulators
//@{
//! Decode a TIFF entry
virtual void visitEntry(const TiffEntry* object) =0;
//! Decode a TIFF directory
virtual void visitDirectory(const TiffDirectory* object) =0;
//! Decode a TIFF sub-IFD
virtual void visitSubIfd(const TiffSubIfd* object) =0;
//@}
}; // class TiffVisitor
/*!
TIFF composite visitor to decode metadata from the composite and add it
to an Image, which is supplied in the constructor.
*/
class TiffMetadataDecoder : public TiffVisitor {
public:
//! @name Creators
//@{
//! Constructor
TiffMetadataDecoder(Image* pImage) : pImage_(pImage) {}
//! Virtual destructor
virtual ~TiffMetadataDecoder() {}
//@}
//! @name Manipulators
//@{
virtual void visitEntry(const TiffEntry* object);
virtual void visitDirectory(const TiffDirectory* object);
virtual void visitSubIfd(const 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
/*! /*!
Stateless parser class for data in TIFF format. @brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF-based data.
*/ */
class TiffParser { class TiffParser {
public: public:
@ -500,7 +563,8 @@ namespace Exiv2 {
\em size into \em image. \em size into \em image.
This is the entry point to access image data in TIFF format. The This is the entry point to access image data in TIFF format. The
parser uses classes TiffHeade2, TiffEntry, TiffDirectory. parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
hierarchies.
@param pData Pointer to the data buffer. Must point to data @param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed. in TIFF format; no checks are performed.
@ -517,12 +581,12 @@ namespace Exiv2 {
const TiffStructure* pTiffStructure, const TiffStructure* pTiffStructure,
TiffVisitor& decoder); TiffVisitor& decoder);
/*! /*!
@brief Create the appropriate TiffComponent to handle the \em tag in @brief Create the TiffComponent for TIFF entry \em tag in \em group
\em group. based on the lookup list \em pTiffStructure.
Uses table \em pTiffStructure to derive the correct component. If a If a tag, group tupel is not found in the table, a TiffEntry is
tag, group tupel is not found in the table, a TiffEntry is created. If created. If the pointer that is returned is 0, then the TIFF entry
the pointer that is returned is 0, then the TIFF entry should be ignored. should be ignored.
*/ */
static TiffComponent::AutoPtr create( uint32_t extendedTag, static TiffComponent::AutoPtr create( uint32_t extendedTag,
uint16_t group, uint16_t group,
@ -533,10 +597,10 @@ namespace Exiv2 {
// template, inline and free functions // template, inline and free functions
//! Function to create and initialize a new TIFF directory //! Function to create and initialize a new TIFF directory
TiffComponent::AutoPtr newTiffDirectory(const TiffStructure* ts, int i); TiffComponent::AutoPtr newTiffDirectory(const TiffStructure* ts);
//! Function to create and initialize a new TIFF sub-directory //! Function to create and initialize a new TIFF sub-directory
TiffComponent::AutoPtr newTiffSubIfd(const TiffStructure* ts, int i); TiffComponent::AutoPtr newTiffSubIfd(const TiffStructure* ts);
} // namespace Exiv2 } // namespace Exiv2

Loading…
Cancel
Save