diff --git a/src/canonmn.hpp b/src/canonmn.hpp index 05c958b9..1f341977 100644 --- a/src/canonmn.hpp +++ b/src/canonmn.hpp @@ -23,7 +23,7 @@ @brief Canon MakerNote implemented according to the specification EXIF MakerNote of Canon by David Burren - @version $Name: $ $Revision: 1.11 $ + @version $Name: $ $Revision: 1.12 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 18-Feb-04, ahu: created
@@ -177,6 +177,7 @@ namespace Exiv2 { { MakerNoteFactory& mnf = MakerNoteFactory::instance(); mnf.registerMakerNote("Canon", "*", createCanonMakerNote); + mnf.registerMakerNote(new CanonMakerNote); } }; /*! diff --git a/src/exif.cpp b/src/exif.cpp index 1f23ad77..5cb2f632 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -20,14 +20,14 @@ */ /* File: exif.cpp - Version: $Name: $ $Revision: 1.58 $ + Version: $Name: $ $Revision: 1.59 $ 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.58 $ $RCSfile: exif.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.59 $ $RCSfile: exif.cpp,v $"); // Define DEBUG_MAKERNOTE to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -73,22 +73,62 @@ namespace { // class member definitions namespace Exiv2 { + const char* ExifKey::familyName_ = "Exif"; + ExifKey::ExifKey(const std::string& key) - : idx_(0), pMakerNote_(0), key_(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()), idx_(e.idx()), - pMakerNote_(e.makerNote()), key_(makeKey(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_), idx_(rhs.idx_), - pMakerNote_(rhs.pMakerNote_), key_(rhs.key_) + : 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) @@ -97,40 +137,22 @@ namespace Exiv2 { Key::operator=(rhs); tag_ = rhs.tag_; ifdId_ = rhs.ifdId_; + ifdItem_ = rhs.ifdItem_; idx_ = rhs.idx_; - pMakerNote_ = rhs.pMakerNote_; + pMakerNote_ = rhs.pMakerNote_ ? rhs.pMakerNote_->clone() : 0; key_ = rhs.key_; return *this; } - void ExifKey::setMakerNote(MakerNote* pMakerNote) - { - if (ifdId_ == makerIfdId && pMakerNote_ != pMakerNote) { - pMakerNote_ = pMakerNote; - decomposeKey(); - } - } - std::string ExifKey::tagName() const { - if (ifdId_ == makerIfdId && pMakerNote_ != 0) { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); return pMakerNote_->tagName(tag_); } - return ExifTags::tagName(tag(), ifdId()); - } - - uint16_t ExifKey::tag() const - { - if (tag_ == 0xffff) throw Error("Invalid key"); - return tag_; - } - - IfdId ExifKey::ifdId() const - { - if (ifdId_ == ifdIdNotSet) throw Error("Invalid key"); - return ifdId_; + return ExifTags::tagName(tag_, ifdId_); } - + ExifKey* ExifKey::clone() const { return new ExifKey(*this); @@ -138,7 +160,8 @@ namespace Exiv2 { std::string ExifKey::sectionName() const { - if (ifdId_ == makerIfdId && pMakerNote_ != 0) { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); return pMakerNote_->ifdItem(); } return ExifTags::sectionName(tag(), ifdId()); @@ -146,26 +169,57 @@ namespace Exiv2 { void ExifKey::decomposeKey() { - std::pair p; - if (ifdId_ == makerIfdId && pMakerNote_ != 0) { - p.first = pMakerNote_->decomposeKey(key_); - if (p.first == 0xffff) throw Error("Invalid key"); - p.second = makerIfdId; - } - else { - p = ExifTags::decomposeKey(key_); - // If it's couldn't be parsed, we assume it is an incomplete - // makernote key (pMakerNote_ not set) - if (p.second == ifdIdNotSet) p.second = makerIfdId; - // No checks as this could still be an incomplete makernote key - } - tag_ = p.first; - ifdId_ = p.second; + // 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); + pos0 = pos1 + 1; + std::string tagName = key_.substr(pos0); + 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 && pMakerNote_ != 0) { + if (ifdId_ == makerIfdId) { + assert(pMakerNote_); return pMakerNote_->printTag(os, tag(), value); } return ExifTags::printTag(os, tag(), ifdId(), value); @@ -974,7 +1028,6 @@ namespace Exiv2 { { // Todo: Implement a more suitable ExifKey c'tor ExifKey k(key); - k.setMakerNote(pMakerNote_); add(Exifdatum(k, pValue)); } @@ -1316,7 +1369,8 @@ namespace Exiv2 { DataBuf buf(md.size()); md.copy(buf.pData_, byteOrder); - e.setValue(static_cast(md.typeId()), md.count(), buf.pData_, md.size()); + e.setValue(static_cast(md.typeId()), md.count(), + buf.pData_, md.size()); ifd.add(e); } // addToIfd @@ -1355,24 +1409,6 @@ namespace Exiv2 { return md.pKey_->printTag(os, md.value()); } - std::string makeKey(const Entry& entry) - { - if (entry.ifdId() == makerIfdId && entry.makerNote() != 0) { - return entry.makerNote()->makeKey(entry.tag()); - } - return ExifTags::makeKey(entry.tag(), entry.ifdId()); - } - - std::pair decomposeKey(const std::string& key, - const MakerNote* makerNote) - { - std::pair p = ExifTags::decomposeKey(key); - if (p.second == makerIfdId && makerNote != 0) { - p.first = makerNote->decomposeKey(key); - } - return p; - } - } // namespace Exiv2 // ***************************************************************************** diff --git a/src/exif.hpp b/src/exif.hpp index 63071da8..0f4b09f1 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.51 $ + @version $Name: $ $Revision: 1.52 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created @@ -73,11 +73,21 @@ namespace Exiv2 { 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); - // A destructor is not needed, as we do *not* delete the makernote + virtual ~ExifKey(); //@} //! @name Manipulators @@ -86,34 +96,25 @@ namespace Exiv2 { @brief Assignment operator. */ ExifKey& operator=(const ExifKey& rhs); - //! Set the makernote pointer. - void setMakerNote(MakerNote* pMakerNote); //@} //! @name Accessors //@{ virtual std::string key() const { return key_; } - virtual const char* familyName() const { return ExifTags::familyName(); } + 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 name. + For Exif keys, the group name is the IFD item. */ - virtual std::string groupName() const { return ifdName(); } + virtual std::string groupName() const { return ifdItem(); } virtual std::string tagName() const; - /*! - @brief Return the tag. - @throw Error ("Invalid key") if the tag is not set. - */ - virtual uint16_t tag() 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; - /*! - @brief Return the IFD id - @throw Error ("Invalid key") if the IFD id is not set. - */ - IfdId ifdId() 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 @@ -122,30 +123,33 @@ namespace Exiv2 { std::string sectionName() const; //! Return the index (unique id of this key within the original IFD) int idx() const { return idx_; } - //! Return the pointer to the associated MakerNote - MakerNote* makerNote() const { return pMakerNote_; } //@} protected: //! @name Manipulators //@{ /*! - @brief Parse and convert the key string into tag, and IFD Id. - Forwards the request to MakerNote::decomposeKey if necessary. - Updates key_ and ifdId_ if the string can be decomposed, + @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 memebers if the string can be decomposed, or throws Error ("Invalid key"). - @throw Error ("Invalid key") if pMakerNote_ is ot 0 and the key - cannot be parsed into family name, group name and tag name - parts. + @throw Error ("Invalid key") Todo: add conditions */ void decomposeKey(); //@} private: // DATA - uint16_t tag_; //!< Tag value + 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 @@ -951,22 +955,6 @@ namespace Exiv2 { void addToMakerNote(MakerNote* makerNote, const Exifdatum& exifdatum, ByteOrder byteOrder); - /*! - @brief Return a key for the entry. The key is of the form - 'Exif.ifdItem.tagName'. This function knows about - MakerNotes, i.e., it will invoke MakerNote::makeKey if necessary. - */ - std::string makeKey(const Entry& entry); - /*! - @brief Return the tag and IFD id pair for the key. This function knows - about MakerNotes, i.e., it will forward the request to - MakerNote::decomposeKey if necessary. - @return A pair consisting of the tag and IFD id. - @throw Error ("Invalid key") if the key cannot be parsed into - item item, section name and tag name parts. - */ - std::pair decomposeKey(const std::string& key, - const MakerNote* makerNote); } // namespace Exiv2 diff --git a/src/fujimn.hpp b/src/fujimn.hpp index bacb7688..1223511f 100644 --- a/src/fujimn.hpp +++ b/src/fujimn.hpp @@ -24,7 +24,7 @@ in Appendix 4: Makernote of Fujifilm of the document Exif file format by TsuruZoh Tachibanaya - @version $Name: $ $Revision: 1.8 $ + @version $Name: $ $Revision: 1.9 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Feb-04, ahu: created @@ -141,6 +141,7 @@ namespace Exiv2 { { MakerNoteFactory& mnf = MakerNoteFactory::instance(); mnf.registerMakerNote("FUJIFILM", "*", createFujiMakerNote); + mnf.registerMakerNote(new FujiMakerNote); } }; /*! diff --git a/src/key-test.cpp b/src/key-test.cpp index c3ad6d53..03d531ba 100644 --- a/src/key-test.cpp +++ b/src/key-test.cpp @@ -3,7 +3,7 @@ Abstract : Key unit tests File : key-test.cpp - Version : $Name: $ $Revision: 1.2 $ + Version : $Name: $ $Revision: 1.3 $ Author(s): Andreas Huggel (ahu) History : 24-Aug-04, ahu: created @@ -201,6 +201,34 @@ int main() // ----- + ExifKey ek4("Exif.Image.0x0110"); + tc += 1; + if (ek4.key() != "Exif.Image.Model") { + std::cout << "Testcase failed (converted key)" << std::endl; + rc += 1; + } + tc += 1; + if (ek4.tagName() != "Model") { + std::cout << "Testcase failed (converted tagName)" << std::endl; + rc += 1; + } + + // ----- + + ExifKey ek5("Exif.Nikon3.0x0007"); + tc += 1; + if (ek5.key() != "Exif.Nikon3.Focus") { + std::cout << "Testcase failed (converted key)" << std::endl; + rc += 1; + } + tc += 1; + if (ek5.tagName() != "Focus") { + std::cout << "Testcase failed (converted tagName)" << std::endl; + rc += 1; + } + + // ----- + if (rc == 0) { std::cout << "All " << tc << " testcases passed." << std::endl; } diff --git a/src/makernote.cpp b/src/makernote.cpp index 8eb81968..99a5822e 100644 --- a/src/makernote.cpp +++ b/src/makernote.cpp @@ -20,13 +20,13 @@ */ /* File: makernote.cpp - Version: $Name: $ $Revision: 1.27 $ + Version: $Name: $ $Revision: 1.28 $ Author(s): Andreas Huggel (ahu) History: 18-Feb-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.27 $ $RCSfile: makernote.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.28 $ $RCSfile: makernote.cpp,v $"); // Define DEBUG_* to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -38,14 +38,17 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.27 $ $RCSfile: makernote.cpp,v $"); #include "tags.hpp" // for ExifTags::ifdItem #include "error.hpp" +// Todo: remove circular dependency +#include "exif.hpp" // for MakerNote::writeMnTagInfo + // + standard includes #include #include #include - #if defined DEBUG_MAKERNOTE || defined DEBUG_REGISTRY -# include +# include #endif +#include // ***************************************************************************** // class member definitions @@ -57,35 +60,6 @@ namespace Exiv2 { { } - std::string MakerNote::makeKey(uint16_t tag) const - { - return std::string(ExifTags::familyName()) - + "." + std::string(ifdItem()) - + "." + tagName(tag); - } // MakerNote::makeKey - - uint16_t MakerNote::decomposeKey(const std::string& key) const - { - // Get the family, item 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); - 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); - pos0 = pos1 + 1; - std::string tagName = key.substr(pos0); - if (tagName == "") throw Error("Invalid key"); - - if (familyName != ExifTags::familyName()) return 0xffff; - uint16_t tag = this->tag(tagName); - if (tag == 0xffff) return tag; - if (ifdItem != this->ifdItem()) return 0xffff; - - return tag; - } // MakerNote::decomposeKey - std::string MakerNote::tagName(uint16_t tag) const { std::string tagName; @@ -149,12 +123,13 @@ namespace Exiv2 { std::ostream& MakerNote::writeMnTagInfo(std::ostream& os, uint16_t tag) const { + ExifKey exifKey(tag, ifdItem()); return os << tagName(tag) << ", " << std::dec << tag << ", " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << tag << ", " << ExifTags::ifdItem(makerIfdId) << ", " - << makeKey(tag) << ", " + << exifKey.key() << ", " << tagDesc(tag); } // MakerNote::writeMnTagInfo @@ -268,6 +243,21 @@ namespace Exiv2 { return *pInstance_; } // MakerNoteFactory::instance + void MakerNoteFactory::registerMakerNote(MakerNote* pMakerNote) + { + assert(pMakerNote); + ifdItemRegistry_[pMakerNote->ifdItem()] = pMakerNote; + } // MakerNoteFactory::registerMakerNote + + MakerNote* MakerNoteFactory::create(const std::string& ifdItem, + bool alloc) const + { + IfdItemRegistry::const_iterator i = ifdItemRegistry_.find(ifdItem); + if (i == ifdItemRegistry_.end()) return 0; + assert(i->second); + return i->second->clone(alloc); + } // MakerNoteFactory::create + void MakerNoteFactory::registerMakerNote(const std::string& make, const std::string& model, CreateFct createMakerNote) diff --git a/src/makernote.hpp b/src/makernote.hpp index aef50307..af81d9f1 100644 --- a/src/makernote.hpp +++ b/src/makernote.hpp @@ -22,7 +22,7 @@ @file makernote.hpp @brief Contains the Exif %MakerNote interface, IFD %MakerNote and a MakerNote factory - @version $Name: $ $Revision: 1.23 $ + @version $Name: $ $Revision: 1.24 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 18-Feb-04, ahu: created @@ -40,6 +40,7 @@ #include #include #include +#include // ***************************************************************************** // namespace extensions @@ -73,7 +74,7 @@ namespace Exiv2 { - read the makernote from a character buffer - copy the makernote to a character buffer - maintain a list of makernote entries (similar to IFD entries) - - provide makernote specific tag names and keys + - provide makernote specific tag names and tag information - interpret (print) the values of makernote tags Makernotes can be added to the system by subclassing %MakerNote and @@ -164,10 +165,6 @@ namespace Exiv2 { //! @name Accessors //@{ - //! Return the key for the tag. - std::string makeKey(uint16_t tag) const; - //! Return the associated tag for a makernote key. - uint16_t decomposeKey(const std::string& key) const; //! Return the byte order (little or big endian). ByteOrder byteOrder() const { return byteOrder_; } //! Return the offset of the makernote from the start of the TIFF header @@ -179,24 +176,24 @@ namespace Exiv2 { the tag. */ virtual std::string tagName(uint16_t tag) const; + /*! + @brief Return the tag associated with a makernote tag name. The + default implementation looks up the makernote info tag array + if one is set, else it expects tag names in the form "0x01ff" + and converts them to unsigned integer. + */ + virtual uint16_t tag(const std::string& tagName) const; /*! @brief Return the description of a makernote tag. The default implementation looks up the makernote info tag array if one is set, else it returns an empty string. */ - virtual uint16_t tag(const std::string& tagName) const; + virtual std::string tagDesc(uint16_t tag) const; /*! @brief Print a list of all tags known by this MakerNote to the output stream os. The default implementation prints all tags in the makernote info tag array if one is set. */ - virtual std::string tagDesc(uint16_t tag) const; - /*! - @brief Return the tag associated with a makernote tag name. The - default implementation looks up the makernote info tag array - if one is set, else it expects tag names in the form \"0x01ff\" - and converts them to unsigned integer. - */ virtual void taglist(std::ostream& os) const; /*! @brief Write the makernote tag info of tag to the output stream os. @@ -395,6 +392,9 @@ namespace Exiv2 { void registerMakerNote(const std::string& make, const std::string& model, CreateFct createMakerNote); + + //! Register a %MakerNote prototype in the IFD item registry. + void registerMakerNote(MakerNote* pMakerNote); //@} //! @name Accessors @@ -449,6 +449,9 @@ namespace Exiv2 { long len, ByteOrder byteOrder, long offset) const; + + //! Create a %MakerNote based on its IFD item string. + MakerNote* create(const std::string& ifdItem, bool alloc =true) const; //@} /*! @@ -483,12 +486,16 @@ namespace Exiv2 { typedef std::vector > ModelRegistry; //! Type used to store a list of make labels and model registries typedef std::vector > Registry; + //! Type used to store a list of IFD items and %MakerNote prototypes + typedef std::map IfdItemRegistry; // DATA //! Pointer to the one and only instance of this class. static MakerNoteFactory* pInstance_; //! List of makernote types and corresponding makernote create functions. Registry registry_; + //! List of makernote IfdItems and corresponding create functions. + IfdItemRegistry ifdItemRegistry_; }; // class MakerNoteFactory diff --git a/src/nikonmn.cpp b/src/nikonmn.cpp index cc081b59..1138cbd8 100644 --- a/src/nikonmn.cpp +++ b/src/nikonmn.cpp @@ -20,14 +20,14 @@ */ /* File: nikon1mn.cpp - Version: $Name: $ $Revision: 1.6 $ + Version: $Name: $ $Revision: 1.7 $ Author(s): Andreas Huggel (ahu) History: 17-May-04, ahu: created 25-May-04, ahu: combined all Nikon formats in one component */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.6 $ $RCSfile: nikonmn.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.7 $ $RCSfile: nikonmn.cpp,v $"); // ***************************************************************************** // included header files @@ -183,6 +183,8 @@ namespace Exiv2 { return os; } + const Nikon2MakerNote::RegisterMakerNote Nikon2MakerNote::register_; + // Nikon2 MakerNote Tag Info static const MakerNote::MnTagInfo nikon2MnTagInfo[] = { MakerNote::MnTagInfo(0x0003, "Quality", "Image quality setting"), @@ -348,6 +350,8 @@ namespace Exiv2 { return os; } + const Nikon3MakerNote::RegisterMakerNote Nikon3MakerNote::register_; + // Nikon3 MakerNote Tag Info static const MakerNote::MnTagInfo nikon3MnTagInfo[] = { MakerNote::MnTagInfo(0x0001, "Version", "Nikon Makernote version"), diff --git a/src/nikonmn.hpp b/src/nikonmn.hpp index 17f93b69..6b55a3bf 100644 --- a/src/nikonmn.hpp +++ b/src/nikonmn.hpp @@ -28,7 +28,7 @@ Exif file format by TsuruZoh Tachibanaya.
Format 3: "EXIFutils Field Reference Guide". - @version $Name: $ $Revision: 1.5 $ + @version $Name: $ $Revision: 1.6 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 17-May-04, ahu: created
@@ -132,6 +132,7 @@ namespace Exiv2 { { MakerNoteFactory& mnf = MakerNoteFactory::instance(); mnf.registerMakerNote("NIKON*", "*", createNikonMakerNote); + mnf.registerMakerNote(new Nikon1MakerNote); } }; // DATA @@ -206,6 +207,30 @@ namespace Exiv2 { //@} private: + //! Structure used to auto-register the MakerNote. + struct RegisterMakerNote { + //! Default constructor + RegisterMakerNote() + { + MakerNoteFactory& mnf = MakerNoteFactory::instance(); + mnf.registerMakerNote(new Nikon2MakerNote); + } + }; + // DATA + /*! + The static member variable is initialized before main (see note) and + will in the process register the MakerNote class. (Remember the + definition of the variable in the implementation file!) + + @note The standard says that, if no function is explicitly called ever + in a module, then that module's static data might be never + initialized. This clause was introduced to allow dynamic link + libraries. The idea is, with this clause the loader is not + forced to eagerly load all modules, but load them only on + demand. + */ + static const RegisterMakerNote register_; + //! The item name (second part of the key) used for makernote tags std::string ifdItem_; @@ -258,6 +283,30 @@ namespace Exiv2 { //@} private: + //! Structure used to auto-register the MakerNote. + struct RegisterMakerNote { + //! Default constructor + RegisterMakerNote() + { + MakerNoteFactory& mnf = MakerNoteFactory::instance(); + mnf.registerMakerNote(new Nikon3MakerNote); + } + }; + // DATA + /*! + The static member variable is initialized before main (see note) and + will in the process register the MakerNote class. (Remember the + definition of the variable in the implementation file!) + + @note The standard says that, if no function is explicitly called ever + in a module, then that module's static data might be never + initialized. This clause was introduced to allow dynamic link + libraries. The idea is, with this clause the loader is not + forced to eagerly load all modules, but load them only on + demand. + */ + static const RegisterMakerNote register_; + //! The item name (second part of the key) used for makernote tags std::string ifdItem_; diff --git a/src/sigmamn.hpp b/src/sigmamn.hpp index c6ff0883..afb74783 100644 --- a/src/sigmamn.hpp +++ b/src/sigmamn.hpp @@ -23,7 +23,7 @@ @brief Sigma and Foveon MakerNote implemented according to the specification SIGMA and FOVEON EXIF MakerNote Documentation by Foveon. - @version $Name: $ $Revision: 1.8 $ + @version $Name: $ $Revision: 1.9 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 02-Apr-04, ahu: created @@ -131,6 +131,7 @@ namespace Exiv2 { MakerNoteFactory& mnf = MakerNoteFactory::instance(); mnf.registerMakerNote("SIGMA", "*", createSigmaMakerNote); mnf.registerMakerNote("FOVEON", "*", createSigmaMakerNote); + mnf.registerMakerNote(new SigmaMakerNote); } }; // DATA diff --git a/src/taglist.cpp b/src/taglist.cpp index d576afb2..ab0d469e 100644 --- a/src/taglist.cpp +++ b/src/taglist.cpp @@ -3,19 +3,15 @@ Abstract: Print a simple comma separated list of tags defined in Exiv2 File: taglist.cpp - Version: $Name: $ $Revision: 1.9 $ + Version: $Name: $ $Revision: 1.10 $ Author(s): Andreas Huggel (ahu) History: 07-Jan-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: taglist.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.10 $ $RCSfile: taglist.cpp,v $"); #include "makernote.hpp" -#include "nikonmn.hpp" -#include "sigmamn.hpp" -#include "fujimn.hpp" -#include "canonmn.hpp" #include "tags.hpp" #include "datasets.hpp" #include "error.hpp" @@ -38,26 +34,8 @@ try { IptcDataSets::dataSetList(std::cout); break; } - - if (item == "Canon") { - pMakerNote = new CanonMakerNote; - } - else if (item == "Fujifilm") { - pMakerNote = new FujiMakerNote; - } - else if (item == "Sigma") { - pMakerNote = new SigmaMakerNote; - } - else if (item == "Nikon1") { - pMakerNote = new Nikon1MakerNote; - } - else if (item == "Nikon2") { - pMakerNote = new Nikon2MakerNote; - } - else if (item == "Nikon3") { - pMakerNote = new Nikon3MakerNote; - } - + + pMakerNote = MakerNoteFactory::instance().create(item); if (pMakerNote) { pMakerNote->taglist(std::cout); delete pMakerNote; diff --git a/src/tags.cpp b/src/tags.cpp index fef2e227..4d750671 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -20,13 +20,13 @@ */ /* File: tags.cpp - Version: $Name: $ $Revision: 1.35 $ + Version: $Name: $ $Revision: 1.36 $ Author(s): Andreas Huggel (ahu) History: 15-Jan-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.35 $ $RCSfile: tags.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.36 $ $RCSfile: tags.cpp,v $"); // ***************************************************************************** // included header files @@ -35,6 +35,9 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.35 $ $RCSfile: tags.cpp,v $"); #include "types.hpp" #include "value.hpp" +// Todo: remove circular dependency +#include "exif.hpp" // for TagInfo operator<< + #include #include #include @@ -266,24 +269,26 @@ namespace Exiv2 { 0 }; - const char* ExifTags::familyName_ = "Exif"; - int ExifTags::tagInfoIdx(uint16_t tag, IfdId ifdId) { const TagInfo* tagInfo = tagInfos_[ifdId]; if (tagInfo == 0) return -1; int idx; for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) { - if (tagInfo[idx].tag_ == tag) break; + if (tagInfo[idx].tag_ == tag) return idx; } - return idx; + return -1; } - const char* ExifTags::tagName(uint16_t tag, IfdId ifdId) + std::string ExifTags::tagName(uint16_t tag, IfdId ifdId) { int idx = tagInfoIdx(tag, ifdId); - if (idx == -1) throw Error("No taginfo for IFD"); - return tagInfos_[ifdId][idx].name_; + if (idx != -1) return tagInfos_[ifdId][idx].name_; + + std::ostringstream os; + os << "0x" << std::setw(4) << std::setfill('0') << std::right + << std::hex << tag; + return os.str(); } const char* ExifTags::tagDesc(uint16_t tag, IfdId ifdId) @@ -311,13 +316,30 @@ namespace Exiv2 { uint16_t ExifTags::tag(const std::string& tagName, IfdId ifdId) { + uint16_t tag = 0xffff; const TagInfo* tagInfo = tagInfos_[ifdId]; - if (tagInfo == 0) return 0xffff; - int idx; - for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) { - if (tagInfo[idx].name_ == tagName) break; + if (tagInfo) { + int idx; + for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) { + if (tagInfo[idx].name_ == tagName) break; + } + tag = tagInfo[idx].tag_; + } + if (tag == 0xffff) { + // Todo: Check format of tagName + std::istringstream is(tagName); + is >> std::hex >> tag; + } + return tag; + } + + IfdId ExifTags::ifdIdByIfdItem(const std::string& ifdItem) + { + int i; + for (i = int(lastIfdId) - 1; i > 0; --i) { + if (ifdInfo_[i].item_ == ifdItem) break; } - return tagInfo[idx].tag_; + return IfdId(i); } const char* ExifTags::ifdName(IfdId ifdId) @@ -344,44 +366,6 @@ namespace Exiv2 { return SectionId(i); } - std::string ExifTags::makeKey(uint16_t tag, IfdId ifdId) - { - return std::string(familyName()) - + "." + std::string(ifdItem(ifdId)) - + "." + std::string(tagName(tag, ifdId)); - } - - // This 'database lookup' function returns the first match that - // we find, it doesn't verify whether this is the only match. - std::pair ExifTags::decomposeKey(const std::string& key) - { - // 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(ExifTags::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); - pos0 = pos1 + 1; - std::string tagName = key.substr(pos0); - if (tagName == "") throw Error("Invalid key"); - - // Find IfdId - int i; - for (i = int(lastIfdId) - 1; i > 0; --i) { - if (ifdInfo_[i].item_ == ifdItem) break; - } - IfdId ifdId = IfdId(i); - - if (ifdId == ifdIdNotSet) return std::make_pair(0xffff, ifdId); - - return std::make_pair(tag(tagName, ifdId), ifdId); - } // ExifTags::decomposeKey - std::ostream& ExifTags::printTag(std::ostream& os, uint16_t tag, IfdId ifdId, @@ -414,12 +398,13 @@ namespace Exiv2 { std::ostream& operator<<(std::ostream& os, const TagInfo& ti) { + ExifKey exifKey(ti.tag_, ExifTags::ifdItem(ti.ifdId_)); return os << ExifTags::tagName(ti.tag_, ti.ifdId_) << ", " << std::dec << ti.tag_ << ", " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << ti.tag_ << ", " << ExifTags::ifdName(ti.ifdId_) << ", " - << ExifTags::makeKey(ti.tag_, ti.ifdId_) << ", " + << exifKey.key() << ", " << ExifTags::tagDesc(ti.tag_, ti.ifdId_); } diff --git a/src/tags.hpp b/src/tags.hpp index 0a3a6593..400f10bf 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.26 $ + @version $Name: $ $Revision: 1.27 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
@@ -114,19 +114,18 @@ namespace Exiv2 { ExifTags& operator=(const ExifTags& rhs); public: - //! Return an identifier for Exif metadata - static const char* familyName() { return familyName_; } - /*! - @brief Return the name of the tag. + @brief Return the name of the tag or a string with the hexadecimal + value of the tag in the form "0x01ff", if the tag is not + a known Exif tag. + @param tag The tag @param ifdId IFD id - @return The name of the tag or a string indicating that the - tag is unknown. - @throw Error ("No taginfo for IFD") if there is no tag info - data for the given IFD id in the lookup tables. + @return The name of the tag or a string containing the hexadecimal + value of the tag in the form "0x01ff", if this is an unknown + tag. */ - static const char* tagName(uint16_t tag, IfdId ifdId); + static std::string tagName(uint16_t tag, IfdId ifdId); /*! @brief Return the description of the tag. @param tag The tag @@ -137,8 +136,14 @@ namespace Exiv2 { data for the given IFD id in the lookup tables. */ static const char* tagDesc(uint16_t tag, IfdId ifdId); - //! Return the tag for one combination of IFD id and tagName + /*! + @brief Return the tag for one combination of IFD id and tagName. + If the tagName is not known, it expects tag names in the + form "0x01ff" and converts them to unsigned integer. + */ static uint16_t tag(const std::string& tagName, IfdId ifdId); + //! Return the IFD id for an IFD item + static IfdId ifdIdByIfdItem(const std::string& ifdItem); //! Return the name of the IFD static const char* ifdName(IfdId ifdId); //! Return the related image item (image or thumbnail) @@ -169,18 +174,6 @@ namespace Exiv2 { static const char* sectionDesc(uint16_t tag, IfdId ifdId); //! Return the section id for a section name static SectionId sectionId(const std::string& sectionName); - /*! - @brief Return the key for the tag and IFD id. The key is of the form - 'Exif.ifdItem.tagName'. - */ - static std::string makeKey(uint16_t tag, IfdId ifdId); - /*! - @brief Return tag and IFD id pair for the key. - @return A pair consisting of the tag and IFD id. - @throw Error ("Invalid key") if the key cannot be parsed into - item item, section name and tag name parts. - */ - static std::pair decomposeKey(const std::string& key); //! Interpret and print the value of an Exif tag static std::ostream& printTag(std::ostream& os, uint16_t tag, @@ -192,8 +185,6 @@ namespace Exiv2 { private: static int tagInfoIdx(uint16_t tag, IfdId ifdId); - static const char* familyName_; - static const IfdInfo ifdInfo_[]; static const SectionInfo sectionInfo_[];