diff --git a/doc/exiv2.dot b/doc/exiv2.dot index fb509c78..6ba98d53 100644 --- a/doc/exiv2.dot +++ b/doc/exiv2.dot @@ -3,7 +3,7 @@ # Brief Dot file for a graph showing the component dependencies # of the Exiv2 library. Run the following command to get the image: # $ dot -Tgif -oexiv2.gif exiv2.dot -# Version $Name: $ $Revision: 1.4 $ +# Version $Name: $ $Revision: 1.5 $ # Author Andreas Huggel (ahu) # ahuggel@gmx.net # Date 18-Feb-04, ahu: created @@ -15,8 +15,9 @@ L1 [shape=plaintext] ; L2 [shape=plaintext] ; L3 [shape=plaintext] ; L4 [shape=plaintext] ; +L5 [shape=plaintext] ; -"L4" -> "L3" -> "L2" -> "L1" [style=invis] ; +"L5" -> "L4" -> "L3" -> "L2" -> "L1" [style=invis] ; "exif" [shape=box] ; "iptc" [shape=box] ; @@ -30,11 +31,9 @@ L4 [shape=plaintext] ; "error" [shape=box] ; "makernote" [shape=box] ; -"exif" -> "metadatum" ; "exif" -> "tags" ; "exif" -> "makernote" ; "exif" -> "image" ; -"iptc" -> "metadatum" ; "iptc" -> "datasets" ; "iptc" -> "image" ; "metadatum" -> "value" ; @@ -44,10 +43,8 @@ L4 [shape=plaintext] ; "ifd" -> "error" ; "ifd" -> "types" ; "image" -> "types" ; -"tags" -> "error" ; -"tags" -> "value" ; -"datasets" -> "error" ; -"datasets" -> "value" ; +"tags" -> "metadatum"; +"datasets" -> "metadatum" ; "value" -> "types" ; { rank=same; L1 error types } diff --git a/doc/exiv2.gif b/doc/exiv2.gif index 7701ad40..3b604a11 100644 Binary files a/doc/exiv2.gif and b/doc/exiv2.gif differ diff --git a/doc/getting-started.html b/doc/getting-started.html index d1c8abd5..dd59bc1c 100644 --- a/doc/getting-started.html +++ b/doc/getting-started.html @@ -86,7 +86,7 @@ own header and source files.

Exiv2 Components Diagram

-

Exiv2 components diagram

+

Exiv2 components diagram

 

