[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a

Maximiliano Curia maxy at moszumanska.debian.org
Thu Jul 13 17:35:58 UTC 2017


Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=ff2fdd3

The following commit has been merged in the master branch:
commit ff2fdd3b9f5735eff6780c16687cb49454e8c4ca
Author: Andreas Huggel <ahuggel at gmx.net>
Date:   Sat Jan 31 02:55:20 2004 +0000

    Implemented IFD logic to support "non-intrusive write operations", part 1
---
 src/exif.cpp | 368 ++++++++++++++++++++++++++++++++++++-----------------------
 src/exif.hpp | 238 +++++++++++++++++++++++++++++---------
 2 files changed, 413 insertions(+), 193 deletions(-)

diff --git a/src/exif.cpp b/src/exif.cpp
index 93fb738..ca64094 100644
--- a/src/exif.cpp
+++ b/src/exif.cpp
@@ -20,7 +20,7 @@
  */
 /*
   File:      exif.cpp
-  Version:   $Name:  $ $Revision: 1.11 $
+  Version:   $Name:  $ $Revision: 1.12 $
   Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
   History:   26-Jan-04, ahu: created
  */
@@ -363,104 +363,148 @@ namespace Exif {
         value_->read(buf);
     }
 
-    Ifd::Entry::Entry() 
-        : ifdId_(ifdIdNotSet), ifdIdx_(-1), tag_(0), type_(0), count_(0), 
-          offset_(0), data_(0), size_(0)
+    Ifd::RawEntry::RawEntry()
+        : ifdId_(ifdIdNotSet), ifdIdx_(-1),
+          tag_(0), type_(0), count_(0), offset_(0), size_(0)
     {
+        memset(offsetData_, 0x0, 4);
+    }
+
+    Ifd::Entry::Entry(bool alloc)
+        : alloc_(alloc), status_(valid), ifdId_(ifdIdNotSet), ifdIdx_(-1),
+          tag_(0), type_(0), count_(0), offset_(0), size_(0), data_(0)
+    {
+        memset(offsetData_, 0x0, 4);
+    }
+
+    Ifd::Entry::Entry(const RawEntry& e, char* buf, bool alloc)
+        : alloc_(alloc), status_(valid), ifdId_(e.ifdId_), ifdIdx_(e.ifdIdx_),
+          tag_(e.tag_), type_(e.type_), count_(e.count_), offset_(e.offset_), 
+          size_(e.size_), data_(0)
+    {
+        if (size_ > 4) {
+            if (alloc_) {
+                data_ = new char[size_]; 
+                memcpy(data_, buf + offset_, size_);
+            }
+            else {
+                data_ = buf + offset_;
+            }
+        }
+        else {
+            memcpy(offsetData_, e.offsetData_, 4);
+        }
     }
 
     Ifd::Entry::~Entry()
     {
-        delete[] data_;
+        if (alloc_) delete[] data_;
     }
 
     Ifd::Entry::Entry(const Entry& rhs)
-        : ifdId_(rhs.ifdId_), ifdIdx_(rhs.ifdIdx_), tag_(rhs.tag_),
-          type_(rhs.type_), count_(rhs.count_), offset_(rhs.offset_), 
-          data_(0), size_(rhs.size_)
-    {
-        if (rhs.data_) {
-            data_ = new char[rhs.size_];
-            ::memcpy(data_, rhs.data_, rhs.size_);
+        : alloc_(rhs.alloc_), status_(rhs.status_), ifdId_(rhs.ifdId_),
+          ifdIdx_(rhs.ifdIdx_), tag_(rhs.tag_), type_(rhs.type_), 
+          count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), data_(0)
+    {
+        memcpy(offsetData_, rhs.offsetData_, 4);
+        if (alloc_) {
+            if (rhs.data_) {
+                data_ = new char[rhs.size()];
+                memcpy(data_, rhs.data_, rhs.size());
+            }
+        }
+        else {
+            data_ = rhs.data_;
         }
     }
 
     Ifd::Entry::Entry& Ifd::Entry::operator=(const Entry& rhs)
     {
         if (this == &rhs) return *this;
+        alloc_ = rhs.alloc_;
+        status_ = rhs.status_;
         ifdId_ = rhs.ifdId_;
         ifdIdx_ = rhs.ifdIdx_;
         tag_ = rhs.tag_;
         type_ = rhs.type_;
         count_ = rhs.count_;
         offset_ = rhs.offset_;
-        delete data_;
-        data_ = 0;
-        if (rhs.data_) {
-            data_ = new char[rhs.size_];
-            ::memcpy(data_, rhs.data_, rhs.size_);
-        }
+        memcpy(offsetData_, rhs.offsetData_, 4);
         size_ = rhs.size_;
+        if (alloc_) {
+            delete data_;
+            data_ = 0;
+            if (rhs.data_) {
+                data_ = new char[rhs.size()];
+                memcpy(data_, rhs.data_, rhs.size());
+            }
+        }
+        else {
+            data_ = rhs.data_;
+        }
         return *this;
+    } // Ifd::Entry::operator=
+
+    const char* Ifd::Entry::data() const
+    {
+        if (size_ > 4) return data_;
+        return offsetData_;
     }
 
-    Ifd::Ifd(IfdId ifdId)
-        : ifdId_(ifdId), offset_(0), next_(0)
+    Ifd::Ifd(IfdId ifdId, bool alloc)
+        : alloc_(alloc), ifdId_(ifdId), offset_(0), next_(0)
     {
     }
 
-    int Ifd::read(const char* buf, ByteOrder byteOrder, long offset)
+    int Ifd::read(char* buf, ByteOrder byteOrder, long offset)
     {
         offset_ = offset;
         int n = getUShort(buf, byteOrder);
         long o = 2;
 
-        entries_.clear();
-        for (int i=0; i<n; ++i) {
-            Entry e;
+        // Create an array of raw entries
+        RawEntries rawEntries;
+        for (int i = 0; i < n; ++i) {
+            RawEntry e; 
             e.ifdId_ = ifdId_;
             e.ifdIdx_ = i;
             e.tag_ = getUShort(buf+o, byteOrder);
             e.type_ = getUShort(buf+o+2, byteOrder);
             e.count_ = getULong(buf+o+4, byteOrder);
-            // offset will be converted to a relative offset below
-            e.offset_ = getULong(buf+o+8, byteOrder); 
-            // data_ is set later, see below
-            e.size_ = e.count_ * e.typeSize();
-            entries_.push_back(e);
+            e.size_ = e.count_ * ExifTags::typeSize(TypeId(e.type_));
+            e.offset_ = e.size_ > 4 ? getULong(buf+o+8, byteOrder) : 0;
+            memcpy(e.offsetData_, buf+o+8, 4);
+            rawEntries.push_back(e);
             o += 12;
         }
         next_ = getULong(buf+o, byteOrder);
 
-        // Guess the offset if it was not given. The guess is based 
-        // on the assumption that the smallest offset points to a data 
-        // buffer directly following the IFD.
-        // Subsequently all offsets of IFD entries need to be recalculated.
-        const iterator eb = entries_.begin();
-        const iterator ee = entries_.end();
-        iterator i = eb;
-        if (offset_ == 0 && i != ee) {
+        // Guess the offset of the IFD, if it was not given. The guess is based
+        // on the assumption that the smallest offset points to a data buffer
+        // directly following the IFD. Subsequently all offsets of IFD entries
+        // will need to be recalculated.
+        if (offset_ == 0 && rawEntries.size() > 0) {
             // Find the entry with the smallest offset
-            i = std::min_element(eb, ee, cmpOffset);
-            // Set the guessed IFD offset
+            RawEntries::const_iterator i;
+            i = std::min_element(rawEntries.begin(), rawEntries.end(), cmpOffset);
+            // Set the 'guessed' IFD offset, the test is needed for the case when
+            // all entries have data sizes not exceeding 4.
             if (i->size_ > 4) {
                 offset_ = i->offset_ - size();
             }
         }
 
-        // Assign the values to each IFD entry and
-        // calculate offsets relative to the start of the IFD
-        for (i = eb; i != ee; ++i) {
-            delete[] i->data_;
+        // Convert 'raw' IFD entries to the actual entries, assign the data
+        // to each IFD entry and calculate relative offsets, relative to the
+        // start of the IFD
+        entries_.clear();
+        const RawEntries::iterator begin = rawEntries.begin();
+        const RawEntries::iterator end = rawEntries.end();
+        for (RawEntries::iterator i = begin; i != end; ++i) {
             if (i->size_ > 4) {
                 i->offset_ = i->offset_ - offset_;
-                i->data_ = new char[i->size_];
-                ::memcpy(i->data_, buf + i->offset_, i->size_);
-            }
-            else {
-                i->data_ = new char[4];
-                ul2Data(i->data_, i->offset_, byteOrder);
             }
+            entries_.push_back(Entry(*i, buf, alloc_));
         }
 
         return 0;
@@ -484,13 +528,14 @@ namespace Exif {
     }
 
     int Ifd::readSubIfd(
-        Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag
+        Ifd& dest, char* buf, ByteOrder byteOrder, uint16 tag
     ) const
     {
         int rc = 0;
         const_iterator pos = findTag(tag);
         if (pos != entries_.end()) {
-            rc = dest.read(buf + pos->offset_, byteOrder, pos->offset_);
+            uint32 offset = getULong(pos->data(), byteOrder);
+            rc = dest.read(buf + offset, byteOrder, offset);
         }
         return rc;
     } // Ifd::readSubIfd
@@ -509,15 +554,17 @@ namespace Exif {
         const const_iterator e = entries_.end();
         const_iterator i = b;
         for (; 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->size_ > 4) {
+            us2Data(buf+o, i->tag(), byteOrder);
+            us2Data(buf+o+2, i->type(), byteOrder);
+            ul2Data(buf+o+4, i->count(), byteOrder);
+            if (i->size() > 4) {
+                // Calculate offset, data immediately follows the IFD
                 ul2Data(buf+o+8, offset + size() + dataSize, byteOrder);
-                dataSize += i->size_;
+                dataSize += i->size();
             }
             else {
-                ::memcpy(buf+o+8, i->data_, 4);
+                // Copy data into the offset field
+                ::memcpy(buf+o+8, i->data(), 4);
             }
             o += 12;
         }
@@ -534,9 +581,9 @@ namespace Exif {
 
         // 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_;
+            if (i->size() > 4) {
+                ::memcpy(buf + o, i->data(), i->size());
+                o += i->size();
             }
         }
 
@@ -557,32 +604,44 @@ namespace Exif {
 
     void Ifd::add(const Metadatum& metadatum, ByteOrder byteOrder)
     {
-        Entry e;
+        // Todo: Implement Assert (Stroustup 24.3.7.2)
+        if (!alloc_) throw Error("Invariant violated in Ifd::add");
+
+        RawEntry e;
         e.ifdId_ = metadatum.ifdId();
         e.ifdIdx_ = metadatum.ifdIdx();
         e.tag_ = metadatum.tag();
         e.type_ = metadatum.typeId();
         e.count_ = metadatum.count();
-        e.offset_ = 0; // will be calculated when the IFD is written
-        long len = std::max(metadatum.size(), long(4));
-        e.data_ = new char[len];
-        ::memset(e.data_, 0x0, len);
-        metadatum.copy(e.data_, byteOrder);
         e.size_ = metadatum.size();
-
+        e.offset_ = 0;  // will be calculated when the IFD is written
+        char* buf = 0;
+        if (e.size_ > 4) {
+            buf = new char[e.size_];
+            metadatum.copy(buf, byteOrder);
+        }
+        else {
+            metadatum.copy(e.offsetData_, byteOrder);
+        }
         erase(metadatum.tag());
-        entries_.push_back(e);        
+        entries_.push_back(Entry(e, buf, alloc_));
+        delete[] buf;
     }
 
     void Ifd::erase(uint16 tag)
     {
         iterator pos = findTag(tag);
-        if (pos != end()) erase(pos); 
+        if (pos != end()) erase(pos);
     }
 
     void Ifd::erase(iterator pos)
     {
-        entries_.erase(pos);
+        if (alloc_) {
+            entries_.erase(pos);
+        } 
+        else {
+            pos->setStatus(Entry::erased);
+        }
     }
 
     long Ifd::dataSize() const
@@ -590,7 +649,7 @@ namespace Exif {
         long dataSize = 0;
         const_iterator end = this->end();
         for (const_iterator i = begin(); i != end; ++i) {
-            if (i->size_ > 4) dataSize += i->size_;
+            if (i->size() > 4) dataSize += i->size();
         }
         return dataSize;
     }
@@ -598,7 +657,7 @@ namespace Exif {
     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_ 
@@ -607,47 +666,47 @@ namespace Exif {
            << entries_.size() << "
"
            << prefix << "Entry     Tag  Format   (Bytes each)  Number  Offset
"
            << prefix << "-----  ------  ---------------------  ------  -----------
";
-
+        // 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) {
+            if (i->size() > 4) {
+                offset << " 0x" << std::setw(8) << std::setfill('0') 
+                       << std::hex << std::right << i->offset();
+            }
+            else {
+                unsigned char* data = (unsigned char*)i->data();
                 offset << std::setw(2) << std::setfill('0') << std::hex
-                       << (int)*(unsigned char*)i->data_ << " "
+                       << (int)data[0] << " "
                        << std::setw(2) << std::setfill('0') << std::hex
-                       << (int)*(unsigned char*)(i->data_+1) << " "
+                       << (int)data[1] << " "
                        << std::setw(2) << std::setfill('0') << std::hex
-                       << (int)*(unsigned char*)(i->data_+2) << " "
+                       << (int)data[2] << " "
                        << std::setw(2) << std::setfill('0') << std::hex
-                       << (int)*(unsigned char*)(i->data_+3) << " ";
-            }
-            else {
-                offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex
-                       << std::right << i->offset_;
+                       << (int)data[3] << " ";
             }
-
             os << prefix << std::setw(5) << std::setfill(' ') << std::dec
                << std::right << i - b
                << "  0x" << std::setw(4) << std::setfill('0') << std::hex 
-               << std::right << i->tag_ 
+               << 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_
+               << std::right << i->count()
                << "  " << offset.str()
                << "
";
         }
         os << prefix << "Next IFD: 0x" 
            << std::setw(8) << std::setfill('0') << std::hex
            << std::right << next_ << "
";
-
+        // Print data of IFD entries 
         for (i = b; i != e; ++i) {
-            if (i->size_ > 4) {
-                os << "Data of entry " << i-b << ":
";
-                hexdump(os, i->data_, i->size_);
+            if (i->size() > 4) {
+                os << "Data of entry " << i - b << ":
";
+                hexdump(os, i->data(), i->size());
             }
         }
 
@@ -691,7 +750,7 @@ namespace Exif {
                                  ByteOrder byteOrder)
     {
         char* data = new char[64*1024];     // temporary buffer Todo: handle larger
-        ::memset(data, 0x0, 64*1024);       // images (which violate the Exif Std)
+        memset(data, 0x0, 64*1024);         // images (which violate the Exif Std)
         long len = 0;                       // number of bytes in the buffer
 
         // Copy the TIFF header
@@ -721,7 +780,7 @@ namespace Exif {
         for (long k = 0; k < offsets->count(); ++k) {
             long offset = offsets->toLong(k);
             long size = sizes->toLong(k);
-            ::memcpy(data + len, buf + offset, size);
+            memcpy(data + len, buf + offset, size);
             os << len << " ";
             len += size;
         }
@@ -731,6 +790,9 @@ namespace Exif {
         newOffsets.setValue(os.str());
         ifd1.add(newOffsets, tiffHeader.byteOrder());
 
+// ahu: Todo: remove this
+        ifd1.print(std::cout);
+
         // Finally, sort and copy the IFD
         ifd1.sortByTag();
         ifd1.copy(data + ifdOffset, tiffHeader.byteOrder(), ifdOffset);
@@ -742,7 +804,6 @@ namespace Exif {
         return 0;
     }
 
-
     int Thumbnail::write(const std::string& path) const
     {
         std::string p;
@@ -761,84 +822,109 @@ namespace Exif {
         return 0;
     }
 
+    ExifData::ExifData() 
+        : ifd0_(ifd0, false), exifIfd_(exifIfd, false), iopIfd_(iopIfd, false), 
+          gpsIfd_(gpsIfd, false), ifd1_(ifd1, false), valid_(false), 
+          size_(0), data_(0)
+    {
+    }
+
+    ExifData::~ExifData()
+    {
+        delete[] data_;
+    }
+
     int ExifData::read(const std::string& path)
     {
         JpegImage img;
         int rc = img.readExifData(path);
         if (rc) return rc;
-        offset_ = img.offsetExifData();
         return read(img.exifData(), img.sizeExifData());
     }
 
     int ExifData::read(const char* buf, long len)
     {
-        int rc = tiffHeader_.read(buf);
+        // Copy the data buffer
+        delete[] data_;
+        data_ = new char[len];
+        ::memcpy(data_, buf, len);
+        size_ = len;
+        valid_ = true;
+
+        // Read the TIFF header
+        int ret = 0;
+        int rc = tiffHeader_.read(data_);
         if (rc) return rc;
 
         // Read IFD0
-        Ifd ifd0(ifd0);
-        rc = ifd0.read(buf + tiffHeader_.offset(), 
-                       byteOrder(), 
-                       tiffHeader_.offset());
+        rc = ifd0_.read(data_ + tiffHeader_.offset(), 
+                        byteOrder(), 
+                        tiffHeader_.offset());
         if (rc) return rc;
-
         // Find and read ExifIFD sub-IFD of IFD0
-        Ifd exifIfd(exifIfd);
-        rc = ifd0.readSubIfd(exifIfd, buf, byteOrder(), 0x8769);
+        rc = ifd0_.readSubIfd(exifIfd_, data_, byteOrder(), 0x8769);
         if (rc) return rc;
-
         // Find and read Interoperability IFD in ExifIFD
-        Ifd iopIfd(iopIfd);
-        rc = exifIfd.readSubIfd(iopIfd, buf, byteOrder(), 0xa005);
+        rc = exifIfd_.readSubIfd(iopIfd_, data_, byteOrder(), 0xa005);
         if (rc) return rc;
-
         // Find and read GPSInfo sub-IFD in IFD0
-        Ifd gpsIfd(gpsIfd);
-        rc = ifd0.readSubIfd(gpsIfd, buf, byteOrder(), 0x8825);
+        rc = ifd0_.readSubIfd(gpsIfd_, data_, byteOrder(), 0x8825);
         if (rc) return rc;
-
         // Read IFD1
-        Ifd ifd1(ifd1);
-        if (ifd0.next()) {
-            rc = ifd1.read(buf + ifd0.next(), byteOrder(), ifd0.next());
+        if (ifd0_.next()) {
+            rc = ifd1_.read(data_ + ifd0_.next(), byteOrder(), ifd0_.next());
             if (rc) return rc;
         }
 
-        // Find and read ExifIFD sub-IFD of IFD1
-        Ifd ifd1ExifIfd(ifd1ExifIfd);
-        rc = ifd1.readSubIfd(ifd1ExifIfd, buf, byteOrder(), 0x8769);
-        if (rc) return rc;
-
-        // Find and read Interoperability IFD in ExifIFD of IFD1
-        Ifd ifd1IopIfd(ifd1IopIfd);
-        rc = ifd1ExifIfd.readSubIfd(ifd1IopIfd, buf, byteOrder(), 0xa005);
-        if (rc) return rc;
-
-        // Find and read GPSInfo sub-IFD in IFD1
-        Ifd ifd1GpsIfd(ifd1GpsIfd);
-        rc = ifd1.readSubIfd(ifd1GpsIfd, buf, byteOrder(), 0x8825);
-        if (rc) return rc;
+        // Find and delete ExifIFD sub-IFD of IFD1
+        Ifd::iterator pos = ifd1_.findTag(0x8769);
+        if (pos != ifd1_.end()) {
+            ifd1_.erase(pos);
+            ret = -99;
+        }
+        // Find and delete GPSInfo sub-IFD in IFD1
+        pos = ifd1_.findTag(0x8825);
+        if (pos != ifd1_.end()) {
+            ifd1_.erase(pos);
+            ret = -99;
+        }
 
         // Copy all entries from the IFDs to the internal metadata
         metadata_.clear();
-        add(ifd0.begin(), ifd0.end(), byteOrder());
-        add(exifIfd.begin(), exifIfd.end(), byteOrder());
-        add(iopIfd.begin(), iopIfd.end(), byteOrder()); 
-        add(gpsIfd.begin(), gpsIfd.end(), byteOrder());
-        add(ifd1.begin(), ifd1.end(), byteOrder());
-        add(ifd1ExifIfd.begin(), ifd1ExifIfd.end(), byteOrder());
-        add(ifd1IopIfd.begin(), ifd1IopIfd.end(), byteOrder());
-        add(ifd1GpsIfd.begin(), ifd1GpsIfd.end(), byteOrder());
+        add(ifd0_.begin(), ifd0_.end(), byteOrder());
+        add(exifIfd_.begin(), exifIfd_.end(), byteOrder());
+        add(iopIfd_.begin(), iopIfd_.end(), byteOrder()); 
+        add(gpsIfd_.begin(), gpsIfd_.end(), byteOrder());
+        add(ifd1_.begin(), ifd1_.end(), byteOrder());
 
         // Read the thumbnail
-        thumbnail_.read(buf, *this, byteOrder());
+        thumbnail_.read(data_, *this, byteOrder());
 
-        return 0;
+        return ret;
     } // ExifData::read
 
     long ExifData::copy(char* buf) const
     {
-        // Todo: implement me!
+        // Todo: decide if we can just dump the buffer that we 
+        //       should have somewhere
+
+        // Copy the TIFF header
+        // Todo: What about the offset??
+//         len += tiffHeader_.copy(buf);
+
+//         // Create IFD (without Exif and GPS tags) from metadata
+//         Ifd ifd1(ifd1);
+//         ifd1.add(exifData.begin(), exifData.end(), tiffHeader.byteOrder());
+//         Ifd::iterator i = ifd1.findTag(0x8769);
+//         if (i != ifd1.end()) ifd1.erase(i);
+//         i = ifd1.findTag(0x8825);
+//         if (i != ifd1.end()) ifd1.erase(i);
+
+        // Copy all IFDs
+
+
+        // Copy thumbnail data
+
         return 0;
     }
 
@@ -854,9 +940,9 @@ namespace Exif {
     {
         Ifd::const_iterator i = begin;
         for (; i != end; ++i) {
-            Value* value = Value::create(TypeId(i->type_));
-            value->read(i->data_, i->size_, byteOrder);
-            Metadatum md(i->tag_, i->type_, i->ifdId_, i->ifdIdx_, value);
+            Value* value = Value::create(TypeId(i->type()));
+            value->read(i->data(), i->size(), byteOrder);
+            Metadatum md(i->tag(), i->type(), i->ifdId(), i->ifdIdx(), value);
             delete value;
             add(md);
         }
@@ -1059,7 +1145,7 @@ namespace Exif {
         os << std::dec << std::setfill(' ');
     }
 
-    bool cmpOffset(const Ifd::Entry& lhs, const Ifd::Entry& rhs)
+    bool cmpOffset(const Ifd::RawEntry& lhs, const Ifd::RawEntry& rhs)
     {
         // We need to ignore entries with size <= 4, so by definition,
         // entries with size <= 4 are greater than those with size > 4
@@ -1075,7 +1161,7 @@ namespace Exif {
 
     bool cmpTag(const Ifd::Entry& lhs, const Ifd::Entry& rhs)
     {
-        return lhs.tag_ < rhs.tag_;
+        return lhs.tag() < rhs.tag();
     }
 
 }                                       // namespace Exif
diff --git a/src/exif.hpp b/src/exif.hpp
index 0895e13..2ad3e70 100644
--- a/src/exif.hpp
+++ b/src/exif.hpp
@@ -21,7 +21,7 @@
 /*!
   @file    exif.hpp
   @brief   Encoding and decoding of %Exif data
-  @version $Name:  $ $Revision: 1.12 $
+  @version $Name:  $ $Revision: 1.13 $
   @author  Andreas Huggel (ahu)
            <a href="mailto:ahuggel at gmx.net">ahuggel at gmx.net</a>
   @date    09-Jan-04, ahu: created
@@ -460,9 +460,10 @@ namespace Exif {
           subclass of Value to make use of the interface of the subclass to set
           or modify its contents.
           
-          @return A pointer to a copy (clone) of the value.          
+          @return A pointer to a copy (clone) of the value, 0 if the value is 
+                  not set.
          */
-        Value* getValue() const { return value_->clone(); }
+        Value* getValue() const { return value_ == 0 ? 0 : value_->clone(); }
         //! Return the name of the tag
         const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); }
         //! Return the name of the type
@@ -519,8 +520,7 @@ namespace Exif {
           This method is provided mostly for convenient and versatile output of
           the value which can (to some extent) be formatted through standard
           stream manipulators.  Do not attempt to write to the value through
-          this reference. The behaviour of the method is undefined if value is
-          not set.
+          this reference. 
 
           <b>Example:</b> <br>
           @code
@@ -529,8 +529,12 @@ namespace Exif {
               std::cout << i->key() << " " << std::hex << i->value() << "
";
           }
           @endcode
+
+          @return A constant reference to the value.
+          @throw Error ("Value not set") if the value is not set.
          */
-        const Value& value() const { return *value_; }
+        const Value& value() const 
+            { if (value_) return *value_; throw Error("Value not set"); }
         /*!
           @brief Return a unique key for the tag. The key is of the form
                  'ifdItem.sectionName.tagName'.
@@ -570,29 +574,36 @@ namespace Exif {
     /*!
       @brief Models an IFD (Image File Directory)
 
-      Todo:
-      - make the data handling more intelligent
+      This class operates in two modes, one that allocates and deallocates the
+      memory required to store the data, and one that doesn't perform such
+      memory management and which is suitable in the case where a global data
+      buffer is available and only pointers into this buffer need to be
+      remembered.  Note that the different modes imply completely different copy
+      and 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. Use the default mode (with memory management) if
+      possible. <BR>
+      The mode without memory management is used to make "non-intrusive write
+      support" possible. This allows writing to %Exif data of an image without
+      changing the data layout of the %Exif data, to maximize chances that tag
+      data, which the %Exif reader may not understand (e.g., the Makernote)
+      remains valid. Permitted "non-intrusive write operations" include the
+      modification of tag data without increasing the data size and deletion of
+      entries from an IFD.
     */
     class Ifd {
     public:
-        //! Constructor. Allows to set the IFD identifier.
-        explicit Ifd(IfdId ifdId =ifdIdNotSet);
-
-        //! Data structure for one IFD directory entry
-        struct Entry {
-            Entry();                            //!< Default constructor
-            ~Entry();                           //!< Destructor
-            Entry(const Entry& rhs);            //!< Copy constructor
-            Entry& operator=(const Entry& rhs); //!< Assignment operator
-
-            //! Return the size in bytes of one element of this type
-            long typeSize() const
-                { return ExifTags::typeSize(TypeId(type_)); }
-            //! Return the name of the type
-            const char* typeName() const 
-                { return ExifTags::typeName(TypeId(type_)); }
+        /*!
+          @brief Constructor. Allows to set the IFD identifier and choose
+                 whether or not memory management is required for the Entries.
+         */
+        explicit Ifd(IfdId ifdId =ifdIdNotSet, bool alloc =true);
 
-            //! The IFD id (redundant, it is also at the IFD itself)
+        //! Simple structure for 'raw' IFD directory entries (without the data)
+        struct RawEntry {
+            //! Default constructor
+            RawEntry();
+            //! The IFD id 
             IfdId ifdId_;
             //! Position in the IFD
             int ifdIdx_;
@@ -602,13 +613,124 @@ namespace Exif {
             uint16 type_;
             //! Number of components
             uint32 count_;
-            //! Offset from the start of the IFD
+            //! Offset, unprocessed
             uint32 offset_;
-            //! Pointer to the data buffer
-            char* data_;
-            //! Size of the data buffer in bytes
-            long size_; 
-        }; // struct Entry
+            //! Data from the IFD offset field if size is less or equal to four
+            char offsetData_[4];
+            //! Size of the data in bytes
+            long size_;
+        }; // struct RawEntry
+
+        //! Container type to hold 'raw' IFD directory entries
+        typedef std::vector<RawEntry> RawEntries;
+
+        /*!
+          @brief Data structure for one IFD directory entry. See the description
+                 of class Ifd for an explanation of the supported modes for 
+                 memory allocation.
+         */
+        class Entry {
+        public:
+            /*! 
+              @brief The status of an Entry for entries without memory management.
+
+              <TABLE BORDER=0>
+              <TR><TD>valid:</TD>
+              <TD>The entry is valid, including in particular, the data 
+                  pointed to is valid and up to date.</TD></TR>
+              <TR><TD>invalid:</TD>
+              <TD>The entry is not valid, it has been invalidated by a 
+                  modification of the corresponding metadata, which did not 
+                  fit into the original data buffer.</TD></TR>
+              <TR><TD>erased:</TD>
+              <TD>The entry has been deleted.</TD></TR>
+              </TABLE>
+             */
+            enum Status { valid, invalid, erased };
+
+            /*!
+              @brief Default constructor. The entry allocates memory for its 
+                     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);
+            /*!
+              @brief Constructor to create an %Entry from a raw entry structure
+                     and a data buffer. 
+
+              @param e 'Raw' entry structure filled with the relevant data. The 
+                     offset_ field will only be used if size_ is greater than four.
+              @param buf Character buffer with the data of the tag. If size_ is 
+                     less or equal four, the data from the original IFD offset 
+                     field must be available in the field offsetData_. The buf is
+                     not needed in this case and can be 0.
+              @param alloc Determines if memory management is required. If alloc
+                     is true, a data buffer will be allocated to store data
+                     of more than four bytes, else only the pointer will be 
+                     stored. Data less or equal than four bytes is stored
+                     locally in the %Entry.
+             */
+            Entry(const RawEntry& e, char* buf, bool alloc =true);
+            //! Destructor
+            ~Entry();
+            //! Copy constructor
+            Entry(const Entry& rhs);
+            //! Assignment operator
+            Entry& operator=(const Entry& rhs);
+
+            //! @name Accessors
+            //@{
+            //! Return the status
+            Status status() const { return status_; }
+            //! Return the IFD id
+            IfdId ifdId() const { return ifdId_; }
+            //! Return the index in the IFD
+            int ifdIdx() const { return ifdIdx_; }
+            //! Return the tag
+            uint16 tag() const { return tag_; }
+            //! Return the type id.
+            uint16 type() const { return type_; }
+            //! Return the number of components in the value
+            uint32 count() const { return count_; }
+            //! Return the offset from the start of the IFD
+            uint32 offset() const { return offset_; }
+            //! Return the size of the value in bytes
+            long size() const { return size_; }
+            /*!
+              @brief Return a pointer to the data area. Do not attempt to write
+                     to this pointer.
+             */
+            const char* data() const;
+            //@}
+
+            //! Set the status 
+            void setStatus(Status status) { status_ = status; }
+            //! Return the size in bytes of one element of this type
+            long typeSize() const
+                { return ExifTags::typeSize(TypeId(type_)); }
+            //! Return the name of the type
+            const char* typeName() const 
+                { return ExifTags::typeName(TypeId(type_)); }
+
+        private:
+            /*!
+              @brief True:  requires memory allocation and deallocation,<BR>
+                     False: no memory management needed.
+             */
+            bool alloc_;
+            Status status_;      // Status of this entry
+            IfdId ifdId_;        // Redundant IFD id (it is also at the IFD)
+            int ifdIdx_;         // Position in the IFD
+            uint16 tag_;         // Tag
+            uint16 type_;        // Type
+            uint32 count_;       // Number of components
+            uint32 offset_;      // Offset from the start of the IFD,
+                                 // 0 if size <=4, i.e., if there is no offset
+            char offsetData_[4]; // Data from the offset field if size <= 4
+            long size_;          // Size of the data in bytes
+            char* data_;         // Pointer to the data buffer
+        }; // class Entry
 
         //! Container type to hold all IFD directory entries
         typedef std::vector<Entry> Entries;
@@ -663,7 +785,7 @@ namespace Exif {
               to that of the object.
             */
             bool operator()(const Ifd::Entry& entry) const
-                { return tag_ == entry.tag_; }
+                { return tag_ == entry.tag(); }
         private:
             uint16 tag_;
             
@@ -683,7 +805,7 @@ namespace Exif {
 
           @return 0 if successful
          */
-        int read(const char* buf, ByteOrder byteOrder, long offset =0);
+        int read(char* buf, ByteOrder byteOrder, long offset =0);
         /*!
           @brief Read a sub-IFD from the location pointed to by the directory entry 
                  with the given tag.
@@ -697,7 +819,7 @@ namespace Exif {
           @return 0 if successful
         */
         int readSubIfd(
-            Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag
+            Ifd& dest, char* buf, ByteOrder byteOrder, uint16 tag
         ) const;
         /*!
           @brief Copy the IFD to a data array, returns the number of bytes
@@ -740,17 +862,16 @@ namespace Exif {
         void print(std::ostream& os, const std::string& prefix ="") const;
 
     private:
-        Entries entries_;                // IFD entries
-
-        IfdId ifdId_;                    // IFD Id
-        long offset_;                    // offset of the IFD from the start of 
-                                         // TIFF header
-        long next_;                      // offset of next IFD from the start of 
-                                         // the TIFF header
+        const bool alloc_; // True:  requires memory allocation and deallocation,
+                           // False: no memory management needed.
+        Entries entries_;  // IFD entries
+        IfdId ifdId_;      // IFD Id
+        long offset_;      // offset of the IFD from the start of TIFF header
+        long next_;        // offset of next IFD from the start of the TIFF header
 
     }; // class Ifd
 
-    //! %Thumbnail data Todo: implement this properly
+    //! %Thumbnail data Todo: add, create, rotate, delete
     class Thumbnail {
     public:
         //! %Thumbnail image types
@@ -805,6 +926,10 @@ namespace Exif {
     */
     class ExifData {
     public:
+        //! Default constructor
+        ExifData();
+        //! Destructor
+        ~ExifData();
         /*!
           @brief Read the %Exif data from file path.
           @param path Path to the file
@@ -816,8 +941,8 @@ namespace Exif {
          */
         int read(const std::string& path);
         /*!
-          @brief Read the %Exif data from a character buffer. Assumes that 
-                 the original abs offset of the Exif data is set.
+          @brief Read the %Exif data from a character buffer. The data buffer
+                 must start with the TIFF header.
           @param buf Pointer to the data buffer to read from
           @param len Number of bytes in the data buffer 
           @return 0 if successful
@@ -882,11 +1007,20 @@ namespace Exif {
             { return thumbnail_.write(path); }
 
     private:
-        long offset_;                   // Original abs offset of the Exif data
         TiffHeader tiffHeader_;
         Metadata metadata_;
         Thumbnail thumbnail_;
-        
+
+        Ifd ifd0_;
+        Ifd exifIfd_;
+        Ifd iopIfd_;
+        Ifd gpsIfd_;
+        Ifd ifd1_;
+
+        bool valid_;                      // Flag if data buffer is valid
+        long size_;                       // Size of the Exif raw data in bytes
+        char* data_;                      // Exif raw data buffer
+
     }; // class ExifData
 
 // *****************************************************************************
@@ -940,13 +1074,13 @@ namespace Exif {
     void hexdump(std::ostream& os, const char* buf, long len);
 
     /*! 
-      @brief Compare two IFD entries by offset, taking care of special cases
-             where one or both of the entries don't have an offset.  Return true
-             if the offset of entry lhs is less than that of rhs, else false. By
-             definition, entries without an offset are greater than those with
-             an offset.
+      @brief Compare two 'raw' IFD entries by offset, taking care of special
+             cases where one or both of the entries don't have an offset.
+             Return true if the offset of entry lhs is less than that of rhs,
+             else false. By definition, entries without an offset are greater
+             than those with an offset.
      */
-    bool cmpOffset(const Ifd::Entry& lhs, const Ifd::Entry& rhs);        
+    bool cmpOffset(const Ifd::RawEntry& lhs, const Ifd::RawEntry& rhs);        
     /*!
       @brief Compare two IFD entries by tag. Return true if the tag of entry
              lhs is less than that of rhs.

-- 
exiv2 packaging



More information about the pkg-kde-commits mailing list