rev 5728 - in kde-extras: . exiv2 exiv2/branches
exiv2/branches/upstream exiv2/branches/upstream/current
exiv2/branches/upstream/current/src
Mark Purcell
msp at alioth.debian.org
Sat Mar 10 12:10:15 CET 2007
Author: msp
Date: 2007-03-10 11:10:14 +0000 (Sat, 10 Mar 2007)
New Revision: 5728
Added:
kde-extras/exiv2/
kde-extras/exiv2/branches/
kde-extras/exiv2/branches/upstream/
kde-extras/exiv2/branches/upstream/current/
kde-extras/exiv2/branches/upstream/current/src/
kde-extras/exiv2/branches/upstream/current/src/ifd.cpp
kde-extras/exiv2/tags/
Log:
[svn-inject] Installing original source of exiv2
Added: kde-extras/exiv2/branches/upstream/current/src/ifd.cpp
===================================================================
--- kde-extras/exiv2/branches/upstream/current/src/ifd.cpp 2007-03-10 10:58:40 UTC (rev 5727)
+++ kde-extras/exiv2/branches/upstream/current/src/ifd.cpp 2007-03-10 11:10:14 UTC (rev 5728)
@@ -0,0 +1,740 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ * Copyright (C) 2004, 2005, 2006 Andreas Huggel <ahuggel at 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: ifd.cpp
+ Version: $Rev: 763 $
+ Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ */
+// *****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: ifd.cpp 763 2006-05-09 19:42:23Z ahuggel $");
+
+// *****************************************************************************
+// included header files
+#include "ifd.hpp"
+#include "types.hpp"
+#include "error.hpp"
+#include "tags.hpp" // for ExifTags::ifdName
+
+// + standard includes
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <cstring>
+#include <cassert>
+
+// *****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Entry::Entry(bool alloc)
+ : alloc_(alloc), ifdId_(ifdIdNotSet), idx_(0),
+ tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0),
+ sizeDataArea_(0), pDataArea_(0), byteOrder_(invalidByteOrder)
+ {
+ }
+
+ Entry::~Entry()
+ {
+ if (alloc_) {
+ delete[] pData_;
+ delete[] pDataArea_;
+ }
+ }
+
+ Entry::Entry(const Entry& rhs)
+ : alloc_(rhs.alloc_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
+ tag_(rhs.tag_), type_(rhs.type_),
+ count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(0),
+ sizeDataArea_(rhs.sizeDataArea_), pDataArea_(0), byteOrder_(rhs.byteOrder_)
+ {
+ if (alloc_) {
+ if (rhs.pData_) {
+ pData_ = new byte[rhs.size()];
+ memcpy(pData_, rhs.pData_, rhs.size());
+ }
+ if (rhs.pDataArea_) {
+ pDataArea_ = new byte[rhs.sizeDataArea()];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
+ }
+ }
+ else {
+ pData_ = rhs.pData_;
+ pDataArea_ = rhs.pDataArea_;
+ }
+ }
+
+ Entry& Entry::operator=(const Entry& rhs)
+ {
+ if (this == &rhs) return *this;
+ alloc_ = rhs.alloc_;
+ ifdId_ = rhs.ifdId_;
+ idx_ = rhs.idx_;
+ tag_ = rhs.tag_;
+ type_ = rhs.type_;
+ count_ = rhs.count_;
+ offset_ = rhs.offset_;
+ size_ = rhs.size_;
+ sizeDataArea_ = rhs.sizeDataArea_;
+ byteOrder_ = rhs.byteOrder_;
+ if (alloc_) {
+ delete[] pData_;
+ pData_ = 0;
+ if (rhs.pData_) {
+ pData_ = new byte[rhs.size()];
+ memcpy(pData_, rhs.pData_, rhs.size());
+ }
+ delete[] pDataArea_;
+ pDataArea_ = 0;
+ if (rhs.pDataArea_) {
+ pDataArea_ = new byte[rhs.sizeDataArea()];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
+ }
+ }
+ else {
+ pData_ = rhs.pData_;
+ pDataArea_ = rhs.pDataArea_;
+ }
+ return *this;
+ } // Entry::operator=
+
+ void Entry::setValue(uint32_t data, ByteOrder byteOrder)
+ {
+ if (pData_ == 0 || size_ < 4) {
+ assert(alloc_);
+ size_ = 4;
+ delete[] pData_;
+ pData_ = new byte[size_];
+ }
+ ul2Data(pData_, data, byteOrder);
+ // do not change size_
+ type_ = unsignedLong;
+ count_ = 1;
+ }
+
+ void Entry::setValue(uint16_t type, uint32_t count, const byte* buf, long len, ByteOrder byteOrder)
+ {
+ byteOrder_ = byteOrder;
+ long dataSize = count * TypeInfo::typeSize(TypeId(type));
+ // No minimum size requirement, but make sure the buffer can hold the data
+ if (len < dataSize) throw Error(24, tag(), dataSize, len);
+ if (alloc_) {
+ delete[] pData_;
+ pData_ = new byte[len];
+ memset(pData_, 0x0, len);
+ memcpy(pData_, buf, dataSize);
+ size_ = len;
+ }
+ else {
+ if (size_ == 0) {
+ // Set the data pointer of a virgin entry
+ pData_ = const_cast<byte*>(buf);
+ size_ = len;
+ }
+ else {
+ // Overwrite existing data if it fits into the buffer
+ if (size_ < dataSize) throw Error(24, tag(), dataSize, size_);
+ memset(pData_, 0x0, size_);
+ memcpy(pData_, buf, dataSize);
+ // do not change size_
+ }
+ }
+ type_ = type;
+ count_ = count;
+ } // Entry::setValue
+
+ void Entry::setDataArea(const byte* buf, long len)
+ {
+ if (alloc_) {
+ delete[] pDataArea_;
+ pDataArea_ = new byte[len];
+ memcpy(pDataArea_, buf, len);
+ sizeDataArea_ = len;
+ }
+ else {
+ if (sizeDataArea_ == 0) {
+ // Set the data area pointer of a virgin entry
+ pDataArea_ = const_cast<byte*>(buf);
+ sizeDataArea_ = len;
+ }
+ else {
+ // Overwrite existing data if it fits into the buffer
+ if (sizeDataArea_ < len) {
+ throw Error(25, tag(), sizeDataArea_, len);
+ }
+ memset(pDataArea_, 0x0, sizeDataArea_);
+ memcpy(pDataArea_, buf, len);
+ // do not change sizeDataArea_
+ }
+ }
+ } // Entry::setDataArea
+
+ void Entry::setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder)
+ {
+ for (uint32_t i = 0; i < count(); ++i) {
+ byte* buf = pData_ + i * typeSize();
+ switch(TypeId(type())) {
+ case unsignedShort: {
+ uint16_t d = getUShort(buf, byteOrder);
+ if (d + offset > 0xffff) throw Error(26);
+ us2Data(buf, d + static_cast<uint16_t>(offset), byteOrder);
+ break;
+ }
+ case unsignedLong: {
+ ul2Data(buf, getULong(buf, byteOrder) + offset, byteOrder);
+ break;
+ }
+ case unsignedRational: {
+ URational d = getURational(buf, byteOrder);
+ d.first = d.first + offset * d.second;
+ ur2Data(buf, d, byteOrder);
+ break;
+ }
+ case signedShort: {
+ int16_t d = getShort(buf, byteOrder);
+ if (d + static_cast<int32_t>(offset) > 0xffff) throw Error(26);
+ s2Data(buf, d + static_cast<int16_t>(offset), byteOrder);
+ break;
+ }
+ case signedLong: {
+ int32_t d = getLong(buf, byteOrder);
+ l2Data(buf, d + static_cast<int32_t>(offset), byteOrder);
+ break;
+ }
+ case signedRational: {
+ Rational d = getRational(buf, byteOrder);
+ d.first = d.first + static_cast<int32_t>(offset) * d.second;
+ r2Data(buf, d, byteOrder);
+ break;
+ }
+ default:
+ throw Error(27);
+ break;
+ }
+ }
+ } // Entry::setDataAreaOffsets
+
+ void Entry::updateBase(byte* pOldBase, byte* pNewBase)
+ {
+ if (!alloc_) {
+ if (pDataArea_) {
+ pDataArea_ = pDataArea_ - pOldBase + pNewBase;
+ }
+ if (pData_) {
+ pData_ = pData_ - pOldBase + pNewBase;
+ }
+ }
+ } // Entry::updateBase
+
+ const byte* Entry::component(uint32_t n) const
+ {
+ if (n >= count()) return 0;
+ return data() + n * typeSize();
+ } // Entry::component
+
+ Ifd::Ifd(IfdId ifdId)
+ : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(0),
+ dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
+ {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+
+ Ifd::Ifd(IfdId ifdId, long offset)
+ : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(offset),
+ dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
+ {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+
+ Ifd::Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext)
+ : alloc_(alloc), ifdId_(ifdId), pBase_(0), offset_(offset),
+ dataOffset_(0), hasNext_(hasNext), pNext_(0), next_(0)
+ {
+ if (alloc_ && hasNext_) {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+ }
+
+ Ifd::~Ifd()
+ {
+ // do not delete pBase_
+ if (alloc_ && hasNext_) delete[] pNext_;
+ }
+
+ Ifd::Ifd(const Ifd& rhs)
+ : alloc_(rhs.alloc_), entries_(rhs.entries_), ifdId_(rhs.ifdId_),
+ pBase_(rhs.pBase_), offset_(rhs.offset_), dataOffset_(rhs.dataOffset_),
+ hasNext_(rhs.hasNext_), pNext_(rhs.pNext_), next_(rhs.next_)
+ {
+ if (alloc_ && hasNext_) {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ if (rhs.pNext_) memcpy(pNext_, rhs.pNext_, 4);
+ }
+ }
+
+ int Ifd::read(const byte* buf,
+ long len,
+ long start,
+ ByteOrder byteOrder,
+ long shift)
+ {
+ int rc = 0;
+ long o = start;
+ Ifd::PreEntries preEntries;
+
+ if (len < o + 2) rc = 6;
+ if (rc == 0) {
+ offset_ = start - shift;
+ int n = getUShort(buf + o, byteOrder);
+ o += 2;
+
+ for (int i = 0; i < n; ++i) {
+ if (len < o + 12) {
+#ifndef SUPPRESS_WARNINGS
+ std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
+ << " entry " << i
+ << " lies outside of the IFD memory buffer.\n";
+#endif
+ rc = 6;
+ break;
+ }
+ Ifd::PreEntry pe;
+ pe.tag_ = getUShort(buf + o, byteOrder);
+ pe.type_ = getUShort(buf + o + 2, byteOrder);
+ pe.count_ = getULong(buf + o + 4, byteOrder);
+ pe.size_ = pe.count_ * TypeInfo::typeSize(TypeId(pe.type_));
+ pe.offsetLoc_ = o + 8 - shift;
+ pe.offset_ = pe.size_ > 4 ? getLong(buf + o + 8, byteOrder) : 0;
+ preEntries.push_back(pe);
+ o += 12;
+ }
+ }
+ if (rc == 0 && hasNext_) {
+ if (len < o + 4) {
+#ifndef SUPPRESS_WARNINGS
+ std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
+ << " memory of the pointer to the next IFD"
+ << " lies outside of the IFD memory buffer.\n";
+#endif
+ rc = 6;
+ }
+ else {
+ if (alloc_) {
+ memcpy(pNext_, buf + o, 4);
+ }
+ else {
+ pNext_ = const_cast<byte*>(buf + o);
+ }
+ next_ = getULong(buf + o, byteOrder);
+ }
+ }
+ // Set the offset of the first data entry outside of the IFD.
+ if (rc == 0 && preEntries.size() > 0) {
+ // Find the entry with the smallest offset
+ Ifd::PreEntries::const_iterator i = std::min_element(
+ preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset);
+ // Only do something if there is at least one entry with data
+ // outside the IFD directory itself.
+ if (i->size_ > 4) {
+ // Set the offset of the first data entry outside of the IFD
+ if (i->offset_ + shift < 0) {
+#ifndef SUPPRESS_WARNINGS
+ std::cerr << "Error: Offset of the 1st data entry of "
+ << ExifTags::ifdName(ifdId_)
+ << " is out of bounds:\n"
+ << " Offset = 0x" << std::setw(8)
+ << std::setfill('0') << std::hex
+ << i->offset_ - offset_ // relative to start of IFD
+ << ", is before start of buffer by "
+ << std::dec << -1 * (i->offset_ + shift)
+ << " Bytes\n";
+#endif
+ rc = 6;
+ }
+ else if (i->offset_ + shift + i->size_ > len) {
+#ifndef SUPPRESS_WARNINGS
+ std::cerr << "Error: Upper boundary of the 1st data entry of "
+ << ExifTags::ifdName(ifdId_)
+ << " is out of bounds:\n"
+ << " Offset = 0x" << std::setw(8)
+ << std::setfill('0') << std::hex
+ << i->offset_ - offset_ // relative to start of IFD
+ << ", exceeds buffer size by "
+ << std::dec << i->offset_ + shift + i->size_ - len
+ << " Bytes\n";
+#endif
+ rc = 6;
+ }
+ else {
+ dataOffset_ = i->offset_;
+ }
+ }
+ }
+ // Convert the pre-IFD entries to the actual entries, assign the data
+ // to each IFD entry and calculate relative offsets, relative to the
+ // start of the IFD
+ if (rc == 0) {
+ entries_.clear();
+ int idx = 0;
+ const Ifd::PreEntries::iterator begin = preEntries.begin();
+ const Ifd::PreEntries::iterator end = preEntries.end();
+ for (Ifd::PreEntries::iterator i = begin; i != end; ++i) {
+ Entry e(alloc_);
+ e.setIfdId(ifdId_);
+ e.setIdx(++idx);
+ e.setTag(i->tag_);
+ long tmpOffset = // still from the start of the TIFF header
+ i->size_ > 4 ? i->offset_ : i->offsetLoc_;
+ if (tmpOffset + shift + i->size_ > len) {
+#ifndef SUPPRESS_WARNINGS
+ std::cerr << "Warning: Upper boundary of data for "
+ << ExifTags::ifdName(ifdId_)
+ << " entry " << static_cast<int>(i - begin)
+ << " is out of bounds:\n"
+ << " Offset = 0x" << std::setw(8)
+ << std::setfill('0') << std::hex
+ << tmpOffset - offset_ // relative to start of IFD
+ << ", size = " << std::dec << i->size_
+ << ", exceeds buffer size by "
+ << tmpOffset + shift + i->size_ - len
+ << " Bytes; Truncating the data.\n";
+#endif
+ // Truncate the entry
+ i->size_ = 0;
+ i->count_ = 0;
+ tmpOffset = i->offsetLoc_;
+ }
+ // Set the offset to the data, relative to start of IFD
+ e.setOffset(tmpOffset - offset_);
+ // Set the size to at least for bytes to accomodate offset-data
+#ifndef SUPPRESS_WARNINGS
+ if (i->type_ < 1 || i->type_ > 10 || i->type_ == 6) {
+ std::cerr << "Warning: "
+ << ExifTags::ifdName(ifdId_) << " tag 0x"
+ << std::setw(4) << std::setfill('0') << std::hex
+ << i->tag_ << " has invalid Exif type "
+ << std::dec << i->type_
+ << "; using 7 (undefined).\n";
+ }
+#endif
+ e.setValue(i->type_, i->count_, buf + start + e.offset(),
+ std::max(long(4), i->size_));
+ this->add(e);
+ }
+ }
+ if (!alloc_) pBase_ = const_cast<byte*>(buf + shift);
+ if (rc) this->clear();
+
+ return rc;
+ } // Ifd::read
+
+ Ifd::const_iterator Ifd::findIdx(int idx) const
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByIdx(idx));
+ }
+
+ Ifd::iterator Ifd::findIdx(int idx)
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByIdx(idx));
+ }
+
+ Ifd::const_iterator Ifd::findTag(uint16_t tag) const
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByTag(tag));
+ }
+
+ Ifd::iterator Ifd::findTag(uint16_t tag)
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByTag(tag));
+ }
+
+ void Ifd::sortByTag()
+ {
+ std::sort(entries_.begin(), entries_.end(), cmpEntriesByTag);
+ }
+
+ int Ifd::readSubIfd(
+ Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag
+ ) const
+ {
+ int rc = 0;
+ const_iterator pos = findTag(tag);
+ if (pos != entries_.end()) {
+ long offset = getULong(pos->data(), byteOrder);
+ if (len < offset) {
+ rc = 6;
+ }
+ else {
+ rc = dest.read(buf, len, offset, byteOrder);
+ }
+ }
+ return rc;
+ } // Ifd::readSubIfd
+
+ long Ifd::copy(byte* buf, ByteOrder byteOrder, long offset)
+ {
+ if (entries_.size() == 0 && next_ == 0) return 0;
+ if (offset != 0) offset_ = offset;
+
+ // Add the number of entries to the data buffer
+ us2Data(buf, static_cast<uint16_t>(entries_.size()), byteOrder);
+ long o = 2;
+
+ // Add all directory entries to the data buffer
+ long dataSize = 0;
+ long dataAreaSize = 0;
+ long totalDataSize = 0;
+ const iterator b = entries_.begin();
+ const iterator e = entries_.end();
+ iterator i;
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ totalDataSize += i->size();
+ }
+ }
+ for (i = b; i != e; ++i) {
+ us2Data(buf + o, i->tag(), byteOrder);
+ us2Data(buf + o + 2, i->type(), byteOrder);
+ ul2Data(buf + o + 4, i->count(), byteOrder);
+ if (i->sizeDataArea() > 0) {
+ long dataAreaOffset = offset_+size()+totalDataSize+dataAreaSize;
+ i->setDataAreaOffsets(dataAreaOffset, byteOrder);
+ dataAreaSize += i->sizeDataArea();
+ }
+ if (i->size() > 4) {
+ // Set the offset of the entry, data immediately follows the IFD
+ i->setOffset(size() + dataSize);
+ l2Data(buf + o + 8, offset_ + i->offset(), byteOrder);
+ dataSize += i->size();
+ }
+ else {
+ // Copy data into the offset field
+ memset(buf + o + 8, 0x0, 4);
+ memcpy(buf + o + 8, i->data(), i->size());
+ }
+ o += 12;
+ }
+
+ if (hasNext_) {
+ // Add the offset to the next IFD to the data buffer
+ if (pNext_) {
+ memcpy(buf + o, pNext_, 4);
+ }
+ else {
+ memset(buf + o, 0x0, 4);
+ }
+ o += 4;
+ }
+
+ // Add the data of all IFD entries to the data buffer
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ memcpy(buf + o, i->data(), i->size());
+ o += i->size();
+ }
+ }
+
+ // Add all data areas to the data buffer
+ for (i = b; i != e; ++i) {
+ if (i->sizeDataArea() > 0) {
+ memcpy(buf + o, i->dataArea(), i->sizeDataArea());
+ o += i->sizeDataArea();
+ }
+ }
+
+ return o;
+ } // Ifd::copy
+
+ void Ifd::clear()
+ {
+ entries_.clear();
+ offset_ = 0;
+ dataOffset_ = 0;
+ if (hasNext_) {
+ if (alloc_) {
+ memset(pNext_, 0x0, 4);
+ }
+ else {
+ pBase_ = 0;
+ pNext_ = 0;
+ }
+ next_ = 0;
+ }
+ } // Ifd::clear
+
+ void Ifd::setNext(uint32_t next, ByteOrder byteOrder)
+ {
+ if (hasNext_) {
+ assert(pNext_);
+ ul2Data(pNext_, next, byteOrder);
+ next_ = next;
+ }
+ }
+
+ void Ifd::add(const Entry& entry)
+ {
+ assert(alloc_ == entry.alloc());
+ assert(ifdId_ == entry.ifdId());
+ // allow duplicates
+ entries_.push_back(entry);
+ }
+
+ int Ifd::erase(uint16_t tag)
+ {
+ int idx = 0;
+ iterator pos = findTag(tag);
+ if (pos != end()) {
+ idx = pos->idx();
+ erase(pos);
+ }
+ return idx;
+ }
+
+ Ifd::iterator Ifd::erase(iterator pos)
+ {
+ return entries_.erase(pos);
+ }
+
+ byte* Ifd::updateBase(byte* pNewBase)
+ {
+ byte *pOld = 0;
+ if (!alloc_) {
+ iterator end = this->end();
+ for (iterator pos = begin(); pos != end; ++pos) {
+ pos->updateBase(pBase_, pNewBase);
+ }
+ if (hasNext_) {
+ pNext_ = pNext_ - pBase_ + pNewBase;
+ }
+ pOld = pBase_;
+ pBase_ = pNewBase;
+ }
+ return pOld;
+ }
+
+ long Ifd::size() const
+ {
+ if (entries_.size() == 0 && next_ == 0) return 0;
+ return static_cast<long>(2 + 12 * entries_.size() + (hasNext_ ? 4 : 0));
+ }
+
+ long Ifd::dataSize() const
+ {
+ long dataSize = 0;
+ const_iterator end = this->end();
+ for (const_iterator i = begin(); i != end; ++i) {
+ if (i->size() > 4) dataSize += i->size();
+ dataSize += i->sizeDataArea();
+ }
+ return dataSize;
+ }
+
+ void Ifd::print(std::ostream& os, const std::string& prefix) const
+ {
+ if (entries_.size() == 0) return;
+ // Print a header
+ os << prefix << "IFD Offset: 0x"
+ << std::setw(8) << std::setfill('0') << std::hex << std::right
+ << offset_
+ << ", IFD Entries: "
+ << std::setfill(' ') << std::dec << std::right
+ << static_cast<unsigned int>(entries_.size()) << "\n"
+ << prefix << "Entry Tag Format (Bytes each) Number Offset\n"
+ << prefix << "----- ------ --------------------- ------ -----------\n";
+ // Print IFD entries
+ const const_iterator b = entries_.begin();
+ const const_iterator e = entries_.end();
+ const_iterator i = b;
+ for (; i != e; ++i) {
+ std::ostringstream offset;
+ if (i->size() > 4) {
+ offset << " 0x" << std::setw(8) << std::setfill('0')
+ << std::hex << std::right << i->offset();
+ }
+ else {
+ const byte* data = i->data();
+ for (int k = 0; k < i->size(); ++k) {
+ offset << std::setw(2) << std::setfill('0') << std::hex
+ << (int)data[k] << " ";
+ }
+ }
+ os << prefix << std::setw(5) << std::setfill(' ') << std::dec
+ << std::right << static_cast<int>(i - b)
+ << " 0x" << std::setw(4) << std::setfill('0') << std::hex
+ << std::right << i->tag()
+ << " " << std::setw(17) << std::setfill(' ')
+ << std::left << i->typeName()
+ << " (" << std::dec << i->typeSize() << ")"
+ << " " << std::setw(6) << std::setfill(' ') << std::dec
+ << std::right << i->count()
+ << " " << offset.str()
+ << "\n";
+ }
+ if (hasNext_) {
+ os << prefix << "Next IFD: 0x"
+ << std::setw(8) << std::setfill('0') << std::hex
+ << std::right << next() << "\n";
+ }
+ // Print data of IFD entries
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ os << "Data of entry " << static_cast<int>(i - b) << ":\n";
+ hexdump(os, i->data(), i->size(), offset_ + i->offset());
+ }
+ }
+
+ } // Ifd::print
+
+ // *************************************************************************
+ // free functions
+
+ bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.tag() < rhs.tag();
+ }
+
+ bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs)
+ {
+ // We need to ignore entries with size <= 4, so by definition,
+ // entries with size <= 4 are greater than those with size > 4
+ // when compared by their offset.
+ if (lhs.size_ <= 4) {
+ return false; // lhs is greater by definition, or they are equal
+ }
+ if (rhs.size_ <= 4) {
+ return true; // rhs is greater by definition (they cannot be equal)
+ }
+ return lhs.offset_ < rhs.offset_;
+ } // cmpPreEntriesByOffset
+
+} // namespace Exiv2
More information about the pkg-kde-commits
mailing list