diff --git a/src/datasets.cpp b/src/datasets.cpp index f8d0e32f..62f32a12 100644 --- a/src/datasets.cpp +++ b/src/datasets.cpp @@ -20,13 +20,13 @@ */ /* File: datasets.cpp - Version: $Name: $ $Revision: 1.6 $ + Version: $Name: $ $Revision: 1.7 $ Author(s): Brad Schick (brad) History: 24-Jul-04, brad: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.6 $ $RCSfile: datasets.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.7 $ $RCSfile: datasets.cpp,v $"); // ***************************************************************************** // included header files @@ -34,14 +34,12 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.6 $ $RCSfile: datasets.cpp,v $"); #include "error.hpp" #include "types.hpp" #include "value.hpp" +#include "metadatum.hpp" #include #include #include -// Todo: remove circular dependency -#include "iptc.hpp" // for DataSet operator<< - // ***************************************************************************** // class member definitions namespace Exiv2 { @@ -291,6 +289,77 @@ namespace Exiv2 { } } // IptcDataSets::dataSetList + const char* IptcKey::familyName_ = "Iptc"; + + IptcKey::IptcKey(const std::string& key) + : key_(key) + { + decomposeKey(); + } + + IptcKey::IptcKey(uint16_t tag, uint16_t record) + : tag_(tag), record_(record) + { + makeKey(); + } + + IptcKey::IptcKey(const IptcKey& rhs) + : tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_) + { + } + + IptcKey& IptcKey::operator=(const IptcKey& rhs) + { + if (this == &rhs) return *this; + Key::operator=(rhs); + tag_ = rhs.tag_; + record_ = rhs.record_; + key_ = rhs.key_; + return *this; + } + + IptcKey* IptcKey::clone() const + { + return new IptcKey(*this); + } + + void IptcKey::decomposeKey() + { + // Get the family name, record name and dataSet name parts of the key + std::string::size_type pos1 = key_.find('.'); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string familyName = key_.substr(0, pos1); + if (familyName != std::string(familyName_)) { + throw Error("Invalid key"); + } + std::string::size_type pos0 = pos1 + 1; + pos1 = key_.find('.', pos0); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string recordName = key_.substr(pos0, pos1 - pos0); + if (recordName == "") throw Error("Invalid key"); + std::string dataSetName = key_.substr(pos1 + 1); + if (dataSetName == "") throw Error("Invalid key"); + + // Use the parts of the key to find dataSet and recordId + uint16_t recId = IptcDataSets::recordId(recordName); + uint16_t dataSet = IptcDataSets::dataSet(dataSetName, recId); + + // Possibly translate hex name parts (0xabcd) to real names + recordName = IptcDataSets::recordName(recId); + dataSetName = IptcDataSets::dataSetName(dataSet, recId); + + tag_ = dataSet; + record_ = recId; + key_ = familyName + "." + recordName + "." + dataSetName; + } // IptcKey::decomposeKey + + void IptcKey::makeKey() + { + key_ = std::string(familyName_) + + "." + IptcDataSets::recordName(record_) + + "." + IptcDataSets::dataSetName(tag_, record_); + } + // ************************************************************************* // free functions diff --git a/src/datasets.hpp b/src/datasets.hpp index 199b3e86..83b854e3 100644 --- a/src/datasets.hpp +++ b/src/datasets.hpp @@ -21,7 +21,7 @@ /*! @file datasets.hpp @brief Iptc dataSet and type information - @version $Name: $ $Revision: 1.5 $ + @version $Name: $ $Revision: 1.6 $ @author Brad Schick (brad) @date 24-Jul-04, brad: created */ @@ -31,6 +31,7 @@ // ***************************************************************************** // included header files #include "types.hpp" +#include "metadatum.hpp" // + standard includes #include @@ -256,6 +257,89 @@ namespace Exiv2 { }; // class IptcDataSets + /*! + @brief Concrete keys for Iptc metadata. + */ + class IptcKey : public Key { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to create an Iptc key from a key string. + + @param key The key string. + @throw Error ("Invalid key") if the first part of the key is not + 'Iptc' or the remaining parts of the key cannot be parsed and + converted to a record name and a dataset name. + */ + explicit IptcKey(const std::string& key); + /*! + @brief Constructor to create an Iptc key from dataset and record ids. + @param tag Dataset id + @param record Record id + */ + IptcKey(uint16_t tag, uint16_t record); + //! Copy constructor + IptcKey(const IptcKey& rhs); + //@} + + //! @name Manipulators + //@{ + /*! + @brief Assignment operator. + */ + IptcKey& operator=(const IptcKey& rhs); + //@} + + //! @name Accessors + //@{ + virtual std::string key() const { return key_; } + virtual const char* familyName() const { return familyName_; } + /*! + @brief Return the name of the group (the second part of the key). + For Iptc keys, the group name is the record name. + */ + virtual std::string groupName() const { return recordName(); } + virtual std::string tagName() const + { return IptcDataSets::dataSetName(tag_, record_); } + virtual uint16_t tag() const { return tag_; } + virtual IptcKey* clone() const; + + //! Return the name of the record + std::string recordName() const + { return IptcDataSets::recordName(record_); } + //! Return the record id + uint16_t record() const { return record_; } + //@} + + protected: + //! @name Manipulators + //@{ + /*! + @brief Set the key corresponding to the dataset and record id. + The key is of the form 'Iptc.recordName.dataSetName'. + */ + void makeKey(); + /*! + @brief Parse and convert the key string into dataset and record id. + Updates data members if the string can be decomposed, or throws + Error ("Invalid key"). + + @throw Error ("Invalid key") if the key cannot be decomposed. + */ + void decomposeKey(); + //@} + + private: + // DATA + static const char* familyName_; + + uint16_t tag_; //!< Tag value + uint16_t record_; //!< Record value + std::string key_; //!< Key + + }; // class IptcKey + // ***************************************************************************** // free functions diff --git a/src/exif.cpp b/src/exif.cpp index 2c01c62d..1e0f41e2 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -20,14 +20,14 @@ */ /* File: exif.cpp - Version: $Name: $ $Revision: 1.62 $ + Version: $Name: $ $Revision: 1.63 $ Author(s): Andreas Huggel (ahu) History: 26-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.62 $ $RCSfile: exif.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.63 $ $RCSfile: exif.cpp,v $"); // Define DEBUG_MAKERNOTE to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -73,158 +73,6 @@ namespace { // class member definitions namespace Exiv2 { - const char* ExifKey::familyName_ = "Exif"; - - ExifKey::ExifKey(const std::string& key) - : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""), - idx_(0), pMakerNote_(0), key_(key) - { - decomposeKey(); - } - - ExifKey::ExifKey(uint16_t tag, const std::string& ifdItem) - : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""), - idx_(0), pMakerNote_(0), key_("") - { - IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); - if (ifdId == makerIfdId) throw Error("Invalid key"); - MakerNote* pMakerNote = 0; - if (ifdId == ifdIdNotSet) { - pMakerNote = MakerNoteFactory::instance().create(ifdItem); - if (pMakerNote) ifdId = makerIfdId; - else throw Error("Invalid key"); - } - tag_ = tag; - ifdId_ = ifdId; - ifdItem_ = ifdItem; - pMakerNote_ = pMakerNote; - makeKey(); - } - - ExifKey::ExifKey(const Entry& e) - : tag_(e.tag()), ifdId_(e.ifdId()), ifdItem_(""), - idx_(e.idx()), pMakerNote_(0), key_("") - { - if (ifdId_ == makerIfdId) { - if (e.makerNote()) { - ifdItem_ = e.makerNote()->ifdItem(); - pMakerNote_ = e.makerNote()->clone(); - } - else throw Error("Invalid Key"); - } - else { - ifdItem_ = ExifTags::ifdItem(ifdId_); - } - makeKey(); - } - - ExifKey::ExifKey(const ExifKey& rhs) - : tag_(rhs.tag_), ifdId_(rhs.ifdId_), ifdItem_(rhs.ifdItem_), - idx_(rhs.idx_), - pMakerNote_(rhs.pMakerNote_ ? rhs.pMakerNote_->clone() : 0), - key_(rhs.key_) - { - } - - ExifKey::~ExifKey() - { - delete pMakerNote_; - } - - ExifKey& ExifKey::operator=(const ExifKey& rhs) - { - if (this == &rhs) return *this; - Key::operator=(rhs); - tag_ = rhs.tag_; - ifdId_ = rhs.ifdId_; - ifdItem_ = rhs.ifdItem_; - idx_ = rhs.idx_; - pMakerNote_ = rhs.pMakerNote_ ? rhs.pMakerNote_->clone() : 0; - key_ = rhs.key_; - return *this; - } - - std::string ExifKey::tagName() const - { - if (ifdId_ == makerIfdId) { - assert(pMakerNote_); - return pMakerNote_->tagName(tag_); - } - return ExifTags::tagName(tag_, ifdId_); - } - - ExifKey* ExifKey::clone() const - { - return new ExifKey(*this); - } - - std::string ExifKey::sectionName() const - { - if (ifdId_ == makerIfdId) { - assert(pMakerNote_); - return pMakerNote_->ifdItem(); - } - return ExifTags::sectionName(tag(), ifdId()); - } - - void ExifKey::decomposeKey() - { - // Get the family name, IFD name and tag name parts of the key - std::string::size_type pos1 = key_.find('.'); - if (pos1 == std::string::npos) throw Error("Invalid key"); - std::string familyName = key_.substr(0, pos1); - if (familyName != std::string(familyName_)) { - throw Error("Invalid key"); - } - std::string::size_type pos0 = pos1 + 1; - pos1 = key_.find('.', pos0); - if (pos1 == std::string::npos) throw Error("Invalid key"); - std::string ifdItem = key_.substr(pos0, pos1 - pos0); - if (ifdItem == "") throw Error("Invalid key"); - std::string tagName = key_.substr(pos1 + 1); - if (tagName == "") throw Error("Invalid key"); - - // Find IfdId - IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); - if (ifdId == makerIfdId) throw Error("Invalid key"); - MakerNote* pMakerNote = 0; - if (ifdId == ifdIdNotSet) { - pMakerNote = MakerNoteFactory::instance().create(ifdItem); - if (pMakerNote) ifdId = makerIfdId; - else throw Error("Invalid key"); - } - - // Convert tag - uint16_t tag = pMakerNote ? - pMakerNote->tag(tagName) : ExifTags::tag(tagName, ifdId); - // Translate hex tag name (0xabcd) to a real tag name if there is one - tagName = pMakerNote ? - pMakerNote->tagName(tag) : ExifTags::tagName(tag, ifdId); - - tag_ = tag; - ifdId_ = ifdId; - ifdItem_ = ifdItem; - pMakerNote_ = pMakerNote; - key_ = familyName + "." + ifdItem + "." + tagName; - } - - void ExifKey::makeKey() - { - key_ = std::string(familyName_) - + "." + ifdItem_ - + "." + (pMakerNote_ ? - pMakerNote_->tagName(tag_) : ExifTags::tagName(tag_, ifdId_)); - } - - std::ostream& ExifKey::printTag(std::ostream& os, const Value& value) const - { - if (ifdId_ == makerIfdId) { - assert(pMakerNote_); - return pMakerNote_->printTag(os, tag(), value); - } - return ExifTags::printTag(os, tag(), ifdId(), value); - } - Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder) : pKey_(new ExifKey(e)), pValue_(0) { diff --git a/src/exif.hpp b/src/exif.hpp index 265ab7ef..7e8e30f2 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.54 $ + @version $Name: $ $Revision: 1.55 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created @@ -60,101 +60,6 @@ namespace Exiv2 { // ***************************************************************************** // class definitions - //! Concrete keys for Exif metadata. - class ExifKey : public Key { - public: - //! @name Creators - //@{ - /*! - @brief Constructor to create an Exif key from a key string. - - @param key The key string. - @throw Error ("Invalid key") if the key cannot be parsed into three - parts or the first part of the key is not 'Exif'. - */ - explicit ExifKey(const std::string& key); - /*! - @brief Constructor to create an Exif key from a tag and IFD item - string. - @param tag The tag value - @param ifdItem The IFD string. For MakerNote tags, this must be the - IFD item of the specific MakerNote. "MakerNote" is not allowed. - @throw Error ("Invalid key") if the key cannot be constructed from - the tag and IFD item parameters. - */ - ExifKey(uint16_t tag, const std::string& ifdItem); - //! Constructor to build an ExifKey from an IFD entry. - explicit ExifKey(const Entry& e); - //! Copy constructor - ExifKey(const ExifKey& rhs); - virtual ~ExifKey(); - //@} - - //! @name Manipulators - //@{ - /*! - @brief Assignment operator. - */ - ExifKey& operator=(const ExifKey& rhs); - //@} - - //! @name Accessors - //@{ - virtual std::string key() const { return key_; } - virtual const char* familyName() const { return familyName_; } - /*! - @brief Return the name of the group (the second part of the key). - For Exif keys, the group name is the IFD item. - */ - virtual std::string groupName() const { return ifdItem(); } - virtual std::string tagName() const; - virtual uint16_t tag() const { return tag_; } - virtual ExifKey* clone() const; - - //! Interpret and print the value of an Exif tag - std::ostream& printTag(std::ostream& os, const Value& value) const; - //! Return the IFD id - IfdId ifdId() const { return ifdId_; } - //! Return the name of the IFD - const char* ifdName() const { return ExifTags::ifdName(ifdId()); } - //! Return the related image item - std::string ifdItem() const { return ifdItem_; } - //! Return the name of the Exif section (deprecated) - std::string sectionName() const; - //! Return the index (unique id of this key within the original IFD) - int idx() const { return idx_; } - //@} - - protected: - //! @name Manipulators - //@{ - /*! - @brief Set the key corresponding to the tag and IFD id. - The key is of the form 'Exif.ifdItem.tagName'. - */ - void makeKey(); - /*! - @brief Parse and convert the key string into tag and IFD Id. - Updates data members if the string can be decomposed, - or throws Error ("Invalid key"). - - @throw Error ("Invalid key") if the key cannot be decomposed. - */ - void decomposeKey(); - //@} - - private: - // DATA - static const char* familyName_; - - uint16_t tag_; //!< Tag value - IfdId ifdId_; //!< The IFD associated with this tag - std::string ifdItem_; //!< The IFD item - int idx_; //!< Unique id of an entry within one IFD - MakerNote* pMakerNote_; //!< Pointer to the associated MakerNote - std::string key_; //!< Key - }; // class ExifKey - /*! @brief Information related to one Exif tag. */ diff --git a/src/iptc.cpp b/src/iptc.cpp index 78ce4516..e68a0c91 100644 --- a/src/iptc.cpp +++ b/src/iptc.cpp @@ -20,13 +20,13 @@ */ /* File: iptc.cpp - Version: $Name: $ $Revision: 1.5 $ + Version: $Name: $ $Revision: 1.6 $ Author(s): Brad Schick (brad) History: 31-July-04, brad: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.5 $ $RCSfile: iptc.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.6 $ $RCSfile: iptc.cpp,v $"); // Define DEBUG_MAKERNOTE to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -48,77 +48,6 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.5 $ $RCSfile: iptc.cpp,v $"); // class member definitions namespace Exiv2 { - const char* IptcKey::familyName_ = "Iptc"; - - IptcKey::IptcKey(const std::string& key) - : key_(key) - { - decomposeKey(); - } - - IptcKey::IptcKey(uint16_t tag, uint16_t record) - : tag_(tag), record_(record) - { - makeKey(); - } - - IptcKey::IptcKey(const IptcKey& rhs) - : tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_) - { - } - - IptcKey& IptcKey::operator=(const IptcKey& rhs) - { - if (this == &rhs) return *this; - Key::operator=(rhs); - tag_ = rhs.tag_; - record_ = rhs.record_; - key_ = rhs.key_; - return *this; - } - - IptcKey* IptcKey::clone() const - { - return new IptcKey(*this); - } - - void IptcKey::decomposeKey() - { - // Get the family name, record name and dataSet name parts of the key - std::string::size_type pos1 = key_.find('.'); - if (pos1 == std::string::npos) throw Error("Invalid key"); - std::string familyName = key_.substr(0, pos1); - if (familyName != std::string(familyName_)) { - throw Error("Invalid key"); - } - std::string::size_type pos0 = pos1 + 1; - pos1 = key_.find('.', pos0); - if (pos1 == std::string::npos) throw Error("Invalid key"); - std::string recordName = key_.substr(pos0, pos1 - pos0); - if (recordName == "") throw Error("Invalid key"); - std::string dataSetName = key_.substr(pos1 + 1); - if (dataSetName == "") throw Error("Invalid key"); - - // Use the parts of the key to find dataSet and recordId - uint16_t recId = IptcDataSets::recordId(recordName); - uint16_t dataSet = IptcDataSets::dataSet(dataSetName, recId); - - // Possibly translate hex name parts (0xabcd) to real names - recordName = IptcDataSets::recordName(recId); - dataSetName = IptcDataSets::dataSetName(dataSet, recId); - - tag_ = dataSet; - record_ = recId; - key_ = familyName + "." + recordName + "." + dataSetName; - } // IptcKey::decomposeKey - - void IptcKey::makeKey() - { - key_ = std::string(familyName_) - + "." + IptcDataSets::recordName(record_) - + "." + IptcDataSets::dataSetName(tag_, record_); - } - Iptcdatum::Iptcdatum(const IptcKey& key, const Value* value) : pKey_(key.clone()), pValue_(0), modified_(false) diff --git a/src/iptc.hpp b/src/iptc.hpp index d613c1a2..5249e7c2 100644 --- a/src/iptc.hpp +++ b/src/iptc.hpp @@ -21,7 +21,7 @@ /*! @file iptc.hpp @brief Encoding and decoding of Iptc data - @version $Name: $ $Revision: 1.6 $ + @version $Name: $ $Revision: 1.7 $ @author Brad Schick (brad) schick@robotbattle.com @date 31-Jul-04, brad: created @@ -48,87 +48,6 @@ namespace Exiv2 { // ***************************************************************************** // class definitions - //! Concrete keys for Iptc metadata. - class IptcKey : public Key { - public: - //! @name Creators - //@{ - /*! - @brief Constructor to create an Iptc key from a key string. - - @param key The key string. - @throw Error ("Invalid key") if the first part of the key is not - 'Iptc' or the remaining parts of the key cannot be parsed and - converted to a record name and a dataset name. - */ - explicit IptcKey(const std::string& key); - /*! - @brief Constructor to create an Iptc key from dataset and record ids. - @param tag Dataset id - @param record Record id - */ - IptcKey(uint16_t tag, uint16_t record); - //! Copy constructor - IptcKey(const IptcKey& rhs); - //@} - - //! @name Manipulators - //@{ - /*! - @brief Assignment operator. - */ - IptcKey& operator=(const IptcKey& rhs); - //@} - - //! @name Accessors - //@{ - virtual std::string key() const { return key_; } - virtual const char* familyName() const { return familyName_; } - /*! - @brief Return the name of the group (the second part of the key). - For Iptc keys, the group name is the record name. - */ - virtual std::string groupName() const { return recordName(); } - virtual std::string tagName() const - { return IptcDataSets::dataSetName(tag_, record_); } - virtual uint16_t tag() const { return tag_; } - virtual IptcKey* clone() const; - - //! Return the name of the record - std::string recordName() const - { return IptcDataSets::recordName(record_); } - //! Return the record id - uint16_t record() const { return record_; } - //@} - - protected: - //! @name Manipulators - //@{ - /*! - @brief Set the key corresponding to the dataset and record id. - The key is of the form 'Iptc.recordName.dataSetName'. - */ - void makeKey(); - /*! - @brief Parse and convert the key string into dataset and record id. - Updates data members if the string can be decomposed, or throws - Error ("Invalid key"). - - @throw Error ("Invalid key") if the key cannot be decomposed. - */ - void decomposeKey(); - //@} - - private: - // DATA - static const char* familyName_; - - uint16_t tag_; //!< Tag value - uint16_t record_; //!< Record value - std::string key_; //!< Key - - }; // class IptcKey - /*! @brief Information related to one Iptc dataset. */ diff --git a/src/tags.cpp b/src/tags.cpp index 4d750671..7d79ca5b 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -20,23 +20,22 @@ */ /* File: tags.cpp - Version: $Name: $ $Revision: 1.36 $ + Version: $Name: $ $Revision: 1.37 $ Author(s): Andreas Huggel (ahu) History: 15-Jan-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.36 $ $RCSfile: tags.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.37 $ $RCSfile: tags.cpp,v $"); // ***************************************************************************** // included header files #include "tags.hpp" #include "error.hpp" #include "types.hpp" +#include "ifd.hpp" #include "value.hpp" - -// Todo: remove circular dependency -#include "exif.hpp" // for TagInfo operator<< +#include "makernote.hpp" #include #include @@ -392,6 +391,158 @@ namespace Exiv2 { os << gpsTagInfo[i] << "\n"; } } // ExifTags::taglist + + const char* ExifKey::familyName_ = "Exif"; + + ExifKey::ExifKey(const std::string& key) + : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""), + idx_(0), pMakerNote_(0), key_(key) + { + decomposeKey(); + } + + ExifKey::ExifKey(uint16_t tag, const std::string& ifdItem) + : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""), + idx_(0), pMakerNote_(0), key_("") + { + IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); + if (ifdId == makerIfdId) throw Error("Invalid key"); + MakerNote* pMakerNote = 0; + if (ifdId == ifdIdNotSet) { + pMakerNote = MakerNoteFactory::instance().create(ifdItem); + if (pMakerNote) ifdId = makerIfdId; + else throw Error("Invalid key"); + } + tag_ = tag; + ifdId_ = ifdId; + ifdItem_ = ifdItem; + pMakerNote_ = pMakerNote; + makeKey(); + } + + ExifKey::ExifKey(const Entry& e) + : tag_(e.tag()), ifdId_(e.ifdId()), ifdItem_(""), + idx_(e.idx()), pMakerNote_(0), key_("") + { + if (ifdId_ == makerIfdId) { + if (e.makerNote()) { + ifdItem_ = e.makerNote()->ifdItem(); + pMakerNote_ = e.makerNote()->clone(); + } + else throw Error("Invalid Key"); + } + else { + ifdItem_ = ExifTags::ifdItem(ifdId_); + } + makeKey(); + } + + ExifKey::ExifKey(const ExifKey& rhs) + : tag_(rhs.tag_), ifdId_(rhs.ifdId_), ifdItem_(rhs.ifdItem_), + idx_(rhs.idx_), + pMakerNote_(rhs.pMakerNote_ ? rhs.pMakerNote_->clone() : 0), + key_(rhs.key_) + { + } + + ExifKey::~ExifKey() + { + delete pMakerNote_; + } + + ExifKey& ExifKey::operator=(const ExifKey& rhs) + { + if (this == &rhs) return *this; + Key::operator=(rhs); + tag_ = rhs.tag_; + ifdId_ = rhs.ifdId_; + ifdItem_ = rhs.ifdItem_; + idx_ = rhs.idx_; + pMakerNote_ = rhs.pMakerNote_ ? rhs.pMakerNote_->clone() : 0; + key_ = rhs.key_; + return *this; + } + + std::string ExifKey::tagName() const + { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); + return pMakerNote_->tagName(tag_); + } + return ExifTags::tagName(tag_, ifdId_); + } + + ExifKey* ExifKey::clone() const + { + return new ExifKey(*this); + } + + std::string ExifKey::sectionName() const + { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); + return pMakerNote_->ifdItem(); + } + return ExifTags::sectionName(tag(), ifdId()); + } + + void ExifKey::decomposeKey() + { + // Get the family name, IFD name and tag name parts of the key + std::string::size_type pos1 = key_.find('.'); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string familyName = key_.substr(0, pos1); + if (familyName != std::string(familyName_)) { + throw Error("Invalid key"); + } + std::string::size_type pos0 = pos1 + 1; + pos1 = key_.find('.', pos0); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string ifdItem = key_.substr(pos0, pos1 - pos0); + if (ifdItem == "") throw Error("Invalid key"); + std::string tagName = key_.substr(pos1 + 1); + if (tagName == "") throw Error("Invalid key"); + + // Find IfdId + IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); + if (ifdId == makerIfdId) throw Error("Invalid key"); + MakerNote* pMakerNote = 0; + if (ifdId == ifdIdNotSet) { + pMakerNote = MakerNoteFactory::instance().create(ifdItem); + if (pMakerNote) ifdId = makerIfdId; + else throw Error("Invalid key"); + } + + // Convert tag + uint16_t tag = pMakerNote ? + pMakerNote->tag(tagName) : ExifTags::tag(tagName, ifdId); + // Translate hex tag name (0xabcd) to a real tag name if there is one + tagName = pMakerNote ? + pMakerNote->tagName(tag) : ExifTags::tagName(tag, ifdId); + + tag_ = tag; + ifdId_ = ifdId; + ifdItem_ = ifdItem; + pMakerNote_ = pMakerNote; + key_ = familyName + "." + ifdItem + "." + tagName; + } + + void ExifKey::makeKey() + { + key_ = std::string(familyName_) + + "." + ifdItem_ + + "." + (pMakerNote_ ? + pMakerNote_->tagName(tag_) : ExifTags::tagName(tag_, ifdId_)); + } + + std::ostream& ExifKey::printTag(std::ostream& os, const Value& value) const + { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); + return pMakerNote_->printTag(os, tag(), value); + } + return ExifTags::printTag(os, tag(), ifdId(), value); + } // ************************************************************************* // free functions diff --git a/src/tags.hpp b/src/tags.hpp index 400f10bf..ca6fb2ab 100644 --- a/src/tags.hpp +++ b/src/tags.hpp @@ -21,7 +21,7 @@ /*! @file tags.hpp @brief Exif tag and type information - @version $Name: $ $Revision: 1.27 $ + @version $Name: $ $Revision: 1.28 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
@@ -32,6 +32,7 @@ // ***************************************************************************** // included header files +#include "metadatum.hpp" #include "types.hpp" // + standard includes @@ -46,6 +47,8 @@ namespace Exiv2 { // ***************************************************************************** // class declarations class Value; + class Entry; + class MakerNote; // ***************************************************************************** // type definitions @@ -192,6 +195,103 @@ namespace Exiv2 { }; // class ExifTags + /*! + @brief Concrete keys for Exif metadata. + */ + class ExifKey : public Key { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to create an Exif key from a key string. + + @param key The key string. + @throw Error ("Invalid key") if the key cannot be parsed into three + parts or the first part of the key is not 'Exif'. + */ + explicit ExifKey(const std::string& key); + /*! + @brief Constructor to create an Exif key from a tag and IFD item + string. + @param tag The tag value + @param ifdItem The IFD string. For MakerNote tags, this must be the + IFD item of the specific MakerNote. "MakerNote" is not allowed. + @throw Error ("Invalid key") if the key cannot be constructed from + the tag and IFD item parameters. + */ + ExifKey(uint16_t tag, const std::string& ifdItem); + //! Constructor to build an ExifKey from an IFD entry. + explicit ExifKey(const Entry& e); + //! Copy constructor + ExifKey(const ExifKey& rhs); + virtual ~ExifKey(); + //@} + + //! @name Manipulators + //@{ + /*! + @brief Assignment operator. + */ + ExifKey& operator=(const ExifKey& rhs); + //@} + + //! @name Accessors + //@{ + virtual std::string key() const { return key_; } + virtual const char* familyName() const { return familyName_; } + /*! + @brief Return the name of the group (the second part of the key). + For Exif keys, the group name is the IFD item. + */ + virtual std::string groupName() const { return ifdItem(); } + virtual std::string tagName() const; + virtual uint16_t tag() const { return tag_; } + virtual ExifKey* clone() const; + + //! Interpret and print the value of an Exif tag + std::ostream& printTag(std::ostream& os, const Value& value) const; + //! Return the IFD id + IfdId ifdId() const { return ifdId_; } + //! Return the name of the IFD + const char* ifdName() const { return ExifTags::ifdName(ifdId()); } + //! Return the related image item + std::string ifdItem() const { return ifdItem_; } + //! Return the name of the Exif section (deprecated) + std::string sectionName() const; + //! Return the index (unique id of this key within the original IFD) + int idx() const { return idx_; } + //@} + + protected: + //! @name Manipulators + //@{ + /*! + @brief Set the key corresponding to the tag and IFD id. + The key is of the form 'Exif.ifdItem.tagName'. + */ + void makeKey(); + /*! + @brief Parse and convert the key string into tag and IFD Id. + Updates data members if the string can be decomposed, + or throws Error ("Invalid key"). + + @throw Error ("Invalid key") if the key cannot be decomposed. + */ + void decomposeKey(); + //@} + + private: + // DATA + static const char* familyName_; + + uint16_t tag_; //!< Tag value + IfdId ifdId_; //!< The IFD associated with this tag + std::string ifdItem_; //!< The IFD item + int idx_; //!< Unique id of an entry within one IFD + MakerNote* pMakerNote_; //!< Pointer to the associated MakerNote + std::string key_; //!< Key + }; // class ExifKey + // ***************************************************************************** // free functions