Blame src/crwimage_int.cpp

Packit 01d647
#include "crwimage_int.hpp"
Packit 01d647
#include "canonmn_int.hpp"
Packit 01d647
#include "i18n.h"                // NLS support.
Packit 01d647
#include "timegm.h"
Packit 01d647
#include "unused.h"
Packit 01d647
#include "error.hpp"
Packit Service fb147c
#include "enforce.hpp"
Packit 01d647
Packit 01d647
#include <cassert>
Packit 01d647
#include <ctime>
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// local declarations
Packit 01d647
namespace {
Packit 01d647
    //! Helper class to map Exif orientation values to CRW rotation degrees
Packit 01d647
    class RotationMap {
Packit 01d647
    public:
Packit 01d647
        //! Get the orientation number for a degree value
Packit 01d647
        static uint16_t orientation(int32_t degrees);
Packit 01d647
        //! Get the degree value for an orientation number
Packit 01d647
        static int32_t  degrees(uint16_t orientation);
Packit 01d647
    private:
Packit 01d647
        //! Helper structure for the mapping list
Packit 01d647
        struct OmList {
Packit 01d647
            uint16_t orientation; //!< Exif orientation value
Packit 01d647
            int32_t  degrees;     //!< CRW Rotation degrees
Packit 01d647
        };
Packit 01d647
        // DATA
Packit 01d647
        static const OmList omList_[];
Packit 01d647
    }; // class RotationMap
Packit 01d647
}
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// local definitions
Packit 01d647
namespace {
Packit 01d647
    //! @cond IGNORE
Packit 01d647
    const RotationMap::OmList RotationMap::omList_[] = {
Packit 01d647
        { 1,    0 },
Packit 01d647
        { 3,  180 },
Packit 01d647
        { 3, -180 },
Packit 01d647
        { 6,   90 },
Packit 01d647
        { 6, -270 },
Packit 01d647
        { 8,  270 },
Packit 01d647
        { 8,  -90 },
Packit 01d647
        // last entry
Packit 01d647
        { 0,    0 }
Packit 01d647
    };
Packit 01d647
Packit 01d647
    uint16_t RotationMap::orientation(int32_t degrees)
Packit 01d647
    {
Packit 01d647
        uint16_t o = 1;
Packit 01d647
        for (int i = 0; omList_[i].orientation != 0; ++i) {
Packit 01d647
            if (omList_[i].degrees == degrees) {
Packit 01d647
                o = omList_[i].orientation;
Packit 01d647
                break;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return o;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int32_t RotationMap::degrees(uint16_t orientation)
Packit 01d647
    {
Packit 01d647
        int32_t d = 0;
Packit 01d647
        for (int i = 0; omList_[i].orientation != 0; ++i) {
Packit 01d647
            if (omList_[i].orientation == orientation) {
Packit 01d647
                d = omList_[i].degrees;
Packit 01d647
                break;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return d;
Packit 01d647
    }
Packit 01d647
    //! @endcond
Packit 01d647
}
Packit 01d647
Packit 01d647
namespace Exiv2 {
Packit 01d647
    namespace Internal {
Packit 01d647
Packit 01d647
    /*
Packit 01d647
      Mapping table used to decode and encode CIFF tags to/from Exif tags.  Only
Packit 01d647
      a subset of the Exif tags can be mapped to known tags found in CRW files
Packit 01d647
      and not all CIFF tags in the CRW files have a corresponding Exif tag. Tags
Packit 01d647
      which are not mapped in the table below are ignored.
Packit 01d647
Packit 01d647
      When decoding, each CIFF tag/directory pair in the CRW image is looked up
Packit 01d647
      in the table and if it has an entry, the corresponding decode function is
Packit 01d647
      called (CrwMap::decode). This function may or may not make use of the
Packit 01d647
      other parameters in the structure (such as the Exif tag and Ifd id).
Packit 01d647
Packit 01d647
      Encoding is done in a loop over the mapping table (CrwMap::encode). For
Packit 01d647
      each entry, the encode function is called, which looks up the (Exif)
Packit 01d647
      metadata to encode in the image. This function may or may not make use of
Packit 01d647
      the other parameters in the mapping structure.
Packit 01d647
    */
Packit 01d647
    const CrwMapping CrwMap::crwMapping_[] = {
Packit 01d647
        //         CrwTag  CrwDir  Size ExifTag IfdId    decodeFct     encodeFct
Packit 01d647
        //         ------  ------  ---- ------- -----    ---------     ---------
Packit 01d647
        CrwMapping(0x0805, 0x300a,   0, 0,      canonId, decode0x0805, encode0x0805),
Packit 01d647
        CrwMapping(0x080a, 0x2807,   0, 0,      canonId, decode0x080a, encode0x080a),
Packit 01d647
        CrwMapping(0x080b, 0x3004,   0, 0x0007, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x0810, 0x2807,   0, 0x0009, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x0815, 0x2804,   0, 0x0006, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x1029, 0x300b,   0, 0x0002, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x102a, 0x300b,   0, 0x0004, canonId, decodeArray,  encodeArray),
Packit 01d647
        CrwMapping(0x102d, 0x300b,   0, 0x0001, canonId, decodeArray,  encodeArray),
Packit 01d647
        CrwMapping(0x1033, 0x300b,   0, 0x000f, canonId, decodeArray,  encodeArray),
Packit 01d647
        CrwMapping(0x1038, 0x300b,   0, 0x0012, canonId, decodeArray,  encodeArray),
Packit 01d647
        CrwMapping(0x10a9, 0x300b,   0, 0x00a9, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        // Mapped to Exif.Photo.ColorSpace instead (see below)
Packit 01d647
        //CrwMapping(0x10b4, 0x300b,   0, 0x00b4, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x10b4, 0x300b,   0, 0xa001, exifId,  decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x10b5, 0x300b,   0, 0x00b5, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x10c0, 0x300b,   0, 0x00c0, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x10c1, 0x300b,   0, 0x00c1, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x1807, 0x3002,   0, 0x9206, exifId,  decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x180b, 0x3004,   0, 0x000c, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x180e, 0x300a,   0, 0x9003, exifId,  decode0x180e, encode0x180e),
Packit 01d647
        CrwMapping(0x1810, 0x300a,   0, 0xa002, exifId,  decode0x1810, encode0x1810),
Packit 01d647
        CrwMapping(0x1817, 0x300a,   4, 0x0008, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        //CrwMapping(0x1818, 0x3002,   0, 0x9204, exifId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x183b, 0x300b,   0, 0x0015, canonId, decodeBasic,  encodeBasic),
Packit 01d647
        CrwMapping(0x2008, 0x0000,   0, 0,      ifd1Id,  decode0x2008, encode0x2008),
Packit 01d647
        // End of list marker
Packit 01d647
        CrwMapping(0x0000, 0x0000,   0, 0x0000, ifdIdNotSet, 0,            0)
Packit 01d647
    }; // CrwMap::crwMapping_[]
Packit 01d647
Packit 01d647
    /*
Packit 01d647
      CIFF directory hierarchy
Packit 01d647
Packit 01d647
                root
Packit 01d647
                 |
Packit 01d647
                300a
Packit 01d647
                 |
Packit 01d647
       +----+----+----+----+
Packit 01d647
       |    |    |    |    |
Packit 01d647
      2804 2807 3002 3003 300b
Packit 01d647
            |
Packit 01d647
           3004
Packit 01d647
Packit 01d647
      The array is arranged bottom-up so that starting with a directory at the
Packit 01d647
      bottom, the (unique) path to root can be determined in a single loop.
Packit 01d647
    */
Packit 01d647
    const CrwSubDir CrwMap::crwSubDir_[] = {
Packit 01d647
        // dir,   parent
Packit 01d647
        { 0x3004, 0x2807 },
Packit 01d647
        { 0x300b, 0x300a },
Packit 01d647
        { 0x3003, 0x300a },
Packit 01d647
        { 0x3002, 0x300a },
Packit 01d647
        { 0x2807, 0x300a },
Packit 01d647
        { 0x2804, 0x300a },
Packit 01d647
        { 0x300a, 0x0000 },
Packit 01d647
        { 0x0000, 0xffff },
Packit 01d647
        // End of list marker
Packit 01d647
        { 0xffff, 0xffff }
Packit 01d647
    };
Packit 01d647
Packit 01d647
    const char CiffHeader::signature_[] = "HEAPCCDR";
Packit 01d647
Packit 01d647
    CiffHeader::~CiffHeader()
Packit 01d647
    {
Packit 01d647
        delete   pRootDir_;
Packit 01d647
        delete[] pPadding_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CiffComponent::~CiffComponent()
Packit 01d647
    {
Packit 01d647
        if (isAllocated_) delete[] pData_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CiffEntry::~CiffEntry()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CiffDirectory::~CiffDirectory()
Packit 01d647
    {
Packit 01d647
        Components::iterator b = components_.begin();
Packit 01d647
        Components::iterator e = components_.end();
Packit 01d647
        for (Components::iterator i = b; i != e; ++i) {
Packit 01d647
            delete *i;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CiffComponent::add(AutoPtr component)
Packit 01d647
    {
Packit 01d647
        doAdd(component);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CiffEntry::doAdd(AutoPtr /*component*/)
Packit 01d647
    {
Packit 01d647
        throw Error(kerFunctionNotSupported, "CiffEntry::add");
Packit 01d647
    } // CiffEntry::doAdd
Packit 01d647
Packit 01d647
    void CiffDirectory::doAdd(AutoPtr component)
Packit 01d647
    {
Packit 01d647
        components_.push_back(component.release());
Packit 01d647
    } // CiffDirectory::doAdd
Packit 01d647
Packit 01d647
    void CiffHeader::read(const byte* pData, uint32_t size)
Packit 01d647
    {
Packit 01d647
        if (size < 14) throw Error(kerNotACrwImage);
Packit 01d647
Packit 01d647
        if (pData[0] == 'I' && pData[0] == pData[1]) {
Packit 01d647
            byteOrder_ = littleEndian;
Packit 01d647
        }
Packit 01d647
        else if (pData[0] == 'M' && pData[0] == pData[1]) {
Packit 01d647
            byteOrder_ = bigEndian;
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            throw Error(kerNotACrwImage);
Packit 01d647
        }
Packit 01d647
        offset_ = getULong(pData + 2, byteOrder_);
Packit 01d647
        if (offset_ < 14 || offset_ > size) throw Error(kerNotACrwImage);
Packit 01d647
        if (std::memcmp(pData + 6, signature(), 8) != 0) {
Packit 01d647
            throw Error(kerNotACrwImage);
Packit 01d647
        }
Packit 01d647
Packit Service fb147c
        delete[] pPadding_;
Packit 01d647
        pPadding_ = new byte[offset_ - 14];
Packit 01d647
        padded_ = offset_ - 14;
Packit 01d647
        std::memcpy(pPadding_, pData + 14, padded_);
Packit 01d647
Packit 01d647
        pRootDir_ = new CiffDirectory;
Packit 01d647
        pRootDir_->readDirectory(pData + offset_, size - offset_, byteOrder_);
Packit 01d647
    } // CiffHeader::read
Packit 01d647
Packit 01d647
    void CiffComponent::read(const byte* pData,
Packit 01d647
                             uint32_t    size,
Packit 01d647
                             uint32_t    start,
Packit 01d647
                             ByteOrder   byteOrder)
Packit 01d647
    {
Packit 01d647
        doRead(pData, size, start, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CiffComponent::doRead(const byte* pData,
Packit 01d647
                               uint32_t    size,
Packit 01d647
                               uint32_t    start,
Packit 01d647
                               ByteOrder   byteOrder)
Packit 01d647
    {
Packit Service fb147c
        // We're going read 10 bytes. Make sure they won't be out-of-bounds.
Packit Service fb147c
        enforce(size >= 10 && start <= size - 10, kerNotACrwImage);
Packit 01d647
        tag_ = getUShort(pData + start, byteOrder);
Packit 01d647
Packit 01d647
        DataLocId dl = dataLocation();
Packit 01d647
        assert(dl == directoryData || dl == valueData);
Packit 01d647
Packit 01d647
        if (dl == valueData) {
Packit 01d647
            size_   = getULong(pData + start + 2, byteOrder);
Packit 01d647
            offset_ = getULong(pData + start + 6, byteOrder);
Packit Service fb147c
Packit Service fb147c
            // Make sure that the sub-region does not overlap with the 10 bytes
Packit Service fb147c
            // that we just read. (Otherwise a malicious file could cause an
Packit Service fb147c
            // infinite recursion.) There are two cases two consider because
Packit Service fb147c
            // the sub-region is allowed to be either before or after the 10
Packit Service fb147c
            // bytes in memory.
Packit Service fb147c
            if (offset_ < start) {
Packit Service fb147c
              // Sub-region is before in memory.
Packit Service fb147c
              enforce(size_ <= start - offset_, kerOffsetOutOfRange);
Packit Service fb147c
            } else {
Packit Service fb147c
              // Sub-region is after in memory.
Packit Service fb147c
              enforce(offset_ >= start + 10, kerOffsetOutOfRange);
Packit Service fb147c
              enforce(offset_ <= size, kerOffsetOutOfRange);
Packit Service fb147c
              enforce(size_ <= size - offset_, kerOffsetOutOfRange);
Packit Service fb147c
            }
Packit 01d647
        }
Packit 01d647
        if (dl == directoryData) {
Packit 01d647
            size_ = 8;
Packit 01d647
            offset_ = start + 2;
Packit 01d647
        }
Packit 01d647
        pData_ = pData + offset_;
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "  Entry for tag 0x"
Packit 01d647
                  << std::hex << tagId() << " (0x" << tag()
Packit 01d647
                  << "), " << std::dec << size_
Packit 01d647
                  << " Bytes, Offset is " << offset_ << "\n";
Packit 01d647
#endif
Packit 01d647
Packit 01d647
    } // CiffComponent::doRead
Packit 01d647
Packit 01d647
    void CiffDirectory::doRead(const byte* pData,
Packit 01d647
                               uint32_t    size,
Packit 01d647
                               uint32_t    start,
Packit 01d647
                               ByteOrder   byteOrder)
Packit 01d647
    {
Packit 01d647
        CiffComponent::doRead(pData, size, start, byteOrder);
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "Reading directory 0x" << std::hex << tag() << "\n";
Packit 01d647
#endif
Packit Service fb147c
        if (this->offset() + this->size() > size)
Packit Service fb147c
            throw Error(kerOffsetOutOfRange);
Packit Service fb147c
Packit 01d647
        readDirectory(pData + offset(), this->size(), byteOrder);
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "<---- 0x" << std::hex << tag() << "\n";
Packit 01d647
#endif
Packit 01d647
    } // CiffDirectory::doRead
Packit 01d647
Packit 01d647
    void CiffDirectory::readDirectory(const byte* pData,
Packit 01d647
                                      uint32_t    size,
Packit 01d647
                                      ByteOrder   byteOrder)
Packit 01d647
    {
Packit 01d647
        if (size < 4)
Packit 01d647
            throw Error(kerCorruptedMetadata);
Packit 01d647
        uint32_t o = getULong(pData + size - 4, byteOrder);
Packit 01d647
        if ( o > size-2 )
Packit 01d647
            throw Error(kerCorruptedMetadata);
Packit 01d647
        uint16_t count = getUShort(pData + o, byteOrder);
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "Directory at offset " << std::dec << o
Packit 01d647
                  <<", " << count << " entries \n";
Packit 01d647
#endif
Packit 01d647
        o += 2;
Packit 01d647
        if ( static_cast<uint32_t>(count) * 10 > size-o )
Packit 01d647
            throw Error(kerCorruptedMetadata);
Packit 01d647
Packit 01d647
        for (uint16_t i = 0; i < count; ++i) {
Packit 01d647
            uint16_t tag = getUShort(pData + o, byteOrder);
Packit 01d647
            CiffComponent::AutoPtr m;
Packit 01d647
            switch (CiffComponent::typeId(tag)) {
Packit 01d647
            case directory: m = CiffComponent::AutoPtr(new CiffDirectory); break;
Packit 01d647
            default: m = CiffComponent::AutoPtr(new CiffEntry); break;
Packit 01d647
            }
Packit 01d647
            m->setDir(this->tag());
Packit 01d647
            m->read(pData, size, o, byteOrder);
Packit 01d647
            add(m);
Packit 01d647
            o += 10;
Packit 01d647
        }
Packit 01d647
    }  // CiffDirectory::readDirectory
Packit 01d647
Packit 01d647
    void CiffHeader::decode(Image& image) const
Packit 01d647
    {
Packit 01d647
        // Nothing to decode from the header itself, just add correct byte order
Packit 01d647
        if (pRootDir_) pRootDir_->decode(image, byteOrder_);
Packit 01d647
    } // CiffHeader::decode
Packit 01d647
Packit 01d647
    void CiffComponent::decode(Image& image, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
        doDecode(image, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CiffEntry::doDecode(Image& image, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
        CrwMap::decode(*this, image, byteOrder);
Packit 01d647
    } // CiffEntry::doDecode
Packit 01d647
Packit 01d647
    void CiffDirectory::doDecode(Image& image, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
        Components::const_iterator b = components_.begin();
Packit 01d647
        Components::const_iterator e = components_.end();
Packit 01d647
        for (Components::const_iterator i = b; i != e; ++i) {
Packit 01d647
            (*i)->decode(image, byteOrder);
Packit 01d647
        }
Packit 01d647
    } // CiffDirectory::doDecode
Packit 01d647
Packit 01d647
    void CiffHeader::write(Blob& blob) const
Packit 01d647
    {
Packit 01d647
        assert(   byteOrder_ == littleEndian
Packit 01d647
               || byteOrder_ == bigEndian);
Packit 01d647
        if (byteOrder_ == littleEndian) {
Packit 01d647
            blob.push_back('I');
Packit 01d647
            blob.push_back('I');
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            blob.push_back('M');
Packit 01d647
            blob.push_back('M');
Packit 01d647
        }
Packit 01d647
        uint32_t o = 2;
Packit 01d647
        byte buf[4];
Packit 01d647
        ul2Data(buf, offset_, byteOrder_);
Packit 01d647
        append(blob, buf, 4);
Packit 01d647
        o += 4;
Packit 01d647
        append(blob, reinterpret_cast<const byte*>(signature_), 8);
Packit 01d647
        o += 8;
Packit 01d647
        // Pad as needed
Packit 01d647
        if (pPadding_) {
Packit 01d647
            assert(padded_ == offset_ - o);
Packit 01d647
            append(blob, pPadding_, padded_);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            for (uint32_t i = o; i < offset_; ++i) {
Packit 01d647
                blob.push_back(0);
Packit 01d647
                ++o;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        if (pRootDir_) {
Packit 01d647
            pRootDir_->write(blob, byteOrder_, offset_);
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint32_t CiffComponent::write(Blob&     blob,
Packit 01d647
                                  ByteOrder byteOrder,
Packit 01d647
                                  uint32_t  offset)
Packit 01d647
    {
Packit 01d647
        return doWrite(blob, byteOrder, offset);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint32_t CiffEntry::doWrite(Blob&     blob,
Packit 01d647
                                ByteOrder /*byteOrder*/,
Packit 01d647
                                uint32_t  offset)
Packit 01d647
    {
Packit 01d647
        return writeValueData(blob, offset);
Packit 01d647
    } // CiffEntry::doWrite
Packit 01d647
Packit 01d647
    uint32_t CiffComponent::writeValueData(Blob& blob, uint32_t offset)
Packit 01d647
    {
Packit 01d647
        if (dataLocation() == valueData) {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
            std::cout << "  Data for tag 0x" << std::hex << tagId()
Packit 01d647
                      << ", " << std::dec << size_ << " Bytes\n";
Packit 01d647
#endif
Packit 01d647
            offset_ = offset;
Packit 01d647
            append(blob, pData_, size_);
Packit 01d647
            offset += size_;
Packit 01d647
            // Pad the value to an even number of bytes
Packit 01d647
            if (size_ % 2 == 1) {
Packit 01d647
                blob.push_back(0);
Packit 01d647
                ++offset;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return offset;
Packit 01d647
    } // CiffComponent::writeValueData
Packit 01d647
Packit 01d647
    uint32_t CiffDirectory::doWrite(Blob&     blob,
Packit 01d647
                                    ByteOrder byteOrder,
Packit 01d647
                                    uint32_t  offset)
Packit 01d647
    {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "Writing directory 0x" << std::hex << tag() << "---->\n";
Packit 01d647
#endif
Packit 01d647
        // Ciff offsets are relative to the start of the directory
Packit 01d647
        uint32_t dirOffset = 0;
Packit 01d647
Packit 01d647
        // Value data
Packit 01d647
        const Components::iterator b = components_.begin();
Packit 01d647
        const Components::iterator e = components_.end();
Packit 01d647
        for (Components::iterator i = b; i != e; ++i) {
Packit 01d647
            dirOffset = (*i)->write(blob, byteOrder, dirOffset);
Packit 01d647
        }
Packit 01d647
        const uint32_t dirStart = dirOffset;
Packit 01d647
Packit 01d647
        // Number of directory entries
Packit 01d647
        byte buf[4];
Packit 01d647
        us2Data(buf, static_cast<uint16_t>(components_.size()), byteOrder);
Packit 01d647
        append(blob, buf, 2);
Packit 01d647
        dirOffset += 2;
Packit 01d647
Packit 01d647
        // Directory entries
Packit 01d647
        for (Components::iterator i = b; i != e; ++i) {
Packit 01d647
            (*i)->writeDirEntry(blob, byteOrder);
Packit 01d647
            dirOffset += 10;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Offset of directory
Packit 01d647
        ul2Data(buf, dirStart, byteOrder);
Packit 01d647
        append(blob, buf, 4);
Packit 01d647
        dirOffset += 4;
Packit 01d647
Packit 01d647
        // Update directory entry
Packit 01d647
        setOffset(offset);
Packit 01d647
        setSize(dirOffset);
Packit 01d647
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "Directory is at offset " << std::dec << dirStart
Packit 01d647
                  << ", " << components_.size() << " entries\n"
Packit 01d647
                  << "<---- 0x" << std::hex << tag() << "\n";
Packit 01d647
#endif
Packit 01d647
        return offset + dirOffset;
Packit 01d647
    } // CiffDirectory::doWrite
Packit 01d647
Packit 01d647
    void CiffComponent::writeDirEntry(Blob& blob, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cout << "  Directory entry for tag 0x"
Packit 01d647
                  << std::hex << tagId() << " (0x" << tag()
Packit 01d647
                  << "), " << std::dec << size_
Packit 01d647
                  << " Bytes, Offset is " << offset_ << "\n";
Packit 01d647
#endif
Packit 01d647
        byte buf[4];
Packit 01d647
Packit 01d647
        DataLocId dl = dataLocation();
Packit 01d647
        assert(dl == directoryData || dl == valueData);
Packit 01d647
Packit 01d647
        if (dl == valueData) {
Packit 01d647
            us2Data(buf, tag_, byteOrder);
Packit 01d647
            append(blob, buf, 2);
Packit 01d647
Packit 01d647
            ul2Data(buf, size_, byteOrder);
Packit 01d647
            append(blob, buf, 4);
Packit 01d647
Packit 01d647
            ul2Data(buf, offset_, byteOrder);
Packit 01d647
            append(blob, buf, 4);
Packit 01d647
        }
Packit 01d647
Packit 01d647
        if (dl == directoryData) {
Packit 01d647
            // Only 8 bytes fit in the directory entry
Packit 01d647
            assert(size_ <= 8);
Packit 01d647
Packit 01d647
            us2Data(buf, tag_, byteOrder);
Packit 01d647
            append(blob, buf, 2);
Packit 01d647
            // Copy value instead of size and offset
Packit 01d647
            append(blob, pData_, size_);
Packit 01d647
            // Pad with 0s
Packit 01d647
            for (uint32_t i = size_; i < 8; ++i) {
Packit 01d647
                blob.push_back(0);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CiffComponent::writeDirEntry
Packit 01d647
Packit 01d647
    void CiffHeader::print(std::ostream& os, const std::string& prefix) const
Packit 01d647
    {
Packit 01d647
        std::ios::fmtflags f( os.flags() );
Packit 01d647
        os << prefix
Packit 01d647
           << _("Header, offset") << " = 0x" << std::setw(8) << std::setfill('0')
Packit 01d647
           << std::hex << std::right << offset_ << "\n";
Packit 01d647
        if (pRootDir_) pRootDir_->print(os, byteOrder_, prefix);
Packit 01d647
        os.flags(f);
Packit 01d647
    } // CiffHeader::print
Packit 01d647
Packit 01d647
    void CiffComponent::print(std::ostream&      os,
Packit 01d647
                              ByteOrder          byteOrder,
Packit 01d647
                              const std::string& prefix) const
Packit 01d647
    {
Packit 01d647
        doPrint(os, byteOrder, prefix);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CiffComponent::doPrint(std::ostream&      os,
Packit 01d647
                                ByteOrder          byteOrder,
Packit 01d647
                                const std::string& prefix) const
Packit 01d647
    {
Packit 01d647
        os << prefix
Packit 01d647
           << _("tag") << " = 0x" << std::setw(4) << std::setfill('0')
Packit 01d647
           << std::hex << std::right << tagId()
Packit 01d647
           << ", " << _("dir") << " = 0x" << std::setw(4) << std::setfill('0')
Packit 01d647
           << std::hex << std::right << dir()
Packit 01d647
           << ", " << _("type") << " = " << TypeInfo::typeName(typeId())
Packit 01d647
           << ", " << _("size") << " = " << std::dec << size_
Packit 01d647
           << ", " << _("offset") << " = " << offset_ << "\n";
Packit 01d647
Packit 01d647
        Value::AutoPtr value;
Packit 01d647
        if (typeId() != directory) {
Packit 01d647
            value = Value::create(typeId());
Packit 01d647
            value->read(pData_, size_, byteOrder);
Packit 01d647
            if (value->size() < 100) {
Packit 01d647
                os << prefix << *value << "\n";
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CiffComponent::doPrint
Packit 01d647
Packit 01d647
    void CiffDirectory::doPrint(std::ostream&      os,
Packit 01d647
                                ByteOrder          byteOrder,
Packit 01d647
                                const std::string& prefix) const
Packit 01d647
    {
Packit 01d647
        CiffComponent::doPrint(os, byteOrder, prefix);
Packit 01d647
        Components::const_iterator b = components_.begin();
Packit 01d647
        Components::const_iterator e = components_.end();
Packit 01d647
        for (Components::const_iterator i = b; i != e; ++i) {
Packit 01d647
            (*i)->print(os, byteOrder, prefix + "   ");
Packit 01d647
        }
Packit 01d647
    } // CiffDirectory::doPrint
Packit 01d647
Packit 01d647
    void CiffComponent::setValue(DataBuf buf)
Packit 01d647
    {
Packit 01d647
        if (isAllocated_) {
Packit Bot be4f0c
            delete[] pData_;
Packit 01d647
            pData_ = 0;
Packit 01d647
            size_ = 0;
Packit 01d647
        }
Packit 01d647
        isAllocated_ = true;
Packit 01d647
        std::pair<byte *, long> p = buf.release();
Packit 01d647
        pData_ = p.first;
Packit 01d647
        size_  = p.second;
Packit 01d647
        if (size_ > 8 && dataLocation() == directoryData) {
Packit 01d647
            tag_ &= 0x3fff;
Packit 01d647
        }
Packit 01d647
    } // CiffComponent::setValue
Packit 01d647
Packit 01d647
    TypeId CiffComponent::typeId(uint16_t tag)
Packit 01d647
    {
Packit 01d647
        TypeId ti = invalidTypeId;
Packit 01d647
        switch (tag & 0x3800) {
Packit 01d647
        case 0x0000: ti = unsignedByte; break;
Packit 01d647
        case 0x0800: ti = asciiString; break;
Packit 01d647
        case 0x1000: ti = unsignedShort; break;
Packit 01d647
        case 0x1800: ti = unsignedLong; break;
Packit 01d647
        case 0x2000: ti = undefined; break;
Packit 01d647
        case 0x2800: // fallthrough
Packit 01d647
        case 0x3000: ti = directory; break;
Packit 01d647
        }
Packit 01d647
        return ti;
Packit 01d647
    } // CiffComponent::typeId
Packit 01d647
Packit 01d647
    DataLocId CiffComponent::dataLocation(uint16_t tag)
Packit 01d647
    {
Packit 01d647
        switch (tag & 0xc000) {
Packit 01d647
        case 0x0000: return valueData;
Packit 01d647
        case 0x4000: return directoryData;
Packit 01d647
        default: throw Error(kerCorruptedMetadata);
Packit 01d647
        }
Packit 01d647
    } // CiffComponent::dataLocation
Packit 01d647
Packit 01d647
    /*!
Packit 01d647
      @brief Finds \em crwTagId in directory \em crwDir, returning a pointer to
Packit 01d647
             the component or 0 if not found.
Packit 01d647
Packit 01d647
     */
Packit 01d647
    CiffComponent* CiffHeader::findComponent(uint16_t crwTagId,
Packit 01d647
                                             uint16_t crwDir) const
Packit 01d647
    {
Packit 01d647
        if (pRootDir_ == 0) return 0;
Packit 01d647
        return pRootDir_->findComponent(crwTagId, crwDir);
Packit 01d647
    } // CiffHeader::findComponent
Packit 01d647
Packit 01d647
    CiffComponent* CiffComponent::findComponent(uint16_t crwTagId,
Packit 01d647
                                                uint16_t crwDir) const
Packit 01d647
    {
Packit 01d647
        return doFindComponent(crwTagId, crwDir);
Packit 01d647
    } // CiffComponent::findComponent
Packit 01d647
Packit 01d647
    CiffComponent* CiffComponent::doFindComponent(uint16_t crwTagId,
Packit 01d647
                                                  uint16_t crwDir) const
Packit 01d647
    {
Packit 01d647
        if (tagId() == crwTagId && dir() == crwDir) {
Packit 01d647
            return const_cast<CiffComponent*>(this);
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    } // CiffComponent::doFindComponent
Packit 01d647
Packit 01d647
    CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId,
Packit 01d647
                                                  uint16_t crwDir) const
Packit 01d647
    {
Packit 01d647
        CiffComponent* cc = NULL;
Packit 01d647
        const Components::const_iterator b = components_.begin();
Packit 01d647
        const Components::const_iterator e = components_.end();
Packit 01d647
        for (Components::const_iterator i = b; i != e; ++i) {
Packit 01d647
            cc = (*i)->findComponent(crwTagId, crwDir);
Packit 01d647
            if (cc) return cc;
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    } // CiffDirectory::doFindComponent
Packit 01d647
Packit 01d647
    void CiffHeader::add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf)
Packit 01d647
    {
Packit 01d647
        CrwDirs crwDirs;
Packit 01d647
        CrwMap::loadStack(crwDirs, crwDir);
Packit 01d647
        uint16_t rootDirectory = crwDirs.top().crwDir_;
Packit 01d647
        UNUSED(rootDirectory);
Packit 01d647
        assert(rootDirectory == 0x0000);
Packit 01d647
        crwDirs.pop();
Packit 01d647
        if (!pRootDir_) pRootDir_ = new CiffDirectory;
Packit 01d647
        if ( pRootDir_) {
Packit 01d647
            CiffComponent* child = pRootDir_->add(crwDirs, crwTagId);
Packit 01d647
            if ( child )   child->setValue(buf);
Packit 01d647
        }
Packit 01d647
    } // CiffHeader::add
Packit 01d647
Packit 01d647
    CiffComponent* CiffComponent::add(CrwDirs& crwDirs, uint16_t crwTagId)
Packit 01d647
    {
Packit 01d647
        return doAdd(crwDirs, crwTagId);
Packit 01d647
    } // CiffComponent::add
Packit 01d647
Packit 01d647
    CiffComponent* CiffComponent::doAdd(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/)
Packit 01d647
    {
Packit 01d647
        return 0;
Packit 01d647
    } // CiffComponent::doAdd
Packit 01d647
Packit 01d647
    CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId)
Packit 01d647
    {
Packit 01d647
        /*
Packit 01d647
          add()
Packit 01d647
            if stack not empty
Packit 01d647
              pop from stack
Packit 01d647
              find dir among components
Packit 01d647
              if not found, create it
Packit 01d647
              add()
Packit 01d647
            else
Packit 01d647
              find tag among components
Packit 01d647
              if not found, create it
Packit 01d647
              set value
Packit 01d647
        */
Packit 01d647
        const Components::iterator b = components_.begin();
Packit 01d647
        const Components::iterator e = components_.end();
Packit 01d647
Packit 01d647
        if (!crwDirs.empty()) {
Packit 01d647
            CrwSubDir csd = crwDirs.top();
Packit 01d647
            crwDirs.pop();
Packit 01d647
            // Find the directory
Packit 01d647
            for (Components::iterator i = b; i != e; ++i) {
Packit 01d647
                if ((*i)->tag() == csd.crwDir_) {
Packit 01d647
                    cc_ = *i;
Packit 01d647
                    break;
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
            if (cc_ == 0) {
Packit 01d647
                // Directory doesn't exist yet, add it
Packit 01d647
                m_ = AutoPtr(new CiffDirectory(csd.crwDir_, csd.parent_));
Packit 01d647
                cc_ = m_.get();
Packit 01d647
                add(m_);
Packit 01d647
            }
Packit 01d647
            // Recursive call to next lower level directory
Packit 01d647
            cc_ = cc_->add(crwDirs, crwTagId);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            // Find the tag
Packit 01d647
            for (Components::iterator i = b; i != e; ++i) {
Packit 01d647
                if ((*i)->tagId() == crwTagId) {
Packit 01d647
                    cc_ = *i;
Packit 01d647
                    break;
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
            if (cc_ == 0) {
Packit 01d647
                // Tag doesn't exist yet, add it
Packit 01d647
                m_ = AutoPtr(new CiffEntry(crwTagId, tag()));
Packit 01d647
                cc_ = m_.get();
Packit 01d647
                add(m_);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return cc_;
Packit 01d647
    } // CiffDirectory::doAdd
Packit 01d647
Packit 01d647
    void CiffHeader::remove(uint16_t crwTagId, uint16_t crwDir)
Packit 01d647
    {
Packit 01d647
        if (pRootDir_) {
Packit 01d647
            CrwDirs crwDirs;
Packit 01d647
            CrwMap::loadStack(crwDirs, crwDir);
Packit 01d647
            uint16_t rootDirectory = crwDirs.top().crwDir_;
Packit 01d647
            UNUSED(rootDirectory);
Packit 01d647
            assert(rootDirectory == 0x0000);
Packit 01d647
            crwDirs.pop();
Packit 01d647
            pRootDir_->remove(crwDirs, crwTagId);
Packit 01d647
        }
Packit 01d647
    } // CiffHeader::remove
Packit 01d647
Packit 01d647
    void CiffComponent::remove(CrwDirs& crwDirs, uint16_t crwTagId)
Packit 01d647
    {
Packit 01d647
        return doRemove(crwDirs, crwTagId);
Packit 01d647
    } // CiffComponent::remove
Packit 01d647
Packit 01d647
    void CiffComponent::doRemove(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/)
Packit 01d647
    {
Packit 01d647
        // do nothing
Packit 01d647
    } // CiffComponent::doRemove
Packit 01d647
Packit 01d647
    void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId)
Packit 01d647
    {
Packit 01d647
        const Components::iterator b = components_.begin();
Packit 01d647
        const Components::iterator e = components_.end();
Packit 01d647
        Components::iterator i;
Packit 01d647
Packit 01d647
        if (!crwDirs.empty()) {
Packit 01d647
            CrwSubDir csd = crwDirs.top();
Packit 01d647
            crwDirs.pop();
Packit 01d647
            // Find the directory
Packit 01d647
            for (i = b; i != e; ++i) {
Packit 01d647
                if ((*i)->tag() == csd.crwDir_) {
Packit 01d647
                    // Recursive call to next lower level directory
Packit 01d647
                    (*i)->remove(crwDirs, crwTagId);
Packit 01d647
                    if ((*i)->empty()) components_.erase(i);
Packit 01d647
                    break;
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            // Find the tag
Packit 01d647
            for (i = b; i != e; ++i) {
Packit 01d647
                if ((*i)->tagId() == crwTagId) {
Packit 01d647
                    // Remove the entry and abort the loop
Packit 01d647
                    delete *i;
Packit 01d647
                    components_.erase(i);
Packit 01d647
                    break;
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CiffDirectory::doRemove
Packit 01d647
Packit 01d647
    bool CiffComponent::empty() const
Packit 01d647
    {
Packit 01d647
        return doEmpty();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    bool CiffComponent::doEmpty() const
Packit 01d647
    {
Packit 01d647
        return size_ == 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    bool CiffDirectory::doEmpty() const
Packit 01d647
    {
Packit 01d647
        return components_.empty();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void CrwMap::decode(const CiffComponent& ciffComponent,
Packit 01d647
                        Image&               image,
Packit 01d647
                        ByteOrder            byteOrder)
Packit 01d647
    {
Packit 01d647
        const CrwMapping* cmi = crwMapping(ciffComponent.dir(),
Packit 01d647
                                           ciffComponent.tagId());
Packit 01d647
        if (cmi && cmi->toExif_) {
Packit 01d647
            cmi->toExif_(ciffComponent, cmi, image, byteOrder);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::decode
Packit 01d647
Packit 01d647
    const CrwMapping* CrwMap::crwMapping(uint16_t crwDir, uint16_t crwTagId)
Packit 01d647
    {
Packit 01d647
        for (int i = 0; crwMapping_[i].ifdId_ != ifdIdNotSet; ++i) {
Packit 01d647
            if (   crwMapping_[i].crwDir_ == crwDir
Packit 01d647
                && crwMapping_[i].crwTagId_ == crwTagId) {
Packit 01d647
                return &(crwMapping_[i]);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    } // CrwMap::crwMapping
Packit 01d647
Packit 01d647
    void CrwMap::decode0x0805(const CiffComponent& ciffComponent,
Packit 01d647
                              const CrwMapping*    /*pCrwMapping*/,
Packit 01d647
                                    Image&         image,
Packit 01d647
                                    ByteOrder      /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        std::string s(reinterpret_cast<const char*>(ciffComponent.pData()));
Packit 01d647
        image.setComment(s);
Packit 01d647
    } // CrwMap::decode0x0805
Packit 01d647
Packit 01d647
    void CrwMap::decode0x080a(const CiffComponent& ciffComponent,
Packit 01d647
                              const CrwMapping*    /*pCrwMapping*/,
Packit 01d647
                                    Image&         image,
Packit 01d647
                                    ByteOrder      byteOrder)
Packit 01d647
    {
Packit 01d647
        if (ciffComponent.typeId() != asciiString) return;
Packit 01d647
Packit 01d647
        // Make
Packit 01d647
        ExifKey key1("Exif.Image.Make");
Packit 01d647
        Value::AutoPtr value1 = Value::create(ciffComponent.typeId());
Packit 01d647
        uint32_t i = 0;
Packit 01d647
        for (;    i < ciffComponent.size()
Packit 01d647
               && ciffComponent.pData()[i] != '\0'; ++i) {
Packit 01d647
            // empty
Packit 01d647
        }
Packit 01d647
        value1->read(ciffComponent.pData(), ++i, byteOrder);
Packit 01d647
        image.exifData().add(key1, value1.get());
Packit 01d647
Packit 01d647
        // Model
Packit 01d647
        ExifKey key2("Exif.Image.Model");
Packit 01d647
        Value::AutoPtr value2 = Value::create(ciffComponent.typeId());
Packit 01d647
        uint32_t j = i;
Packit 01d647
        for (;    i < ciffComponent.size()
Packit 01d647
               && ciffComponent.pData()[i] != '\0'; ++i) {
Packit 01d647
            // empty
Packit 01d647
        }
Packit 01d647
        value2->read(ciffComponent.pData() + j, i - j + 1, byteOrder);
Packit 01d647
        image.exifData().add(key2, value2.get());
Packit 01d647
    } // CrwMap::decode0x080a
Packit 01d647
Packit 01d647
    void CrwMap::decodeArray(const CiffComponent& ciffComponent,
Packit 01d647
                             const CrwMapping*    pCrwMapping,
Packit 01d647
                                   Image&         image,
Packit 01d647
                                   ByteOrder      byteOrder)
Packit 01d647
    {
Packit 01d647
        if (ciffComponent.typeId() != unsignedShort) {
Packit 01d647
            return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
Packit 01d647
        }
Packit 01d647
Packit 01d647
        long aperture = 0;
Packit 01d647
        long shutterSpeed = 0;
Packit 01d647
Packit 01d647
        IfdId ifdId = ifdIdNotSet;
Packit 01d647
        switch (pCrwMapping->tag_) {
Packit 01d647
        case 0x0001: ifdId = canonCsId; break;
Packit 01d647
        case 0x0004: ifdId = canonSiId; break;
Packit 01d647
        case 0x000f: ifdId = canonCfId; break;
Packit 01d647
        case 0x0012: ifdId = canonPiId; break;
Packit 01d647
        }
Packit 01d647
        assert(ifdId != ifdIdNotSet);
Packit 01d647
Packit 01d647
        std::string groupName(Internal::groupName(ifdId));
Packit 01d647
        uint16_t c = 1;
Packit 01d647
        while (uint32_t(c)*2 < ciffComponent.size()) {
Packit 01d647
            uint16_t n = 1;
Packit 01d647
            ExifKey key(c, groupName);
Packit 01d647
            UShortValue value;
Packit 01d647
            if (ifdId == canonCsId && c == 23 && ciffComponent.size() > 50) n = 3;
Packit 01d647
            value.read(ciffComponent.pData() + c*2, n*2, byteOrder);
Packit 01d647
            image.exifData().add(key, &value);
Packit 01d647
            if (ifdId == canonSiId && c == 21) aperture = value.toLong();
Packit 01d647
            if (ifdId == canonSiId && c == 22) shutterSpeed = value.toLong();
Packit 01d647
            c += n;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        if (ifdId == canonSiId) {
Packit 01d647
            // Exif.Photo.FNumber
Packit 01d647
            float f = fnumber(canonEv(aperture));
Packit 01d647
            Rational r = floatToRationalCast(f);
Packit 01d647
            URational ur(r.first, r.second);
Packit 01d647
            URationalValue fn;
Packit 01d647
            fn.value_.push_back(ur);
Packit 01d647
            image.exifData().add(ExifKey("Exif.Photo.FNumber"), &fn);
Packit 01d647
Packit 01d647
            // Exif.Photo.ExposureTime
Packit 01d647
            ur = exposureTime(canonEv(shutterSpeed));
Packit 01d647
            URationalValue et;
Packit 01d647
            et.value_.push_back(ur);
Packit 01d647
            image.exifData().add(ExifKey("Exif.Photo.ExposureTime"), &et);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::decodeArray
Packit 01d647
Packit 01d647
    void CrwMap::decode0x180e(const CiffComponent& ciffComponent,
Packit 01d647
                              const CrwMapping*    pCrwMapping,
Packit 01d647
                                    Image&         image,
Packit 01d647
                                    ByteOrder      byteOrder)
Packit 01d647
    {
Packit 01d647
        if (ciffComponent.size() < 8 || ciffComponent.typeId() != unsignedLong) {
Packit 01d647
            return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
Packit 01d647
        }
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        ULongValue v;
Packit 01d647
        v.read(ciffComponent.pData(), 8, byteOrder);
Packit 01d647
        time_t t = v.value_[0];
Packit Service fb147c
        struct tm* tm = std::localtime(&t);
Packit 01d647
        if (tm) {
Packit 01d647
            const size_t m = 20;
Packit 01d647
            char s[m];
Packit 01d647
            std::strftime(s, m, "%Y:%m:%d %H:%M:%S", tm);
Packit 01d647
Packit 01d647
            ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
Packit 01d647
            AsciiValue value;
Packit 01d647
            value.read(std::string(s));
Packit 01d647
            image.exifData().add(key, &value);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::decode0x180e
Packit 01d647
Packit 01d647
    void CrwMap::decode0x1810(const CiffComponent& ciffComponent,
Packit 01d647
                              const CrwMapping*    pCrwMapping,
Packit 01d647
                                    Image&         image,
Packit 01d647
                                    ByteOrder      byteOrder)
Packit 01d647
    {
Packit 01d647
        if (ciffComponent.typeId() != unsignedLong || ciffComponent.size() < 28) {
Packit 01d647
            return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
Packit 01d647
        }
Packit 01d647
Packit 01d647
        ExifKey key1("Exif.Photo.PixelXDimension");
Packit 01d647
        ULongValue value1;
Packit 01d647
        value1.read(ciffComponent.pData(), 4, byteOrder);
Packit 01d647
        image.exifData().add(key1, &value1);
Packit 01d647
Packit 01d647
        ExifKey key2("Exif.Photo.PixelYDimension");
Packit 01d647
        ULongValue value2;
Packit 01d647
        value2.read(ciffComponent.pData() + 4, 4, byteOrder);
Packit 01d647
        image.exifData().add(key2, &value2);
Packit 01d647
Packit 01d647
        int32_t r = getLong(ciffComponent.pData() + 12, byteOrder);
Packit 01d647
        uint16_t o = RotationMap::orientation(r);
Packit 01d647
        image.exifData()["Exif.Image.Orientation"] = o;
Packit 01d647
Packit 01d647
    } // CrwMap::decode0x1810
Packit 01d647
Packit 01d647
    void CrwMap::decode0x2008(const CiffComponent& ciffComponent,
Packit 01d647
                              const CrwMapping*    /*pCrwMapping*/,
Packit 01d647
                                    Image&         image,
Packit 01d647
                                    ByteOrder      /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        ExifThumb exifThumb(image.exifData());
Packit 01d647
        exifThumb.setJpegThumbnail(ciffComponent.pData(), ciffComponent.size());
Packit 01d647
    } // CrwMap::decode0x2008
Packit 01d647
Packit 01d647
    void CrwMap::decodeBasic(const CiffComponent& ciffComponent,
Packit 01d647
                             const CrwMapping*    pCrwMapping,
Packit 01d647
                                   Image&         image,
Packit 01d647
                                   ByteOrder      byteOrder)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        // create a key and value pair
Packit 01d647
        ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
Packit 01d647
        Value::AutoPtr value;
Packit 01d647
        if (ciffComponent.typeId() != directory) {
Packit 01d647
            value = Value::create(ciffComponent.typeId());
Packit 01d647
            uint32_t size = 0;
Packit 01d647
            if (pCrwMapping->size_ != 0) {
Packit 01d647
                // size in the mapping table overrides all
Packit 01d647
                size = pCrwMapping->size_;
Packit 01d647
            }
Packit 01d647
            else if (ciffComponent.typeId() == asciiString) {
Packit 01d647
                // determine size from the data, by looking for the first 0
Packit 01d647
                uint32_t i = 0;
Packit 01d647
                for (;    i < ciffComponent.size()
Packit 01d647
                       && ciffComponent.pData()[i] != '\0'; ++i) {
Packit 01d647
                    // empty
Packit 01d647
                }
Packit 01d647
                size = ++i;
Packit 01d647
            }
Packit 01d647
            else {
Packit 01d647
                // by default, use the size from the directory entry
Packit 01d647
                size = ciffComponent.size();
Packit 01d647
            }
Packit 01d647
            value->read(ciffComponent.pData(), size, byteOrder);
Packit 01d647
        }
Packit 01d647
        // Add metadatum to exif data
Packit 01d647
        image.exifData().add(key, value.get());
Packit 01d647
    } // CrwMap::decodeBasic
Packit 01d647
Packit 01d647
    void CrwMap::loadStack(CrwDirs& crwDirs, uint16_t crwDir)
Packit 01d647
    {
Packit 01d647
        for (int i = 0; crwSubDir_[i].crwDir_ != 0xffff; ++i) {
Packit 01d647
            if (crwSubDir_[i].crwDir_ == crwDir) {
Packit 01d647
                crwDirs.push(crwSubDir_[i]);
Packit 01d647
                crwDir = crwSubDir_[i].parent_;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CrwMap::loadStack
Packit 01d647
Packit 01d647
    void CrwMap::encode(CiffHeader* pHead, const Image& image)
Packit 01d647
    {
Packit 01d647
        for (const CrwMapping* cmi = crwMapping_; cmi->ifdId_ != ifdIdNotSet; ++cmi) {
Packit 01d647
            if (cmi->fromExif_ != 0) {
Packit 01d647
                cmi->fromExif_(image, cmi, pHead);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode
Packit 01d647
Packit 01d647
    void CrwMap::encodeBasic(const Image&      image,
Packit 01d647
                             const CrwMapping* pCrwMapping,
Packit 01d647
                                   CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        // Determine the source Exif metadatum
Packit 01d647
        ExifKey ek(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
Packit 01d647
        ExifData::const_iterator ed = image.exifData().findKey(ek);
Packit 01d647
Packit 01d647
        // Set the new value or remove the entry
Packit 01d647
        if (ed != image.exifData().end()) {
Packit 01d647
            DataBuf buf(ed->size());
Packit 01d647
            ed->copy(buf.pData_, pHead->byteOrder());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encodeBasic
Packit 01d647
Packit 01d647
    void CrwMap::encode0x0805(const Image&      image,
Packit 01d647
                              const CrwMapping* pCrwMapping,
Packit 01d647
                                    CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        std::string comment = image.comment();
Packit 01d647
Packit 01d647
        CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
Packit 01d647
                                                 pCrwMapping->crwDir_);
Packit 01d647
        if (!comment.empty()) {
Packit 01d647
            uint32_t size = static_cast<uint32_t>(comment.size());
Packit 01d647
            if (cc && cc->size() > size) size = cc->size();
Packit 01d647
            DataBuf buf(size);
Packit 01d647
            std::memset(buf.pData_, 0x0, buf.size_);
Packit 01d647
            std::memcpy(buf.pData_, comment.data(), comment.size());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            if (cc) {
Packit 01d647
                // Just delete the value, do not remove the tag
Packit 01d647
                DataBuf buf(cc->size());
Packit 01d647
                std::memset(buf.pData_, 0x0, buf.size_);
Packit 01d647
                cc->setValue(buf);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode0x0805
Packit 01d647
Packit 01d647
    void CrwMap::encode0x080a(const Image&      image,
Packit 01d647
                              const CrwMapping* pCrwMapping,
Packit 01d647
                                    CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        const ExifKey k1("Exif.Image.Make");
Packit 01d647
        const ExifKey k2("Exif.Image.Model");
Packit 01d647
        const ExifData::const_iterator ed1 = image.exifData().findKey(k1);
Packit 01d647
        const ExifData::const_iterator ed2 = image.exifData().findKey(k2);
Packit 01d647
        const ExifData::const_iterator edEnd = image.exifData().end();
Packit 01d647
Packit 01d647
        long size = 0;
Packit 01d647
        if (ed1 != edEnd) size += ed1->size();
Packit 01d647
        if (ed2 != edEnd) size += ed2->size();
Packit 01d647
        if (size != 0) {
Packit 01d647
            DataBuf buf(size);
Packit 01d647
            if (ed1 != edEnd) ed1->copy(buf.pData_, pHead->byteOrder());
Packit 01d647
            if (ed2 != edEnd) ed2->copy(buf.pData_ + ed1->size(), pHead->byteOrder());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode0x080a
Packit 01d647
Packit 01d647
    void CrwMap::encodeArray(const Image&      image,
Packit 01d647
                             const CrwMapping* pCrwMapping,
Packit 01d647
                                   CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        IfdId ifdId = ifdIdNotSet;
Packit 01d647
        switch (pCrwMapping->tag_) {
Packit 01d647
        case 0x0001: ifdId = canonCsId; break;
Packit 01d647
        case 0x0004: ifdId = canonSiId; break;
Packit 01d647
        case 0x000f: ifdId = canonCfId; break;
Packit 01d647
        case 0x0012: ifdId = canonPiId; break;
Packit 01d647
        }
Packit 01d647
        assert(ifdId != ifdIdNotSet);
Packit 01d647
        DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder());
Packit 01d647
        if (buf.size_ == 0) {
Packit 01d647
            // Try the undecoded tag
Packit 01d647
            encodeBasic(image, pCrwMapping, pHead);
Packit 01d647
        }
Packit 01d647
        if (buf.size_ > 0) {
Packit 01d647
            // Write the number of shorts to the beginning of buf
Packit 01d647
            us2Data(buf.pData_, static_cast<uint16_t>(buf.size_), pHead->byteOrder());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encodeArray
Packit 01d647
Packit 01d647
    void CrwMap::encode0x180e(const Image&      image,
Packit 01d647
                              const CrwMapping* pCrwMapping,
Packit 01d647
                                    CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        time_t t = 0;
Packit 01d647
        const ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
Packit 01d647
        const ExifData::const_iterator ed = image.exifData().findKey(key);
Packit 01d647
        if (ed != image.exifData().end()) {
Packit 01d647
            struct tm tm;
Packit 01d647
            std::memset(&tm, 0x0, sizeof(tm));
Packit Service fb147c
            if ( exifTime(ed->toString().c_str(), &tm) == 0 ) {
Packit Service fb147c
                t=::mktime(&tm;;
Packit Service fb147c
            }
Packit 01d647
        }
Packit 01d647
        if (t != 0) {
Packit 01d647
            DataBuf buf(12);
Packit 01d647
            std::memset(buf.pData_, 0x0, 12);
Packit 01d647
            ul2Data(buf.pData_, static_cast<uint32_t>(t), pHead->byteOrder());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode0x180e
Packit 01d647
Packit 01d647
    void CrwMap::encode0x1810(const Image&      image,
Packit 01d647
                              const CrwMapping* pCrwMapping,
Packit 01d647
                                    CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        const ExifKey kX("Exif.Photo.PixelXDimension");
Packit 01d647
        const ExifKey kY("Exif.Photo.PixelYDimension");
Packit 01d647
        const ExifKey kO("Exif.Image.Orientation");
Packit 01d647
        const ExifData &exivData = image.exifData();
Packit 01d647
        const ExifData::const_iterator edX = exivData.findKey(kX);
Packit 01d647
        const ExifData::const_iterator edY = exivData.findKey(kY);
Packit 01d647
        const ExifData::const_iterator edO = exivData.findKey(kO);
Packit 01d647
        const ExifData::const_iterator edEnd = exivData.end();
Packit 01d647
Packit 01d647
        CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
Packit 01d647
                                                 pCrwMapping->crwDir_);
Packit 01d647
        if (edX != edEnd || edY != edEnd || edO != edEnd) {
Packit 01d647
            uint32_t size = 28;
Packit Bot be4f0c
            if (cc) {
Packit Bot be4f0c
              if (cc->size() < size)
Packit Bot be4f0c
                throw Error(kerCorruptedMetadata);
Packit Bot be4f0c
              size = cc->size();
Packit Bot be4f0c
            }
Packit 01d647
            DataBuf buf(size);
Packit 01d647
            std::memset(buf.pData_, 0x0, buf.size_);
Packit 01d647
            if (cc) std::memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8);
Packit 01d647
            if (edX != edEnd && edX->size() == 4) {
Packit 01d647
                edX->copy(buf.pData_, pHead->byteOrder());
Packit 01d647
            }
Packit 01d647
            if (edY != edEnd && edY->size() == 4) {
Packit 01d647
                edY->copy(buf.pData_ + 4, pHead->byteOrder());
Packit 01d647
            }
Packit 01d647
            int32_t d = 0;
Packit 01d647
            if (edO != edEnd && edO->count() > 0 && edO->typeId() == unsignedShort) {
Packit 01d647
                d = RotationMap::degrees(static_cast<uint16_t>(edO->toLong()));
Packit 01d647
            }
Packit 01d647
            l2Data(buf.pData_ + 12, d, pHead->byteOrder());
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode0x1810
Packit 01d647
Packit 01d647
    void CrwMap::encode0x2008(const Image&      image,
Packit 01d647
                              const CrwMapping* pCrwMapping,
Packit 01d647
                                    CiffHeader* pHead)
Packit 01d647
    {
Packit 01d647
        assert(pCrwMapping != 0);
Packit 01d647
        assert(pHead != 0);
Packit 01d647
Packit 01d647
        ExifThumbC exifThumb(image.exifData());
Packit 01d647
        DataBuf buf = exifThumb.copy();
Packit 01d647
        if (buf.size_ != 0) {
Packit 01d647
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
Packit 01d647
        }
Packit 01d647
    } // CrwMap::encode0x2008
Packit 01d647
Packit 01d647
    // *************************************************************************
Packit 01d647
    // free functions
Packit 01d647
    DataBuf packIfdId(const ExifData& exifData,
Packit 01d647
                            IfdId     ifdId,
Packit 01d647
                            ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        const uint16_t size = 1024;
Packit 01d647
        DataBuf buf(size);
Packit 01d647
        std::memset(buf.pData_, 0x0, buf.size_);
Packit 01d647
Packit 01d647
        uint16_t len = 0;
Packit 01d647
        const ExifData::const_iterator b = exifData.begin();
Packit 01d647
        const ExifData::const_iterator e = exifData.end();
Packit 01d647
        for (ExifData::const_iterator i = b; i != e; ++i) {
Packit 01d647
            if (i->ifdId() != ifdId) continue;
Packit 01d647
            const uint16_t s = i->tag()*2 + static_cast<uint16_t>(i->size());
Packit 01d647
            assert(s <= size);
Packit 01d647
            if (len < s) len = s;
Packit 01d647
            i->copy(buf.pData_ + i->tag()*2, byteOrder);
Packit 01d647
        }
Packit 01d647
        // Round the size to make it even.
Packit 01d647
        buf.size_ = len + len%2;
Packit 01d647
        return buf;
Packit 01d647
    }
Packit 01d647
Packit 01d647
}}                                       // namespace Internal, Exiv2