[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a
Maximiliano Curia
maxy at moszumanska.debian.org
Thu Jul 13 17:36:44 UTC 2017
Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=974d5e4
The following commit has been merged in the master branch:
commit 974d5e4637ad34dfa8a0a2ed61620ad34c500e47
Author: Andreas Huggel <ahuggel at gmx.net>
Date: Sun Nov 14 16:33:04 2004 +0000
Added data area concept to Value, ValueType, Entry, Ifd. Implements feature #395
---
src/Makefile | 2 +-
src/dataarea-test.cpp | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/exif.cpp | 29 ++++++--
src/exif.hpp | 35 +++++++++-
src/ifd.cpp | 121 ++++++++++++++++++++++++++++++++--
src/ifd.hpp | 76 +++++++++++++++++----
src/types.cpp | 36 +++++++++-
src/types.hpp | 62 ++++++++++++++----
src/value.hpp | 112 +++++++++++++++++++++++++++++--
9 files changed, 605 insertions(+), 46 deletions(-)
diff --git a/src/Makefile b/src/Makefile
index c784a8f..a11ed20 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -58,7 +58,7 @@ CCSRC = canonmn.cpp datasets.cpp exif.cpp fujimn.cpp ifd.cpp image.cpp iptc.cpp
# Add source files of simple applications to this list
BINSRC = addmoddel.cpp exifcomment.cpp exifprint.cpp ifd-test.cpp iptcprint.cpp \
iptctest.cpp key-test.cpp makernote-test.cpp taglist.cpp write-test.cpp \
- write2-test.cpp
+ write2-test.cpp dataarea-test.cpp
# State the main source file of the Exiv2 application here
EXIV2MAIN = exiv2.cpp
diff --git a/src/dataarea-test.cpp b/src/dataarea-test.cpp
new file mode 100644
index 0000000..16295b2
--- /dev/null
+++ b/src/dataarea-test.cpp
@@ -0,0 +1,178 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ Abstract : Tests for dataArea related methods
+
+ File : dataarea-test.cpp
+ Version : $Rev$
+ Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
+ History : 12-Nov-04, ahu: created
+
+ */
+// *****************************************************************************
+// included header files
+#include "exif.hpp"
+#include <iostream>
+#include <iomanip>
+#include <string>
+
+void write(const std::string& file, Exiv2::ExifData& ed);
+void print(const std::string& file);
+int read(const std::string& path);
+
+using namespace Exiv2;
+
+// *****************************************************************************
+// Main
+int main(int argc, char* const argv[])
+{
+try {
+ byte da1[]
+ = { 0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,
+ 0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,
+ 0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,
+ 0xaa,0xbb,0xaa,0xbb,0xaa,0xbb,0xaa,0xbb
+ };
+
+ long len1 = 32;
+
+ byte da2[]
+ = { 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,
+ 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc
+ };
+ long len2 = 16;
+
+ Value::AutoPtr v1 = Value::create(unsignedLong);
+ v1->setDataArea(da1, len1);
+ v1->read("0");
+
+ Value::AutoPtr v2 = Value::create(undefined);
+ v2->read("238 238 238 238 238 238 238 238");
+
+ Value::AutoPtr v3 = Value::create(unsignedShort);
+ v3->setDataArea(da2, len2);
+ v3->read("0 16");
+
+ ExifData ed;
+ ed.add(ExifKey("Exif.Image.Copyright"), v1.get());
+ ed.add(ExifKey("Exif.Image.Software"), v2.get());
+ ed.add(ExifKey("Exif.Image.Artist"), v3.get());
+
+ std::string file("dataarea.exv");
+ std::cout << "Writing file " << file << "
";
+ write(file, ed);
+
+ std::cout << "
Reading IFD from file
";
+ read(file);
+
+ std::cout << "
Reading metadata from file
";
+ print(file);
+
+ return 0;
+}
+catch (Exiv2::Error& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'
";
+ return -1;
+}
+}
+
+void write(const std::string& file, Exiv2::ExifData& ed)
+{
+ int rc = ed.writeExifData(file);
+ if (rc) {
+ std::string error = Exiv2::ExifData::strError(rc, file);
+ throw Exiv2::Error(error);
+ }
+}
+
+void print(const std::string& file)
+{
+ Exiv2::ExifData ed;
+ int rc = ed.read(file);
+ if (rc) {
+ std::string error = Exiv2::ExifData::strError(rc, file);
+ throw Exiv2::Error(error);
+ }
+
+ Exiv2::ExifData::const_iterator end = ed.end();
+ for (Exiv2::ExifData::const_iterator i = ed.begin(); i != end; ++i) {
+ std::cout << std::setw(35) << std::setfill(' ') << std::left
+ << i->key() << " "
+ << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << i->tag() << " "
+ << std::setw(12) << std::setfill(' ') << std::left
+ << i->ifdName() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << i->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << i->count() << " "
+ << std::dec << i->value()
+ << "
";
+
+ }
+}
+
+int read(const std::string& path)
+{
+ Image::AutoPtr image = ImageFactory::instance().open(path);
+ assert(image.get() != 0);
+
+ int rc = image->readMetadata();
+ if (rc) return rc;
+ if (image->sizeExifData() > 0) {
+ const byte *pData = image->exifData();
+ long size = image->sizeExifData();
+
+ // Read the TIFF header
+ TiffHeader tiffHeader;
+ rc = tiffHeader.read(pData);
+ if (rc) return rc;
+
+ // Read IFD0
+ Ifd ifd0(ifd0Id);
+ rc = ifd0.read(pData + tiffHeader.offset(),
+ size - tiffHeader.offset(),
+ tiffHeader.byteOrder(),
+ tiffHeader.offset());
+ if (rc) return rc;
+ ifd0.print(std::cout);
+
+ Ifd::const_iterator i = ifd0.findTag(0x8298);
+ assert(i != ifd0.end());
+
+ Value::AutoPtr v = Value::create(TypeId(i->type()));
+ v->read(i->data(), i->count() * i->typeSize(), tiffHeader.byteOrder());
+ v->setDataArea(pData + v->toLong(), 32);
+
+ std::cout << "Value of tag 0x8298: " << std::hex;
+ v->write(std::cout);
+ std::cout << std::endl;
+
+ DataBuf buf = v->dataArea();
+ for (int i = 0; i< buf.size_; ++i) {
+ std::cout << std::hex << (int)buf.pData_[i] << " ";
+ }
+ std::cout << std::endl;
+
+ // --------
+
+ i = ifd0.findTag(0x013b);
+ assert(i != ifd0.end());
+
+ v = Value::create(TypeId(i->type()));
+ v->read(i->data(), i->count() * i->typeSize(), tiffHeader.byteOrder());
+ v->setDataArea(pData + v->toLong(), 16);
+
+ std::cout << "Value of tag 0x013b: ";
+ v->write(std::cout);
+ std::cout << std::endl;
+
+ buf = v->dataArea();
+ for (int i = 0; i< buf.size_; ++i) {
+ std::cout << std::hex << (int)buf.pData_[i] << " ";
+ }
+ std::cout << std::endl;
+
+ }
+ return 0;
+}
diff --git a/src/exif.cpp b/src/exif.cpp
index 8102453..b2196d0 100644
--- a/src/exif.cpp
+++ b/src/exif.cpp
@@ -76,8 +76,7 @@ namespace Exiv2 {
Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder)
: key_(ExifKey::AutoPtr(new ExifKey(e)))
{
- value_ = Value::create(TypeId(e.type()));
- value_->read(e.data(), e.count() * e.typeSize(), byteOrder);
+ setValue(e, byteOrder);
}
Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue)
@@ -121,6 +120,7 @@ namespace Exiv2 {
{
value_ = Value::create(TypeId(e.type()));
value_->read(e.data(), e.count() * e.typeSize(), byteOrder);
+ value_->setDataArea(e.dataArea(), e.sizeDataArea());
}
void Exifdatum::setValue(const std::string& buf)
@@ -165,9 +165,10 @@ namespace Exiv2 {
tiffHeader_.byteOrder(), tiffHeader_.offset());
}
offset_ = rhs.offset_;
- size_ = rhs.size_;
delete[] pImage_;
- pImage_ = newImage.release();
+ std::pair<byte*, long> p = newImage.release();
+ pImage_ = p.first;
+ size_ = p.second;
return *this;
}
@@ -386,9 +387,10 @@ namespace Exiv2 {
memcpy(newImage.pData_, rhs.pImage_, rhs.size_);
}
offset_ = rhs.offset_;
- size_ = rhs.size_;
delete[] pImage_;
- pImage_ = newImage.release();
+ std::pair<byte*, long> p = newImage.release();
+ pImage_ = p.first;
+ size_ = p.second;
return *this;
}
@@ -819,6 +821,7 @@ namespace Exiv2 {
const_iterator mdEnd = this->end();
for (const_iterator md = begin(); md != mdEnd; ++md) {
size += md->size();
+ size += md->sizeDataArea();
ifdEntries[md->ifdId()] += 1;
}
std::map<IfdId, int>::const_iterator eEnd = ifdEntries.end();
@@ -1060,6 +1063,10 @@ namespace Exiv2 {
md->copy(buf.pData_, byteOrder);
entry->setValue(static_cast<uint16_t>(md->typeId()), md->count(),
buf.pData_, md->size());
+
+ // Todo: Do this with less copying...
+ DataBuf dataArea(md->dataArea());
+ entry->setDataArea(dataArea.pData_, dataArea.size_);
}
}
return compatible;
@@ -1215,7 +1222,11 @@ namespace Exiv2 {
DataBuf buf(md.size());
md.copy(buf.pData_, byteOrder);
e.setValue(static_cast<uint16_t>(md.typeId()), md.count(),
- buf.pData_, md.size());
+ buf.pData_, buf.size_);
+
+ DataBuf dataArea(md.dataArea());
+ e.setDataArea(dataArea.pData_, dataArea.size_);
+
ifd.add(e);
} // addToIfd
@@ -1246,6 +1257,10 @@ namespace Exiv2 {
md.copy(buf.pData_, byteOrder);
e.setValue(static_cast<uint16_t>(md.typeId()), md.count(),
buf.pData_, md.size());
+
+ DataBuf dataArea(md.dataArea());
+ e.setDataArea(dataArea.pData_, dataArea.size_);
+
makerNote->add(e);
} // addToMakerNote
diff --git a/src/exif.hpp b/src/exif.hpp
index d442b6c..9dc870f 100644
--- a/src/exif.hpp
+++ b/src/exif.hpp
@@ -104,10 +104,25 @@ namespace Exiv2 {
void setValue(const Entry& e, ByteOrder byteOrder);
/*!
@brief Set the value to the string buf.
- Uses Value::read(const std::string& buf). If the Exifdatum does
+ Uses Value::read(const std::string& buf). If the %Exifdatum does
not have a value yet, then an AsciiValue is created.
*/
void setValue(const std::string& buf);
+ /*!
+ @brief Set the data area by copying (cloning) the buffer pointed to
+ by buf.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to set such
+ a data area.
+
+ @param buf Pointer to the source data area
+ @param len Size of the data area
+ @return Return -1 if the %Exifdatum does not have a value yet or the
+ value has no data area, else 0.
+ */
+ int setDataArea(const byte* buf, long len)
+ { return value_.get() == 0 ? -1 : value_->setDataArea(buf, len); }
//@}
//! @name Accessors
@@ -227,6 +242,24 @@ namespace Exiv2 {
*/
const Value& value() const
{ if (value_.get() != 0) return *value_; throw Error("Value not set"); }
+ //! Return the size of the data area.
+ long sizeDataArea() const
+ { return value_.get() == 0 ? 0 : value_->sizeDataArea(); }
+ /*!
+ @brief Return a copy of the data area of the value. The caller owns
+ this copy and DataBuf ensures that it will be deleted.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to access
+ such a data area.
+
+ @return A DataBuf containing a copy of the data area or an empty
+ DataBuf if the value does not have a data area assigned or the
+ value is not set.
+ */
+ DataBuf dataArea() const
+ { return value_.get() == 0 ? DataBuf(0, 0) : value_->dataArea(); }
+
//@}
private:
diff --git a/src/ifd.cpp b/src/ifd.cpp
index 6602c30..a736071 100644
--- a/src/ifd.cpp
+++ b/src/ifd.cpp
@@ -51,29 +51,39 @@ namespace Exiv2 {
Entry::Entry(bool alloc)
: alloc_(alloc), ifdId_(ifdIdNotSet), idx_(0), pMakerNote_(0),
- tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0)
+ tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0),
+ sizeDataArea_(0), pDataArea_(0)
{
}
Entry::~Entry()
{
- if (alloc_) delete[] pData_;
+ if (alloc_) {
+ delete[] pData_;
+ delete[] pDataArea_;
+ }
// do *not* delete the MakerNote
}
Entry::Entry(const Entry& rhs)
: alloc_(rhs.alloc_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
pMakerNote_(rhs.pMakerNote_), tag_(rhs.tag_), type_(rhs.type_),
- count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(0)
+ count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(0),
+ sizeDataArea_(rhs.sizeDataArea_), pDataArea_(0)
{
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_;
}
}
@@ -89,6 +99,7 @@ namespace Exiv2 {
count_ = rhs.count_;
offset_ = rhs.offset_;
size_ = rhs.size_;
+ sizeDataArea_ = rhs.sizeDataArea_;
if (alloc_) {
delete[] pData_;
pData_ = 0;
@@ -96,9 +107,16 @@ namespace Exiv2 {
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=
@@ -149,6 +167,78 @@ namespace Exiv2 {
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 (len > sizeDataArea_) throw Error("Value too large");
+ 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("Offset out of range");
+ }
+ 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("Offset out of range");
+ 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("Unsupported data area offset type");
+ break;
+ }
+ }
+ } // Entry::setDataAreaOffsets
+
const byte* Entry::component(uint32_t n) const
{
if (n >= count()) return 0;
@@ -383,13 +473,25 @@ namespace Exiv2 {
// 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 = b;
- for (; i != e; ++i) {
+ 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);
@@ -421,6 +523,14 @@ namespace Exiv2 {
}
}
+ // 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
@@ -481,6 +591,7 @@ namespace Exiv2 {
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;
}
diff --git a/src/ifd.hpp b/src/ifd.hpp
index 0ae9671..22c0b10 100644
--- a/src/ifd.hpp
+++ b/src/ifd.hpp
@@ -64,7 +64,7 @@ namespace Exiv2 {
data if alloc is true (the default), otherwise it remembers
just the pointers into a read and writeable data buffer which
it doesn't allocate or delete.
- */
+ */
explicit Entry(bool alloc =true);
//! Destructor
~Entry();
@@ -98,7 +98,10 @@ namespace Exiv2 {
contains a pointer to the Exif IFD).
<BR>This method cannot be used to set the value of a newly created
%Entry in non-alloc mode.
- */
+
+ @note This method is now deprecated, use data area related methods
+ instead.
+ */
void setValue(uint32_t data, ByteOrder byteOrder);
/*!
@brief Set type, count, the data buffer and its size.
@@ -115,7 +118,7 @@ namespace Exiv2 {
will be as indicated in the size argument. I.e., it is possible to
allocate (set) a data buffer larger than required to hold count
components of the given type.
-
+
@param type The type of the data.
@param count Number of components in the buffer.
@param data Pointer to the data buffer.
@@ -127,6 +130,33 @@ namespace Exiv2 {
count components of the given type.
*/
void setValue(uint16_t type, uint32_t count, const byte* data, long size);
+ /*!
+ @brief Set the data area. Memory management as for
+ setValue(uint16_t, uint32_t, const byte*, long)
+
+ For certain tags the regular value of an IFD entry is an offset to a
+ data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
+ (Exif.Image.ExifTag) or tag 0x0201 in IFD1
+ (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
+ to a data area containing the Exif IFD. That of JPEGInterchangeFormat
+ contains the JPEG thumbnail image.
+ This method sets the data area of a tag in accordance with the memory
+ allocation mode.
+
+ @param buf Pointer to the data area.
+ @param len Size of the data area.
+ */
+ void setDataArea(const byte* buf, long len);
+ /*!
+ @brief Set the offset(s) to the data area of an entry.
+
+ Add @em offset to each data component of the entry. This is used by
+ Ifd::copy to convert the data components of an entry containing
+ offsets relative to the data area to become offsets from the start of
+ the TIFF header. Usually, entries with a data area have exactly one
+ unsigned long data component, which is 0.
+ */
+ void setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder);
//@}
//! @name Accessors
@@ -158,9 +188,9 @@ namespace Exiv2 {
//! Return the offset from the start of the IFD to the data of the entry
uint32_t offset() const { return offset_; }
/*!
- @brief Return a pointer to the data area. Do not attempt to write
- to this pointer.
- */
+ @brief Return a pointer to the data buffer. Do not attempt to write
+ to this pointer.
+ */
const byte* data() const { return pData_; }
/*!
@brief Return a pointer to the n-th component, 0 if there is no
@@ -169,6 +199,24 @@ namespace Exiv2 {
const byte* component(uint32_t n) const;
//! Get the memory allocation mode
bool alloc() const { return alloc_; }
+ //! Return the size of the data area.
+ long sizeDataArea() const { return sizeDataArea_; }
+ /*!
+ @brief Return a pointer to the data area. Do not attempt to write to
+ this pointer.
+
+ For certain tags the regular value of an IFD entry is an offset to a
+ data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
+ (Exif.Image.ExifTag) or tag 0x0201 in IFD1
+ (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
+ to a data area containing the Exif IFD. That of JPEGInterchangeFormat
+ contains the JPEG thumbnail image.
+ Use this method to access (read-only) the data area of a tag. Use
+ setDataArea() to write to the data area.
+
+ @return Return a pointer to the data area.
+ */
+ const byte* dataArea() const { return pDataArea_; }
//@}
private:
@@ -176,7 +224,7 @@ namespace Exiv2 {
/*!
True: Requires memory allocation and deallocation,<BR>
False: No memory management needed.
- */
+ */
bool alloc_;
//! Redundant IFD id (it is also at the IFD)
IfdId ifdId_;
@@ -199,6 +247,10 @@ namespace Exiv2 {
long size_;
//! Pointer to the data buffer
byte* pData_;
+ //! Size of the data area
+ long sizeDataArea_;
+ //! Pointer to the data area
+ byte* pDataArea_;
}; // class Entry
@@ -264,7 +316,7 @@ namespace Exiv2 {
assignment behaviours, with the first resulting in entirely separate
classes and the second mode resulting in multiple classes using one
and the same data buffer.
- */
+ */
class Ifd {
//! @name Not implemented
//@{
@@ -444,10 +496,10 @@ namespace Exiv2 {
//! Get the size of this IFD in bytes (IFD only, without data)
long size() const;
/*!
- @brief Return the total size of the data of this IFD in bytes,
- sums the size of all directory entries where size is greater
- than four (i.e., only data that requires memory outside the
- IFD directory entries is counted).
+ @brief Return the total size of the data of this IFD in bytes; sums
+ the size of all directory entries where size is greater than
+ four plus the size of all data areas, i.e., all data that
+ requires memory outside the IFD directory entries is counted.
*/
long dataSize() const;
/*!
diff --git a/src/types.cpp b/src/types.cpp
index 551d6e1..253158a 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -78,6 +78,29 @@ namespace Exiv2 {
return typeInfoTable_[ typeId < lastTypeId ? typeId : 0 ].size_;
}
+ DataBuf::DataBuf(DataBuf& rhs)
+ : pData_(rhs.pData_), size_(rhs.size_)
+ {
+ rhs.release();
+ }
+
+ DataBuf::DataBuf(byte* pData, long size)
+ : pData_(0), size_(0)
+ {
+ if (size > 0) {
+ pData_ = new byte[size];
+ memcpy(pData_, pData, size);
+ size_ = size;
+ }
+ }
+
+ DataBuf& DataBuf::operator=(DataBuf& rhs)
+ {
+ if (this == &rhs) return *this;
+ reset(rhs.release());
+ return *this;
+ }
+
void DataBuf::alloc(long size)
{
if (size > size_) {
@@ -87,14 +110,23 @@ namespace Exiv2 {
}
}
- byte* DataBuf::release()
+ std::pair<byte*, long> DataBuf::release()
{
- byte* p = pData_;
+ std::pair<byte*, long> p = std::make_pair(pData_, size_);
pData_ = 0;
size_ = 0;
return p;
}
+ void DataBuf::reset(std::pair<byte*, long> p)
+ {
+ if (pData_ != p.first) {
+ delete[] pData_;
+ pData_ = p.first;
+ }
+ size_ = p.second;
+ }
+
// *************************************************************************
// free functions
diff --git a/src/types.hpp b/src/types.hpp
index f6221d8..6d5fe5f 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -121,6 +121,18 @@ namespace Exiv2 {
};
/*!
+ @brief Auxiliary type to enable copies and assignments, similar to
+ std::auto_ptr_ref. See http://www.josuttis.com/libbook/auto_ptr.html
+ for a discussion.
+ */
+ struct DataBufRef {
+ //! Constructor
+ DataBufRef(std::pair<byte*, long> rhs) : p(rhs) {}
+ //! Pointer to a byte array and its size
+ std::pair<byte*, long> p;
+ };
+
+ /*!
@brief Utility class containing a character array. All it does is to take
care of memory allocation and deletion. Its primary use is meant to
be as a stack variable in functions that need a temporary data
@@ -128,38 +140,64 @@ namespace Exiv2 {
essentially an std::auto_ptr for a character array. But it isn't...
*/
class DataBuf {
- // Not implemented
- //! Copy constructor
- DataBuf(const DataBuf&);
- //! Assignment operator
- DataBuf& operator=(const DataBuf&);
public:
//! @name Creators
//@{
//! Default constructor
- DataBuf() : size_(0), pData_(0) {}
+ DataBuf() : pData_(0), size_(0) {}
//! Constructor with an initial buffer size
- DataBuf(long size) : size_(size), pData_(new byte[size]) {}
+ explicit DataBuf(long size) : pData_(new byte[size]), size_(size) {}
+ //! Constructor, copies an existing buffer
+ DataBuf(byte* pData, long size);
+ /*!
+ @brief Copy constructor. Transfers the buffer to the newly created
+ object similar to std::auto_ptr, i.e., the original object is
+ modified.
+ */
+ DataBuf(DataBuf& rhs);
//! Destructor, deletes the allocated buffer
~DataBuf() { delete[] pData_; }
//@}
//! @name Manipulators
//@{
+ /*!
+ @brief Assignment operator. Transfers the buffer and releases the
+ buffer at the original object similar to std::auto_ptr, i.e.,
+ the original object is modified.
+ */
+ DataBuf& operator=(DataBuf& rhs);
//! Allocate a data buffer of the given size
void alloc(long size);
/*!
- @brief Release ownership of the buffer to the caller. Returns pointer
- value, resets pData_ and size_ to 0.
+ @brief Release ownership of the buffer to the caller. Returns the
+ buffer as a data pointer and size pair, resets the internal
+ buffer.
*/
- byte* release();
+ std::pair<byte*, long> release();
+ //! Reset value
+ void reset(std::pair<byte*, long> =std::make_pair(0,0));
+ //@}
+
+ /*!
+ @name Conversions
+
+ Special conversions with auxiliary type to enable copies
+ and assignments, similar to those used for std::auto_ptr.
+ See http://www.josuttis.com/libbook/auto_ptr.html for a discussion.
+ */
+ //@{
+ DataBuf(DataBufRef rhs) : pData_(rhs.p.first), size_(rhs.p.second) {}
+ DataBuf& operator=(DataBufRef rhs) { reset(rhs.p); return *this; }
+ operator DataBufRef() { return DataBufRef(release()); }
+ operator DataBuf() { return DataBuf(release()); }
//@}
// DATA
- //! The current size of the buffer
- long size_;
//! Pointer to the buffer, 0 if none has been allocated
byte* pData_;
+ //! The current size of the buffer
+ long size_;
}; // class DataBuf
/*!
diff --git a/src/value.hpp b/src/value.hpp
index 7998972..fbd86a6 100644
--- a/src/value.hpp
+++ b/src/value.hpp
@@ -94,6 +94,19 @@ namespace Exiv2 {
@param buf The string to read from.
*/
virtual void read(const std::string& buf) =0;
+ /*!
+ @brief Set the data area, if the value has one by copying (cloning)
+ the buffer pointed to by buf.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to set such
+ a data area.
+
+ @param buf Pointer to the source data area
+ @param len Size of the data area
+ @return Return -1 if the value has no data area, else 0.
+ */
+ virtual int setDataArea(const byte* buf, long len) { return -1; }
//@}
//! @name Accessors
@@ -157,6 +170,21 @@ namespace Exiv2 {
@return The converted value.
*/
virtual Rational toRational(long n =0) const =0;
+ //! Return the size of the data area, 0 if there is none.
+ virtual long sizeDataArea() const { return 0; }
+ /*!
+ @brief Return a copy of the data area if the value has one. The
+ caller owns this copy and DataBuf ensures that it will be
+ deleted.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to access
+ such a data area.
+
+ @return A DataBuf containing a copy of the data area or an empty
+ DataBuf if the value does not have a data area assigned.
+ */
+ virtual DataBuf dataArea() const { return DataBuf(0, 0); };
//@}
/*!
@@ -702,14 +730,15 @@ namespace Exiv2 {
//! @name Creators
//@{
//! Default constructor.
- ValueType() : Value(getType<T>()) {}
+ ValueType() : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0) {}
//! Constructor
- ValueType(const byte* buf, long len, ByteOrder byteOrder)
- : Value(getType<T>()) { read(buf, len, byteOrder); }
+ ValueType(const byte* buf, long len, ByteOrder byteOrder);
//! Constructor
- ValueType( const T& val, ByteOrder byteOrder =littleEndian);
+ ValueType(const T& val, ByteOrder byteOrder =littleEndian);
+ //! Copy constructor
+ ValueType(const ValueType<T>& rhs);
//! Virtual destructor.
- virtual ~ValueType() {}
+ virtual ~ValueType();
//@}
//! @name Manipulators
@@ -724,6 +753,11 @@ namespace Exiv2 {
produced by the write() method.
*/
virtual void read(const std::string& buf);
+ /*!
+ @brief Set the data area. This method copies (clones) the buffer
+ pointed to by buf.
+ */
+ virtual int setDataArea(const byte* buf, long len);
//@}
//! @name Accessors
@@ -736,6 +770,13 @@ namespace Exiv2 {
virtual long toLong(long n =0) const;
virtual float toFloat(long n =0) const;
virtual Rational toRational(long n =0) const;
+ //! Return the size of the data area.
+ virtual long sizeDataArea() const { return sizeDataArea_; }
+ /*!
+ @brief Return a copy of the data area in a DataBuf. The caller owns
+ this copy and DataBuf ensures that it will be deleted.
+ */
+ virtual DataBuf dataArea() const;
//@}
//! Container for values
@@ -758,6 +799,11 @@ namespace Exiv2 {
//! Internal virtual copy constructor.
virtual ValueType<T>* clone_() const;
+ // DATA
+ //! Pointer to the buffer, 0 if none has been allocated
+ byte* pDataArea_;
+ //! The current size of the buffer
+ long sizeDataArea_;
}; // class ValueType
//! Unsigned short value type
@@ -894,8 +940,15 @@ namespace Exiv2 {
}
template<typename T>
+ ValueType<T>::ValueType(const byte* buf, long len, ByteOrder byteOrder)
+ : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0)
+ {
+ read(buf, len, byteOrder);
+ }
+
+ template<typename T>
ValueType<T>::ValueType(const T& val, ByteOrder byteOrder)
- : Value(getType<T>())
+ : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0)
{
read(reinterpret_cast<const byte*>(&val),
TypeInfo::typeSize(typeId()),
@@ -903,11 +956,38 @@ namespace Exiv2 {
}
template<typename T>
+ ValueType<T>::ValueType(const ValueType<T>& rhs)
+ : Value(rhs), value_(rhs.value_), pDataArea_(0), sizeDataArea_(0)
+ {
+ if (rhs.sizeDataArea_ > 0) {
+ pDataArea_ = new byte[rhs.sizeDataArea_];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea_);
+ sizeDataArea_ = rhs.sizeDataArea_;
+ }
+ }
+
+ template<typename T>
+ ValueType<T>::~ValueType()
+ {
+ delete[] pDataArea_;
+ }
+
+ template<typename T>
ValueType<T>& ValueType<T>::operator=(const ValueType<T>& rhs)
{
if (this == &rhs) return *this;
Value::operator=(rhs);
value_ = rhs.value_;
+
+ byte* tmp = 0;
+ if (rhs.sizeDataArea_ > 0) {
+ tmp = new byte[rhs.sizeDataArea_];
+ memcpy(tmp, rhs.pDataArea_, rhs.sizeDataArea_);
+ }
+ delete[] pDataArea_;
+ pDataArea_ = tmp;
+ sizeDataArea_ = rhs.sizeDataArea_;
+
return *this;
}
@@ -1020,6 +1100,26 @@ namespace Exiv2 {
return Rational(value_[n].first, value_[n].second);
}
+ template<typename T>
+ inline DataBuf ValueType<T>::dataArea() const
+ {
+ return DataBuf(pDataArea_, sizeDataArea_);
+ }
+
+ template<typename T>
+ inline int ValueType<T>::setDataArea(const byte* buf, long len)
+ {
+ byte* tmp = 0;
+ if (len > 0) {
+ tmp = new byte[len];
+ memcpy(tmp, buf, len);
+ }
+ delete[] pDataArea_;
+ pDataArea_ = tmp;
+ sizeDataArea_ = len;
+ return 0;
+ }
+
} // namespace Exiv2
#endif // #ifndef VALUE_HPP_
--
exiv2 packaging
More information about the pkg-kde-commits
mailing list