[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