diff --git a/src/actions.cpp b/src/actions.cpp index 7fc56cab..aced45d2 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -20,13 +20,13 @@ */ /* File: actions.cpp - Version: $Name: $ $Revision: 1.32 $ + Version: $Name: $ $Revision: 1.33 $ Author(s): Andreas Huggel (ahu) History: 08-Dec-03, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.32 $ $RCSfile: actions.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.33 $ $RCSfile: actions.cpp,v $"); // ***************************************************************************** // included header files @@ -163,25 +163,26 @@ namespace Action { } // Camera make - printTag(exifData, "Image.OtherTags.Make", "Camera make"); + printTag(exifData, "Exif.Image.Make", "Camera make"); // Camera model - printTag(exifData, "Image.OtherTags.Model", "Camera model"); + printTag(exifData, "Exif.Image.Model", "Camera model"); // Image Timestamp - printTag(exifData, "Image.DateTime.DateTimeOriginal", "Image timestamp"); + printTag(exifData, "Exif.Photo.DateTimeOriginal", "Image timestamp"); // Image number // Todo: Image number for cameras other than Canon - printTag(exifData, "Makernote.Canon.ImageNumber", "Image number"); + printTag(exifData, "Exif.Canon.ImageNumber", "Image number"); // Exposure time // From ExposureTime, failing that, try ShutterSpeedValue std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Exposure time" << ": "; Exiv2::ExifData::const_iterator md; - if (0 == printTag(exifData, "Image.CaptureConditions.ExposureTime")) { - md = exifData.findKey("Image.CaptureConditions.ShutterSpeedValue"); + if (0 == printTag(exifData, "Exif.Photo.ExposureTime")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Photo.ShutterSpeedValue")); if (md != exifData.end()) { double tmp = exp(log(2.0) * md->toFloat()) + 0.5; if (tmp > 1) { @@ -198,8 +199,9 @@ namespace Action { // Get if from FNumber and, failing that, try ApertureValue std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Aperture" << ": "; - if (0 == printTag(exifData, "Image.CaptureConditions.FNumber")) { - md = exifData.findKey("Image.CaptureConditions.ApertureValue"); + if (0 == printTag(exifData, "Exif.Photo.FNumber")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Photo.ApertureValue")); if (md != exifData.end()) { std::cout << std::fixed << std::setprecision(1) << "F" << exp(log(2.0) * md->toFloat() / 2); @@ -208,16 +210,16 @@ namespace Action { std::cout << "\n"; // Exposure bias - printTag(exifData, "Image.CaptureConditions.ExposureBiasValue", "Exposure bias"); + printTag(exifData, "Exif.Photo.ExposureBiasValue", "Exposure bias"); // Flash - printTag(exifData, "Image.CaptureConditions.Flash", "Flash"); + printTag(exifData, "Exif.Photo.Flash", "Flash"); // Todo: Flash bias, flash energy // Todo: Implement this for other cameras std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Flash bias" << ": "; - md = exifData.findKey("Makernote.Canon.CameraSettings2"); + md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings2")); if (md != exifData.end() && md->count() >= 15) { Exiv2::CanonMakerNote::print0x0004_15(std::cout, md->toLong(15)); } @@ -227,8 +229,9 @@ namespace Action { // Todo: Calculate 35 mm equivalent a la jhead std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Focal length" << ": "; - if (1 == printTag(exifData, "Image.CaptureConditions.FocalLength")) { - md = exifData.findKey("Image.CaptureConditions.FocalLengthIn35mmFilm"); + if (1 == printTag(exifData, "Exif.Photo.FocalLength")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Photo.FocalLengthIn35mmFilm")); if (md != exifData.end()) { std::cout << " (35 mm equivalent: " << *md << ")"; } @@ -238,8 +241,9 @@ namespace Action { // Subject distance std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Subject distance" << ": "; - if (0 == printTag(exifData, "Image.CaptureConditions.SubjectDistance")) { - md = exifData.findKey("Makernote.Canon.CameraSettings2"); + if (0 == printTag(exifData, "Exif.Photo.SubjectDistance")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Canon.CameraSettings2")); if (md != exifData.end() && md->count() >= 19) { Exiv2::CanonMakerNote::print0x0004_19(std::cout, md->toLong(19)); } @@ -251,20 +255,21 @@ namespace Action { std::cout << std::setw(align_) << std::setfill(' ') << std::left << "ISO speed" << ": "; bool done = false; - if (0 == printTag(exifData, "Image.CaptureConditions.ISOSpeedRatings")) { - md = exifData.findKey("Makernote.Canon.CameraSettings1"); + if (0 == printTag(exifData, "Exif.Photo.ISOSpeedRatings")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Canon.CameraSettings1")); if (md != exifData.end() && md->count() >= 16) { Exiv2::CanonMakerNote::print0x0001_16(std::cout, md->toLong(16)); done = true; } if (!done) { - done = printTag(exifData, "Makernote.Nikon1.ISOSpeed"); + done = printTag(exifData, "Exif.Nikon1.ISOSpeed"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon2.ISOSpeed"); + done = printTag(exifData, "Exif.Nikon2.ISOSpeed"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon3.ISOSpeed"); + done = printTag(exifData, "Exif.Nikon3.ISOSpeed"); } } std::cout << "\n"; @@ -273,8 +278,9 @@ namespace Action { // From ExposureProgram or Canon Makernote std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Exposure mode" << ": "; - if (0 == printTag(exifData, "Image.CaptureConditions.ExposureProgram")) { - md = exifData.findKey("Makernote.Canon.CameraSettings1"); + if (0 == printTag(exifData, "Exif.Photo.ExposureProgram")) { + md = exifData.findKey( + Exiv2::ExifKey("Exif.Canon.CameraSettings1")); if (md != exifData.end() && md->count() >= 20) { Exiv2::CanonMakerNote::print0x0001_20(std::cout, md->toLong(20)); } @@ -282,20 +288,21 @@ namespace Action { std::cout << "\n"; // Metering mode - printTag(exifData, "Image.CaptureConditions.MeteringMode", "Metering mode"); + printTag(exifData, "Exif.Photo.MeteringMode", "Metering mode"); // Macro mode // Todo: Implement this for other cameras std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Macro mode" << ": "; done = false; - md = exifData.findKey("Makernote.Canon.CameraSettings1"); + md = exifData.findKey( + Exiv2::ExifKey("Exif.Canon.CameraSettings1")); if (md != exifData.end() && md->count() >= 1) { Exiv2::CanonMakerNote::print0x0001_01(std::cout, md->toLong(1)); done = true; } if (!done) { - done = printTag(exifData, "Makernote.Fujifilm.Macro"); + done = printTag(exifData, "Exif.Fujifilm.Macro"); } std::cout << "\n"; @@ -304,25 +311,25 @@ namespace Action { std::cout << std::setw(align_) << std::setfill(' ') << std::left << "Image quality" << ": "; done = false; - md = exifData.findKey("Makernote.Canon.CameraSettings1"); + md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings1")); if (md != exifData.end() && md->count() >= 3) { Exiv2::CanonMakerNote::print0x0001_03(std::cout, md->toLong(3)); done = true; } if (!done) { - done = printTag(exifData, "Makernote.Fujifilm.Quality"); + done = printTag(exifData, "Exif.Fujifilm.Quality"); } if (!done) { - done = printTag(exifData, "Makernote.Sigma.Quality"); + done = printTag(exifData, "Exif.Sigma.Quality"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon1.Quality"); + done = printTag(exifData, "Exif.Nikon1.Quality"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon2.Quality"); + done = printTag(exifData, "Exif.Nikon2.Quality"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon3.Quality"); + done = printTag(exifData, "Exif.Nikon3.Quality"); } std::cout << "\n"; @@ -331,9 +338,9 @@ namespace Action { << "Exif Resolution" << ": "; long xdim = 0; long ydim = 0; - md = exifData.findKey("Image.ImageConfig.PixelXDimension"); + md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); if (md != exifData.end()) xdim = md->toLong(); - md = exifData.findKey("Image.ImageConfig.PixelYDimension"); + md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); if (md != exifData.end()) ydim = md->toLong(); if (xdim != 0 && ydim != 0) { std::cout << xdim << " x " << ydim; @@ -345,25 +352,25 @@ namespace Action { std::cout << std::setw(align_) << std::setfill(' ') << std::left << "White balance" << ": "; done = false; - md = exifData.findKey("Makernote.Canon.CameraSettings2"); + md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings2")); if (md != exifData.end() && md->count() >= 7) { Exiv2::CanonMakerNote::print0x0004_07(std::cout, md->toLong(7)); done = true; } if (!done) { - done = printTag(exifData, "Makernote.Fujifilm.WhiteBalance"); + done = printTag(exifData, "Exif.Fujifilm.WhiteBalance"); } if (!done) { - done = printTag(exifData, "Makernote.Sigma.WhiteBalance"); + done = printTag(exifData, "Exif.Sigma.WhiteBalance"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon1.WhiteBalance"); + done = printTag(exifData, "Exif.Nikon1.WhiteBalance"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon2.WhiteBalance"); + done = printTag(exifData, "Exif.Nikon2.WhiteBalance"); } if (!done) { - done = printTag(exifData, "Makernote.Nikon3.WhiteBalance"); + done = printTag(exifData, "Exif.Nikon3.WhiteBalance"); } std::cout << "\n"; @@ -381,10 +388,10 @@ namespace Action { std::cout << "\n"; // Copyright - printTag(exifData, "Image.OtherTags.Copyright", "Copyright"); + printTag(exifData, "Exif.Image.Copyright", "Copyright"); // Exif Comment - printTag(exifData, "Image.UserInfo.UserComment", "Exif comment"); + printTag(exifData, "Exif.Photo.UserComment", "Exif comment"); std::cout << std::endl; } // Print::printSummary @@ -399,7 +406,8 @@ namespace Action { std::cout << std::setw(align_) << std::setfill(' ') << std::left << label << ": "; } - Exiv2::ExifData::const_iterator md = exifData.findKey(key); + Exiv2::ExifKey ek(key); + Exiv2::ExifData::const_iterator md = exifData.findKey(ek); if (md != exifData.end()) { std::cout << *md; rc = 1; @@ -484,7 +492,7 @@ namespace Action { std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; return rc; } - std::string key = "Image.DateTime.DateTimeOriginal"; + Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); Exiv2::ExifData::iterator md = exifData.findKey(key); if (md == exifData.end()) { std::cerr << "Metadatum with key `" << key << "' " @@ -753,9 +761,9 @@ namespace Action { std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; return rc; } - rc = adjustDateTime(exifData, "Image.OtherTags.DateTime", path); - rc += adjustDateTime(exifData, "Image.DateTime.DateTimeOriginal", path); - rc += adjustDateTime(exifData, "Image.DateTime.DateTimeDigitized", path); + rc = adjustDateTime(exifData, "Exif.Image.DateTime", path); + rc += adjustDateTime(exifData, "Exif.Photo.DateTimeOriginal", path); + rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path); if (rc) return 1; rc = exifData.write(path); if (rc) { @@ -784,7 +792,8 @@ namespace Action { const std::string& key, const std::string& path) const { - Exiv2::ExifData::iterator md = exifData.findKey(key); + Exiv2::ExifKey ek(key); + Exiv2::ExifData::iterator md = exifData.findKey(ek); if (md == exifData.end()) { // Key not found. That's ok, we do nothing. return 0; @@ -792,7 +801,7 @@ namespace Action { std::string timeStr = md->toString(); if (timeStr == "" || timeStr[0] == ' ') { std::cerr << path << ": Timestamp of metadatum with key `" - << key << "' not set\n"; + << ek << "' not set\n"; return 1; } time_t time = str2Time(timeStr); @@ -802,7 +811,7 @@ namespace Action { return 1; } if (Params::instance().verbose_) { - std::cout << "Adjusting `" << key << "' by" + std::cout << "Adjusting `" << ek << "' by" << (adjustment_ < 0 ? " " : " +") << adjustment_ << " s to "; } diff --git a/src/addmoddel.cpp b/src/addmoddel.cpp index d123724f..8117e8eb 100644 --- a/src/addmoddel.cpp +++ b/src/addmoddel.cpp @@ -3,7 +3,7 @@ Abstract: Sample program showing how to add, modify and delete Exif metadata. File: addmoddel.cpp - Version: $Name: $ $Revision: 1.3 $ + Version: $Name: $ $Revision: 1.4 $ Author(s): Andreas Huggel (ahu) History: 26-Jan-04, ahu: created */ @@ -28,7 +28,7 @@ try { // Set the value to a string v->read("1999:12:31 23:59:59"); // Add the value together with its key to the Exif data container - std::string key = "Image.DateTime.DateTimeOriginal"; + Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); exifData.add(key, v); std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n"; @@ -43,7 +43,7 @@ try { rv->value_.push_back(std::make_pair(2,3)); rv->value_.push_back(std::make_pair(3,4)); // Add the key and value pair to the Exif data - key = "Image.ImageCharacteristics.PrimaryChromaticities"; + key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); exifData.add(key, rv); std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n"; @@ -54,7 +54,7 @@ try { // Modify Exif data // Find the timestamp metadatum by its key - key = "Image.DateTime.DateTimeOriginal"; + key = Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); // Modify the value @@ -65,7 +65,7 @@ try { << "\", new value \"" << pos->value() << "\"\n"; // Find the other key - key = "Image.ImageCharacteristics.PrimaryChromaticities"; + key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); // Get a pointer to a copy of the value @@ -86,7 +86,7 @@ try { // Delete metadata from the Exif data container // Delete the metadatum at iterator position pos - key = "Image.ImageCharacteristics.PrimaryChromaticities"; + key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); exifData.erase(pos); diff --git a/src/canonmn.cpp b/src/canonmn.cpp index ebe7d878..1e95ae20 100644 --- a/src/canonmn.cpp +++ b/src/canonmn.cpp @@ -20,7 +20,7 @@ */ /* File: canonmn.cpp - Version: $Name: $ $Revision: 1.12 $ + Version: $Name: $ $Revision: 1.13 $ Author(s): Andreas Huggel (ahu) History: 18-Feb-04, ahu: created 07-Mar-04, ahu: isolated as a separate component @@ -30,7 +30,7 @@ */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.12 $ $RCSfile: canonmn.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.13 $ $RCSfile: canonmn.cpp,v $"); // ***************************************************************************** // included header files @@ -68,7 +68,7 @@ namespace Exiv2 { }; CanonMakerNote::CanonMakerNote(bool alloc) - : IfdMakerNote(canonMnTagInfo, alloc), sectionName_("Canon") + : IfdMakerNote(canonMnTagInfo, alloc), ifdItem_("Canon") { } diff --git a/src/canonmn.hpp b/src/canonmn.hpp index 789eb161..3a15dc75 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.9 $ + @version $Name: $ $Revision: 1.10 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 18-Feb-04, ahu: created
@@ -98,8 +98,8 @@ namespace Exiv2 { //! @name Accessors //@{ CanonMakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Canon") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Canon") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -193,8 +193,8 @@ namespace Exiv2 { */ static const RegisterMakerNote register_; - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class CanonMakerNote diff --git a/src/datasets.cpp b/src/datasets.cpp index babc25f5..65739fd4 100644 --- a/src/datasets.cpp +++ b/src/datasets.cpp @@ -20,13 +20,13 @@ */ /* File: datasets.cpp - Version: $Name: $ $Revision: 1.3 $ + Version: $Name: $ $Revision: 1.4 $ Author(s): Brad Schick (brad) History: 24-Jul-04, brad: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.3 $ $RCSfile: datasets.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.4 $ $RCSfile: datasets.cpp,v $"); // ***************************************************************************** // included header files @@ -162,6 +162,8 @@ namespace Exiv2 { 0 }; + const char* IptcDataSets::familyName_ = "Iptc"; + int IptcDataSets::dataSetIdx(uint16 number, uint16 recordId) { if( recordId != envelope && recordId != application2 ) return -1; @@ -248,13 +250,15 @@ namespace Exiv2 { std::string IptcDataSets::makeKey(const DataSet& dataSet) { - return "Iptc." + std::string(recordName(dataSet.recordId_)) + return std::string(familyName()) + + "." + std::string(recordName(dataSet.recordId_)) + "." + dataSet.name_; } std::string IptcDataSets::makeKey(uint16 number, uint16 recordId) { - return "Iptc." + std::string(recordName(recordId)) + return std::string(familyName()) + + "." + std::string(recordName(recordId)) + "." + std::string(dataSetName(number, recordId)); } diff --git a/src/datasets.hpp b/src/datasets.hpp index 8f3bc66f..af746f28 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.2 $ + @version $Name: $ $Revision: 1.3 $ @author Brad Schick (brad) @date 24-Jul-04, brad: created */ @@ -171,7 +171,10 @@ namespace Exiv2 { static const uint16 PreviewVersion = 201; static const uint16 Preview = 202; //@} - + + private: + static const char* familyName_; + private: //! Prevent construction: not implemented. IptcDataSets() {} @@ -181,6 +184,8 @@ namespace Exiv2 { IptcDataSets& operator=(const IptcDataSets& rhs); public: + //! Return an identifier for Iptc datasets + static const char* familyName() { return familyName_; } /*! @brief Return the name of the dataset. @param number The dataset number @@ -240,12 +245,12 @@ namespace Exiv2 { static uint16 recordId(const std::string& recordName); /*! @brief Return the key for the dataSet number and record id. The key is - of the form 'recordName.dataSetName'. + of the form 'Iptc.recordName.dataSetName'. */ static std::string makeKey(uint16 number, uint16 recordId); /*! @brief Return the key for the dataSet. The key is of the form - 'recordName.dataSetName'. + 'Iptc.recordName.dataSetName'. */ static std::string makeKey(const DataSet& dataSet); /*! diff --git a/src/exif.cpp b/src/exif.cpp index af9763fb..c965c115 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -20,14 +20,14 @@ */ /* File: exif.cpp - Version: $Name: $ $Revision: 1.53 $ + Version: $Name: $ $Revision: 1.54 $ 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.53 $ $RCSfile: exif.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.54 $ $RCSfile: exif.cpp,v $"); // Define DEBUG_MAKERNOTE to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -73,37 +73,127 @@ namespace { // class member definitions namespace Exiv2 { - Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder) + ExifKey::ExifKey(const std::string& key) + : idx_(0), pMakerNote_(0), key_(key) + { + decomposeKey(); + } + + ExifKey::ExifKey(const Entry& e) : tag_(e.tag()), ifdId_(e.ifdId()), idx_(e.idx()), - pMakerNote_(e.makerNote()), pValue_(0), key_(makeKey(e)) + pMakerNote_(e.makerNote()), key_(makeKey(e)) { - pValue_ = Value::create(TypeId(e.type())); - pValue_->read(e.data(), e.count() * e.typeSize(), byteOrder); } - Exifdatum::Exifdatum(const std::string& key, - const Value* value, - MakerNote* makerNote) - : idx_(0), pMakerNote_(makerNote), pValue_(0), key_(key) + ExifKey::ExifKey(const ExifKey& rhs) + : tag_(rhs.tag_), ifdId_(rhs.ifdId_), idx_(rhs.idx_), + pMakerNote_(rhs.pMakerNote_), key_(rhs.key_) + { + } + + ExifKey& ExifKey::operator=(const ExifKey& rhs) + { + if (this == &rhs) return *this; + Key::operator=(rhs); + tag_ = rhs.tag_; + ifdId_ = rhs.ifdId_; + idx_ = rhs.idx_; + pMakerNote_ = rhs.pMakerNote_; + key_ = rhs.key_; + return *this; + } + + void ExifKey::setMakerNote(MakerNote* pMakerNote) + { + if (ifdId_ == makerIfd && pMakerNote_ != pMakerNote) { + pMakerNote_ = pMakerNote; + decomposeKey(); + } + } + + std::string ExifKey::tagName() const + { + if (ifdId_ == makerIfd && pMakerNote_ != 0) { + return pMakerNote_->tagName(tag_); + } + return ExifTags::tagName(tag(), ifdId()); + } + + uint16 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_; + } + + ExifKey* ExifKey::clone() const + { + return new ExifKey(*this); + } + + std::string ExifKey::sectionName() const + { + if (ifdId_ == makerIfd && pMakerNote_ != 0) { + return pMakerNote_->ifdItem(); + } + return ExifTags::sectionName(tag(), ifdId()); + } + + void ExifKey::decomposeKey() { - if (value) pValue_ = value->clone(); - std::pair p = decomposeKey(key, makerNote); - if (p.first == 0xffff) throw Error("Invalid key"); + std::pair p; + if (ifdId_ == makerIfd && pMakerNote_ != 0) { + p.first = pMakerNote_->decomposeKey(key_); + if (p.first == 0xffff) throw Error("Invalid key"); + p.second = makerIfd; + } + 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 = makerIfd; + // No checks as this could still be an incomplete makernote key + } tag_ = p.first; - if (p.second == ifdIdNotSet) throw Error("Invalid key"); ifdId_ = p.second; } + std::ostream& ExifKey::printTag(std::ostream& os, const Value& value) const + { + if (ifdId_ == makerIfd && pMakerNote_ != 0) { + 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) + { + pValue_ = Value::create(TypeId(e.type())); + pValue_->read(e.data(), e.count() * e.typeSize(), byteOrder); + } + + Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue) + : pKey_(key.clone()), pValue_(0) + { + if (pValue) pValue_ = pValue->clone(); + } + Exifdatum::~Exifdatum() { + delete pKey_; delete pValue_; - // do *not* delete the MakerNote } Exifdatum::Exifdatum(const Exifdatum& rhs) - : Metadatum(rhs), tag_(rhs.tag_), ifdId_(rhs.ifdId_), idx_(rhs.idx_), - pMakerNote_(rhs.pMakerNote_), pValue_(0), key_(rhs.key_) + : Metadatum(rhs), pKey_(0), pValue_(0) { + if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy } @@ -111,14 +201,15 @@ namespace Exiv2 { { if (this == &rhs) return *this; Metadatum::operator=(rhs); - tag_ = rhs.tag_; - ifdId_ = rhs.ifdId_; - idx_ = rhs.idx_; - pMakerNote_ = rhs.pMakerNote_; + + delete pKey_; + pKey_ = 0; + if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy + delete pValue_; pValue_ = 0; if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy - key_ = rhs.key_; + return *this; } // Exifdatum::operator= @@ -141,22 +232,6 @@ namespace Exiv2 { pValue_->read(buf); } - std::string Exifdatum::tagName() const - { - if (ifdId_ == makerIfd && pMakerNote_ != 0) { - return pMakerNote_->tagName(tag_); - } - return ExifTags::tagName(tag_, ifdId_); - } - - std::string Exifdatum::sectionName() const - { - if (ifdId_ == makerIfd && pMakerNote_ != 0) { - return pMakerNote_->sectionName(tag_); - } - return ExifTags::sectionName(tag_, ifdId_); - } - TiffThumbnail::TiffThumbnail() : offset_(0), size_(0), pImage_(0), ifd_(ifd1, 0, false) { @@ -229,17 +304,16 @@ namespace Exiv2 { buflen += ifd1.size() + ifd1.dataSize(); if (len < buflen) rc = 1; } - std::string key; ExifData::const_iterator offsets; ExifData::const_iterator sizes; if (rc == 0) { // Copy thumbnail image data, remember the offsets used - key = "Thumbnail.RecordingOffset.StripOffsets"; + ExifKey key("Exif.Thumbnail.StripOffsets"); offsets = exifData.findKey(key); if (offsets == exifData.end()) rc = 2; } if (rc == 0) { - key = "Thumbnail.RecordingOffset.StripByteCounts"; + ExifKey key("Exif.Thumbnail.StripByteCounts"); sizes = exifData.findKey(key); if (sizes == exifData.end()) rc = 2; } @@ -426,12 +500,12 @@ namespace Exiv2 { const ExifData& exifData, ByteOrder byteOrder) { - std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat"; + ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); ExifData::const_iterator pos = exifData.findKey(key); if (pos == exifData.end()) return 2; long offset = pos->toLong(); - key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength"; - pos = exifData.findKey(key); + ExifKey key2("Exif.Thumbnail.JPEGInterchangeFormatLength"); + pos = exifData.findKey(key2); if (pos == exifData.end()) return 2; long size = pos->toLong(); if (len < offset + size) return 1; @@ -466,7 +540,7 @@ namespace Exiv2 { void JpegThumbnail::update(ExifData& exifData) const { - std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat"; + ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); ExifData::iterator pos = exifData.findKey(key); if (pos == exifData.end()) { Value* value = Value::create(unsignedLong); @@ -476,13 +550,13 @@ namespace Exiv2 { } pos->setValue(toString(offset_)); - key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength"; - pos = exifData.findKey(key); + ExifKey key2("Exif.Thumbnail.JPEGInterchangeFormatLength"); + pos = exifData.findKey(key2); if (pos == exifData.end()) { Value *value = Value::create(unsignedLong); - exifData.add(key, value); + exifData.add(key2, value); delete value; - pos = exifData.findKey(key); + pos = exifData.findKey(key2); } pos->setValue(toString(size_)); @@ -600,7 +674,7 @@ namespace Exiv2 { if (rc) { // Todo: How to handle debug output like this std::cerr << "Warning: Failed to read " - << pMakerNote_->sectionName(0) + << pMakerNote_->ifdItem() << " Makernote, rc = " << rc << "\n"; delete pMakerNote_; @@ -896,9 +970,12 @@ namespace Exiv2 { } } - void ExifData::add(const std::string& key, Value* value) + void ExifData::add(const ExifKey& key, Value* pValue) { - add(Exifdatum(key, value)); + // Todo: Implement a more suitable ExifKey c'tor + ExifKey k(key); + k.setMakerNote(pMakerNote_); + add(Exifdatum(k, pValue)); } void ExifData::add(const Exifdatum& exifdatum) @@ -907,16 +984,16 @@ namespace Exiv2 { exifMetadata_.push_back(exifdatum); } - ExifData::const_iterator ExifData::findKey(const std::string& key) const + ExifData::const_iterator ExifData::findKey(const ExifKey& key) const { return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), - FindMetadatumByKey(key)); + FindMetadatumByKey(key.key())); } - ExifData::iterator ExifData::findKey(const std::string& key) + ExifData::iterator ExifData::findKey(const ExifKey& key) { return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), - FindMetadatumByKey(key)); + FindMetadatumByKey(key.key())); } ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const @@ -1019,7 +1096,8 @@ namespace Exiv2 { delete pThumbnail_; pThumbnail_ = 0; int rc = -1; - const_iterator pos = findKey("Thumbnail.ImageStructure.Compression"); + const_iterator pos + = findKey(ExifKey("Exif.Thumbnail.Compression")); if (pos != end()) { long compression = pos->toLong(); if (compression == 6) { @@ -1200,7 +1278,7 @@ namespace Exiv2 { error += "Exif data contains a broken IFD"; break; case 7: - error += "Unsupported Exif or GPS data found in IFD 1"; + error += "Unsupported Exif or GPS data found in IFD1"; break; default: @@ -1272,13 +1350,9 @@ namespace Exiv2 { makerNote->add(e); } // addToMakerNote - std::ostream& operator<<(std::ostream& os, const Exifdatum& md) { - if (md.ifdId() == makerIfd && md.makerNote() != 0) { - return md.makerNote()->printTag(os, md.tag(), md.value()); - } - return ExifTags::printTag(os, md.tag(), md.ifdId(), md.value()); + return md.pKey_->printTag(os, md.value()); } std::string makeKey(const Entry& entry) diff --git a/src/exif.hpp b/src/exif.hpp index 05c6bcab..38d60c68 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.49 $ + @version $Name: $ $Revision: 1.50 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created @@ -60,30 +60,117 @@ 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); + //! 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 + //@} + + //! @name Manipulators + //@{ + /*! + @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(); } + /*! + @brief Return the name of the group (the second part of the key). + For Exif keys, the group name is the IFD name. + */ + virtual std::string groupName() const { return ifdName(); } + virtual std::string tagName() const; + /*! + @brief Return the tag. + @throw Error ("Invalid key") if the tag is not set. + */ + virtual uint16 tag() const; + 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 name of the IFD + const char* ifdName() const { return ExifTags::ifdName(ifdId()); } + //! Return the related image item + const char* ifdItem() const { return ExifTags::ifdItem(ifdId()); } + //! 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_; } + //! 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, + 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. + */ + void decomposeKey(); + //@} + + private: + // DATA + uint16 tag_; //!< Tag value + IfdId ifdId_; //!< The IFD associated with this tag + 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. */ class Exifdatum : public Metadatum { + friend std::ostream& operator<<(std::ostream&, const Exifdatum&); public: //! @name Creators //@{ /*! @brief Constructor for new tags created by an application. The - Exifdatum is created from a key / value pair. %Exifdatum copies - (clones) the value if one is provided. Alternatively, a program - can create an 'empty' Exifdatum with only a key and set the - value using setValue(). - - @param key The key of the Exifdatum. - @param value Pointer to a Exifdatum value. - @param makerNote Pointer to the associated MakerNote (only needed for - MakerNote tags). - @throw Error ("Invalid key") if the key cannot be parsed and converted - to a tag number and an IFD id or the section name does not match. - */ - explicit Exifdatum(const std::string& key, - const Value* value =0, - MakerNote* makerNote =0); + %Exifdatum is created from a key / value pair. %Exifdatum copies + (clones) the key and value if one is provided. Alternatively, + a program can create an 'empty' %Exifdatum with only a key + and set the value using setValue(). + + @param key ExifKey. + @param pValue Pointer to a Exifdatum value. + @throw Error ("Invalid key") if the key cannot be parsed and converted. + */ + explicit Exifdatum(const ExifKey& key, const Value* pValue =0); //! Constructor to build a Exifdatum from an IFD entry. Exifdatum(const Entry& e, ByteOrder byteOrder); //! Copy constructor @@ -115,6 +202,30 @@ namespace Exiv2 { //! @name Accessors //@{ + //! Return the key of the %Exifdatum. + std::string key() const + { return pKey_ == 0 ? "" : pKey_->key(); } + //! Return the name of the group (the second part of the key) + std::string groupName() const + { return pKey_ == 0 ? "" : pKey_->groupName(); } + //! Return the name of the tag (which is also the third part of the key) + std::string tagName() const + { return pKey_ == 0 ? "" : pKey_->tagName(); } + //! Return the tag + uint16 tag() const + { return pKey_ == 0 ? 0xffff : pKey_->tag(); } + //! Return the IFD id + IfdId ifdId() const + { return pKey_ == 0 ? ifdIdNotSet : pKey_->ifdId(); } + //! Return the name of the IFD + const char* ifdName() const + { return pKey_ == 0 ? "" : pKey_->ifdName(); } + //! Return the related image item (deprecated) + const char* ifdItem() const + { return pKey_ == 0 ? "" : pKey_->ifdItem(); } + //! Return the index (unique id of this key within the original IFD) + int idx() const + { return pKey_ == 0 ? 0 : pKey_->idx(); } /*! @brief Write value to a data buffer and return the number of bytes written. @@ -128,40 +239,21 @@ namespace Exiv2 { */ long copy(byte* buf, ByteOrder byteOrder) const { return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); } - /*! - @brief Return the key of the Exifdatum. The key is of the form - 'ifdItem.sectionName.tagName'. Note however that the key - is not necessarily unique, i.e., an ExifData may contain - multiple metadata with the same key. - */ - std::string key() const { return key_; } - //! Return the related image item (the first part of the key) - const char* ifdItem() const { return ExifTags::ifdItem(ifdId_); } - //! Return the name of the section (the second part of the key) - std::string sectionName() const; - //! Return the name of the tag (which is also the third part of the key) - std::string tagName() const; - //! Return the tag - uint16 tag() const { return tag_; } //! Return the type id of the value TypeId typeId() const { return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); } //! Return the name of the type - const char* typeName() const { return TypeInfo::typeName(typeId()); } + const char* typeName() const + { return TypeInfo::typeName(typeId()); } //! Return the size in bytes of one component of this type - long typeSize() const { return TypeInfo::typeSize(typeId()); } + long typeSize() const + { return TypeInfo::typeSize(typeId()); } //! Return the number of components in the value - long count() const { return pValue_ == 0 ? 0 : pValue_->count(); } + long count() const + { return pValue_ == 0 ? 0 : pValue_->count(); } //! Return the size of the value in bytes - long size() const { return pValue_ == 0 ? 0 : pValue_->size(); } - //! 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 index (unique id of this Exifdatum within the original IFD) - int idx() const { return idx_; } - //! Return the pointer to the associated MakerNote - MakerNote* makerNote() const { return pMakerNote_; } + long size() const + { return pValue_ == 0 ? 0 : pValue_->size(); } //! Return the value as a string. std::string toString() const { return pValue_ == 0 ? "" : pValue_->toString(); } @@ -201,7 +293,8 @@ namespace Exiv2 { @return A pointer to a copy (clone) of the value, 0 if the value is not set. */ - Value* getValue() const { return pValue_ == 0 ? 0 : pValue_->clone(); } + Value* getValue() const + { return pValue_ == 0 ? 0 : pValue_->clone(); } /*! @brief Return a constant reference to the value. @@ -227,17 +320,13 @@ namespace Exiv2 { private: // DATA - uint16 tag_; //!< Tag value - IfdId ifdId_; //!< The IFD associated with this tag - int idx_; //!< Unique id of an entry within one IFD - MakerNote* pMakerNote_; //!< Pointer to the associated MakerNote + ExifKey* pKey_; //!< Key Value* pValue_; //!< Pointer to the value - std::string key_; //!< Key }; // class Exifdatum /*! - @brief Output operator for Exifdatum types, printing the interpreted + @brief Output operator for Exifdatum types, prints the interpreted tag value. */ std::ostream& operator<<(std::ostream& os, const Exifdatum& md); @@ -579,11 +668,12 @@ namespace Exiv2 { ByteOrder byteOrder); /*! @brief Add a Exifdatum from the supplied key and value pair. This - method copies (clones) the value. No duplicate checks are + method copies (clones) key and value and adds a pointer to + the MakerNote to the cloned key. No duplicate checks are performed, i.e., it is possible to add multiple metadata with the same key. */ - void add(const std::string& key, Value* value); + void add(const ExifKey& key, Value* pValue); /*! @brief Add a copy of the Exifdatum to the Exif metadata. No duplicate checks are performed, i.e., it is possible to add @@ -610,7 +700,7 @@ namespace Exiv2 { If multiple metadata with the same key exist, it is undefined which of the matching metadata is found. */ - iterator findKey(const std::string& key); + iterator findKey(const ExifKey& key); /*! @brief Find the Exifdatum with the given ifd id and idx, return an iterator to it. @@ -659,7 +749,7 @@ namespace Exiv2 { it. If multiple metadata with the same key exist, it is undefined which of the matching metadata is found. */ - const_iterator findKey(const std::string& key) const; + const_iterator findKey(const ExifKey& key) const; /*! @brief Find the Exifdatum with the given ifd id and idx, return an iterator to it. @@ -863,7 +953,7 @@ namespace Exiv2 { ByteOrder byteOrder); /*! @brief Return a key for the entry. The key is of the form - 'ifdItem.sectionName.tagName'. This function knows about + 'Exif.ifdItem.tagName'. This function knows about MakerNotes, i.e., it will invoke MakerNote::makeKey if necessary. */ std::string makeKey(const Entry& entry); diff --git a/src/exifcomment.cpp b/src/exifcomment.cpp index 61c93d7b..2510859b 100644 --- a/src/exifcomment.cpp +++ b/src/exifcomment.cpp @@ -3,7 +3,7 @@ Abstract : Sample program showing how to set the Exif comment of an image File: exifcomment.cpp - Version : $Name: $ $Revision: 1.3 $ + Version : $Name: $ $Revision: 1.4 $ Author(s): Andreas Huggel (ahu) History : 10-May-04, ahu: created */ @@ -33,7 +33,7 @@ try { /* There are two pitfalls that we need to consider when setting the Exif user - comment (Image.UserInfo.UserComment) of an image: + comment (Exif.Photo.UserComment) of an image: First, the type of the Exif user comment tag is "undefined" (and not ASCII) according to the Exif standard. This means that in Exiv2, we have @@ -60,7 +60,7 @@ try { 8 + static_cast(comment.size())); // Set the Exif comment - std::string key = "Image.UserInfo.UserComment"; + Exiv2::ExifKey key("Exif.Photo.UserComment"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos != exifData.end()) { // Use the existing Exif UserComment metadatum if there is one diff --git a/src/fujimn.cpp b/src/fujimn.cpp index 74aa0e3c..cbf0d8b2 100644 --- a/src/fujimn.cpp +++ b/src/fujimn.cpp @@ -20,7 +20,7 @@ */ /* File: fujimn.cpp - Version: $Name: $ $Revision: 1.9 $ + Version: $Name: $ $Revision: 1.10 $ Author(s): Andreas Huggel (ahu) History: 18-Feb-04, ahu: created 07-Mar-04, ahu: isolated as a separate component @@ -31,7 +31,7 @@ */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: fujimn.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.10 $ $RCSfile: fujimn.cpp,v $"); // ***************************************************************************** // included header files @@ -78,7 +78,7 @@ namespace Exiv2 { }; FujiMakerNote::FujiMakerNote(bool alloc) - : IfdMakerNote(fujiMnTagInfo, alloc), sectionName_("Fujifilm") + : IfdMakerNote(fujiMnTagInfo, alloc), ifdItem_("Fujifilm") { byteOrder_ = littleEndian; absOffset_ = false; diff --git a/src/fujimn.hpp b/src/fujimn.hpp index e6ce75a4..1dd9cf9a 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.6 $ + @version $Name: $ $Revision: 1.7 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Feb-04, ahu: created @@ -106,8 +106,8 @@ namespace Exiv2 { //@{ int checkHeader() const; FujiMakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Fujifilm") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Fujifilm") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -157,8 +157,8 @@ namespace Exiv2 { */ static const RegisterMakerNote register_; - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class FujiMakerNote diff --git a/src/iptc.cpp b/src/iptc.cpp index 83c55327..086f2eb0 100644 --- a/src/iptc.cpp +++ b/src/iptc.cpp @@ -20,13 +20,13 @@ */ /* File: iptc.cpp - Version: $Name: $ $Revision: 1.2 $ + Version: $Name: $ $Revision: 1.3 $ Author(s): Brad Schick (brad) History: 31-July-04, brad: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.2 $ $RCSfile: iptc.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.3 $ $RCSfile: iptc.cpp,v $"); // Define DEBUG_MAKERNOTE to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -48,27 +48,63 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.2 $ $RCSfile: iptc.cpp,v $"); // class member definitions namespace Exiv2 { - Iptcdatum::Iptcdatum(const std::string& key, - const Value* value) - : pValue_(0), key_(key), modified_(false) + IptcKey::IptcKey(const std::string& key) + : key_(key) { - if (value) pValue_ = value->clone(); - std::pair p = decomposeKey(key); + decomposeKey(); + } + + IptcKey::IptcKey(uint16 tag, uint16 record) + : tag_(tag), record_(record), key_(IptcDataSets::makeKey(tag, record)) + { + } + + 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() + { + std::pair p = IptcDataSets::decomposeKey(key_); if (p.first == 0xffff) throw Error("Invalid key"); - tag_ = p.first; if (p.second == IptcDataSets::invalidRecord) throw Error("Invalid key"); + tag_ = p.first; record_ = p.second; } + Iptcdatum::Iptcdatum(const IptcKey& key, + const Value* value) + : pKey_(key.clone()), pValue_(0), modified_(false) + { + if (value) pValue_ = value->clone(); + } + Iptcdatum::Iptcdatum(const Iptcdatum& rhs) - : Metadatum(rhs), tag_(rhs.tag_), record_(rhs.record_), - pValue_(0), key_(rhs.key_), modified_(false) + : Metadatum(rhs), pKey_(0), pValue_(0), modified_(false) { + if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy } Iptcdatum::~Iptcdatum() { + delete pKey_; delete pValue_; } @@ -77,12 +113,15 @@ namespace Exiv2 { if (this == &rhs) return *this; Metadatum::operator=(rhs); modified_ = true; - tag_ = rhs.tag_; - record_ = rhs.record_; + + delete pKey_; + pKey_ = 0; + if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy + delete pValue_; pValue_ = 0; if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy - key_ = rhs.key_; + return *this; } // Iptcdatum::operator= @@ -100,16 +139,6 @@ namespace Exiv2 { pValue_->read(buf); } - std::string Iptcdatum::tagName() const - { - return IptcDataSets::dataSetName(tag_, record_); - } - - std::string Iptcdatum::recordName() const - { - return IptcDataSets::recordName(record_); - } - const byte IptcData::marker_ = 0x1C; // Dataset marker IptcData::IptcData() @@ -206,7 +235,7 @@ namespace Exiv2 { val = Value::create(undefined); val->read(data, sizeData, bigEndian); } - std::string key = makeKey(dataSet, record); + IptcKey key(dataSet, record); add(key, val); delete val; return 0; @@ -346,7 +375,7 @@ namespace Exiv2 { return exvImage.writeMetadata(); } // IptcData::writeIptcData - int IptcData::add(const std::string& key, Value* value) + int IptcData::add(const IptcKey& key, Value* value) { return add(Iptcdatum(key, value)); } @@ -364,16 +393,16 @@ namespace Exiv2 { return 0; } - IptcData::const_iterator IptcData::findKey(const std::string& key) const + IptcData::const_iterator IptcData::findKey(const IptcKey& key) const { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), - FindMetadatumByKey(key)); + FindMetadatumByKey(key.key())); } - IptcData::iterator IptcData::findKey(const std::string& key) + IptcData::iterator IptcData::findKey(const IptcKey& key) { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), - FindMetadatumByKey(key)); + FindMetadatumByKey(key.key())); } IptcData::const_iterator IptcData::findId(uint16 dataset, uint16 record) const @@ -453,14 +482,4 @@ namespace Exiv2 { return os << md.value(); } - std::string makeKey(uint16 number, uint16 record) - { - return IptcDataSets::makeKey(number, record); - } - - std::pair decomposeKey(const std::string& key) - { - return IptcDataSets::decomposeKey(key); - } - } // namespace Exiv2 diff --git a/src/iptc.hpp b/src/iptc.hpp index 2bac6176..1e670bcc 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.3 $ + @version $Name: $ $Revision: 1.4 $ @author Brad Schick (brad) schick@robotbattle.com @date 31-Jul-04, brad: created @@ -48,6 +48,82 @@ 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 tag, uint16 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 IptcDataSets::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 tag() const { return tag_; } + virtual IptcKey* clone() const; + + //! Return the name of the record + const char* recordName() const + { return IptcDataSets::recordName(record_); } + //! Return the record id + uint16 record() const { return record_; } + //@} + + protected: + //! @name Manipulators + //@{ + /*! + @brief Parse and convert the key string into dataset and record id. + Updates tag_ and record_ if the string can be decomposed, + or throws Error ("Invalid key"). + + @throw Error ("Invalid key") if the key cannot be parsed into + family name, group name and tag name parts. + */ + void decomposeKey(); + //@} + + private: + // DATA + uint16 tag_; //!< Tag value + uint16 record_; //!< Record value + std::string key_; //!< Key + + }; // class IptcKey + /*! @brief Information related to one Iptc dataset. */ @@ -57,17 +133,17 @@ namespace Exiv2 { //@{ /*! @brief Constructor for new tags created by an application. The - Iptcdatum is created from a key / value pair. %Iptcdatum copies - (clones) the value if one is provided. Alternatively, a program - can create an 'empty' Iptcdatum with only a key and set the - value using setValue(). + %Iptcdatum is created from a key / value pair. %Iptcdatum + copies (clones) the value if one is provided. Alternatively, a + program can create an 'empty' %Iptcdatum with only a key and + set the value using setValue(). - @param key The key of the Iptcdatum. - @param value Pointer to a Iptcdatum value. + @param key The key of the %Iptcdatum. + @param value Pointer to a %Iptcdatum value. @throw Error ("Invalid key") if the key cannot be parsed and converted to a tag number and record id. */ - explicit Iptcdatum(const std::string& key, + explicit Iptcdatum(const IptcKey& key, const Value* value =0); //! Copy constructor Iptcdatum(const Iptcdatum& rhs); @@ -109,30 +185,34 @@ namespace Exiv2 { { return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); } /*! @brief Return the key of the Iptcdatum. The key is of the form - 'Iptc.recordName.datasetName'. Note however that the key + 'Iptc.recordName.datasetName'. Note however that the key is not necessarily unique, i.e., an IptcData may contain multiple metadata with the same key. */ - std::string key() const { return key_; } + std::string key() const { return pKey_ == 0 ? "" : pKey_->key(); } /*! @brief Return the name of the record @return record name @throw Error("Unknown record"); */ - std::string recordName() const; + const char* recordName() const + { return pKey_ == 0 ? "" : pKey_->recordName(); } /*! @brief Return the record id @return record id */ - uint16 record() const { return record_; } + uint16 record() const + { return pKey_ == 0 ? 0 : pKey_->record(); } /*! @brief Return the name of the tag (aka dataset) @return tag name @throw Error("No dataSet for record Id") if tag is unknown */ - std::string tagName() const; + std::string tagName() const + { return pKey_ == 0 ? "" : pKey_->tagName(); } //! Return the tag (aka dataset) number - uint16 tag() const { return tag_; } + uint16 tag() const + { return pKey_ == 0 ? 0 : pKey_->tag(); } //! Return the type id of the value TypeId typeId() const { return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); } @@ -217,10 +297,8 @@ namespace Exiv2 { private: // DATA - uint16 tag_; //!< Tag value - uint16 record_; //!< Record value + IptcKey* pKey_; //!< Key Value* pValue_; //!< Pointer to the value - std::string key_; //!< Key bool modified_; //!< Change indicator }; // class Iptcdatum @@ -341,13 +419,13 @@ namespace Exiv2 { */ long copy(byte* buf); /*! - @brief Add a Iptcdatum from the supplied key and value pair. This + @brief Add an %Iptcdatum from the supplied key and value pair. This method copies (clones) the value. A check for non-repeatable datasets is performed. @return 0 if successful;
- 6 if the dataset already exists and is not repeatable;
+ 6 if the dataset already exists and is not repeatable */ - int add(const std::string& key, Value* value); + int add(const IptcKey& key, Value* value); /*! @brief Add a copy of the Iptcdatum to the Iptc metadata. A check for non-repeatable datasets is performed. @@ -375,7 +453,7 @@ namespace Exiv2 { If multiple entries with the same key exist, it is undefined which of the matching metadata is found. */ - iterator findKey(const std::string& key); + iterator findKey(const IptcKey& key); /*! @brief Find a Iptcdatum with the given record and dataset it, return a const iterator to it. If multiple entries with the @@ -404,11 +482,11 @@ namespace Exiv2 { //! End of the metadata const_iterator end() const { return iptcMetadata_.end(); } /*! - @brief Find a Iptcdatum with the given key, return a const iterator to - it. If multiple metadata with the same key exist it is + @brief Find an Iptcdatum with the given key, return a const iterator + to it. If multiple metadata with the same key exist it is undefined which of the matching metadata is found. */ - const_iterator findKey(const std::string& key) const; + const_iterator findKey(const IptcKey& key) const; /*! @brief Find a Iptcdatum with the given record and dataset number, return a const iterator to it. If multiple metadata with the @@ -473,24 +551,6 @@ namespace Exiv2 { mutable bool modified_; }; // class IptcData -// ***************************************************************************** -// free functions - - /*! - @brief Return a key for the entry. The key is of the form - 'Iptc.recordName.datasetName'. - @throw Error ("No dataSet for record Id") if the dataset number or - record Id is unknown - */ - std::string makeKey(uint16 number, uint16 record); - /*! - @brief Return the record and dataset id pair for the key. - @return A pair consisting of the record and dataset id. - @throw Error ("Invalid key") if the key cannot be parsed into - valid record and dataset parts. - */ - std::pair decomposeKey(const std::string& key); - } // namespace Exiv2 #endif // #ifndef IPTC_HPP_ diff --git a/src/iptctest.cpp b/src/iptctest.cpp index cee30d3f..8553eb0f 100644 --- a/src/iptctest.cpp +++ b/src/iptctest.cpp @@ -4,7 +4,7 @@ This is not designed to be a robust application. File : iptctest.cpp - Version : $Name: $ $Revision: 1.1 $ + Version : $Name: $ $Revision: 1.2 $ Author(s): Brad Schick (brad) History : 01-Aug-04, brad: created */ @@ -118,7 +118,7 @@ void processAdd(const std::string& line, int num) Value *val = Value::create(type); val->read(data); - int rc = g_iptcData.add(key, val); + int rc = g_iptcData.add(IptcKey(key), val); if (rc) { std::string error = IptcData::strError(rc, "Input file"); throw Error(error); @@ -180,7 +180,7 @@ void processModify(const std::string& line, int num) iter->setValue(val); } else { - int rc = g_iptcData.add(key, val); + int rc = g_iptcData.add(IptcKey(key), val); if (rc) { std::string error = IptcData::strError(rc, "Input file"); throw Error(error); diff --git a/src/makernote.cpp b/src/makernote.cpp index 97a53f24..606450fa 100644 --- a/src/makernote.cpp +++ b/src/makernote.cpp @@ -20,13 +20,13 @@ */ /* File: makernote.cpp - Version: $Name: $ $Revision: 1.24 $ + Version: $Name: $ $Revision: 1.25 $ Author(s): Andreas Huggel (ahu) History: 18-Feb-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.24 $ $RCSfile: makernote.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.25 $ $RCSfile: makernote.cpp,v $"); // Define DEBUG_* to output debug information to std::cerr #undef DEBUG_MAKERNOTE @@ -59,28 +59,29 @@ namespace Exiv2 { std::string MakerNote::makeKey(uint16 tag) const { - return std::string(ExifTags::ifdItem(makerIfd)) - + "." + sectionName(tag) + "." + tagName(tag); + return std::string(ExifTags::familyName()) + + "." + std::string(ifdItem()) + + "." + tagName(tag); } // MakerNote::makeKey uint16 MakerNote::decomposeKey(const std::string& key) const { - // Get the IFD, section name and tag name parts of the key + // 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 ifdItem = key.substr(0, pos1); + 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 sectionName = key.substr(pos0, pos1 - pos0); + std::string ifdItem = key.substr(pos0, pos1 - pos0); pos0 = pos1 + 1; std::string tagName = key.substr(pos0); if (tagName == "") throw Error("Invalid key"); - if (ifdItem != ExifTags::ifdItem(makerIfd)) return 0xffff; + if (familyName != ExifTags::familyName()) return 0xffff; uint16 tag = this->tag(tagName); if (tag == 0xffff) return tag; - if (sectionName != this->sectionName(tag)) return 0xffff; + if (ifdItem != this->ifdItem()) return 0xffff; return tag; } // MakerNote::decomposeKey diff --git a/src/makernote.hpp b/src/makernote.hpp index 86435fb7..074b582e 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.21 $ + @version $Name: $ $Revision: 1.22 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 18-Feb-04, ahu: created @@ -222,8 +222,8 @@ namespace Exiv2 { virtual Entries::const_iterator findIdx(int idx) const =0; //! Return the size of the makernote in bytes virtual long size() const =0; - //! Return the name of the makernote section - virtual std::string sectionName(uint16 tag) const =0; + //! Return the name of the makernote item + virtual std::string ifdItem() const =0; //! Interpret and print the value of a makernote tag virtual std::ostream& printTag(std::ostream& os, uint16 tag, @@ -327,7 +327,7 @@ namespace Exiv2 { */ virtual long headerSize() const; virtual IfdMakerNote* clone(bool alloc =true) const =0; - virtual std::string sectionName(uint16 tag) const =0; + virtual std::string ifdItem() const =0; virtual std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const =0; diff --git a/src/metadatum.hpp b/src/metadatum.hpp index bc60b443..96c9c29e 100644 --- a/src/metadatum.hpp +++ b/src/metadatum.hpp @@ -20,14 +20,15 @@ */ /*! @file metadatum.hpp - @brief Provides class Metadatum - @version $Name: $ $Revision: 1.1 $ + @brief Provides abstract base classes Metadatum and Key + @version $Name: $ $Revision: 1.2 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Brad Schick (brad) schick@robotbattle.com @date 09-Jan-04, ahu: created
- 31-Jul-04, brad: isolated as a component + 31-Jul-04, brad: isolated as a component
+ 23-Aug-04, ahu: added Key */ #ifndef METADATUM_HPP_ #define METADATUM_HPP_ @@ -48,10 +49,82 @@ namespace Exiv2 { // class definitions /*! - @brief Information related to one Exif tag. + @brief Abstract base class defining the %Key of a metadatum. + Keys are used to identify and group metadata. + */ + class Key { + public: + //! @name Creators + //@{ + //! Destructor + virtual ~Key() {} + //@} + + //! @name Accessors + //@{ + /*! + @brief Return the key of the metadatum as a string. The key is of the + form 'familyName.groupName.tagName'. Note however that the + key is not necessarily unique, e.g., an ExifData may contain + multiple metadata with the same key. + */ + virtual std::string key() const =0; + //! Return an identifier for the type of metadata (the first part of the key) + virtual const char* familyName() const =0; + //! Return the name of the group (the second part of the key) + virtual std::string groupName() const =0; + //! Return the name of the tag (which is also the third part of the key) + virtual std::string tagName() const =0; + //! Return the tag number + virtual uint16 tag() const =0; + /*! + @brief Return a pointer to a copy of itself (deep copy). + The caller owns this copy and is responsible to delete it! + */ + virtual Key* clone() const =0; + /*! + @brief Write the key to an output stream. You do not usually have + to use this function; it is used for the implementation of + the output operator for %Key, + operator<<(std::ostream &os, const Key &key). + */ + std::ostream& write(std::ostream& os) const { return os << key(); } + //@} + + protected: + //! @name Manipulators + //@{ + /*! + @brief Assignment operator. Protected so that it can only be used + by subclasses but not directly. + */ + Key& operator=(const Key& rhs) { return *this; } + //@} + + }; // class Key + + //! Output operator for Key types + inline std::ostream& operator<<(std::ostream& os, const Key& key) + { + return key.write(os); + } + + /*! + @brief Abstract base class defining the interface to access information + related to one metadata tag. */ class Metadatum { public: + //! @name Creators + //@{ + //! Default Constructor + Metadatum() {} + //! Copy constructor + Metadatum(const Metadatum& rhs) {} + //! Destructor + virtual ~Metadatum() {} + //@} + //! @name Manipulators //@{ /*! @@ -83,7 +156,7 @@ namespace Exiv2 { virtual long copy(byte* buf, ByteOrder byteOrder) const =0; /*! @brief Return the key of the metadatum. The key is of the form - 'ifdItem.sectionName.tagName'. Note however that the key + 'familyName.ifdItem.tagName'. Note however that the key is not necessarily unique, i.e., an ExifData may contain multiple metadata with the same key. */ @@ -161,19 +234,12 @@ namespace Exiv2 { //@} protected: - //! @name Creators - //@{ - //! Default Constructor - Metadatum() {} - //! Copy constructor - Metadatum(const Metadatum& rhs) {} - //! Destructor - virtual ~Metadatum() {} - //@} - //! @name Manipulators //@{ - //! Assignment operator + /*! + @brief Assignment operator. Protected so that it can only be used + by subclasses but not directly. + */ Metadatum& operator=(const Metadatum& rhs) { return *this; } //@} diff --git a/src/nikonmn.cpp b/src/nikonmn.cpp index ad5d20bf..beef3196 100644 --- a/src/nikonmn.cpp +++ b/src/nikonmn.cpp @@ -20,14 +20,14 @@ */ /* File: nikon1mn.cpp - Version: $Name: $ $Revision: 1.4 $ + Version: $Name: $ $Revision: 1.5 $ 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.4 $ $RCSfile: nikonmn.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.5 $ $RCSfile: nikonmn.cpp,v $"); // ***************************************************************************** // included header files @@ -73,7 +73,7 @@ namespace Exiv2 { }; Nikon1MakerNote::Nikon1MakerNote(bool alloc) - : IfdMakerNote(nikon1MnTagInfo, alloc), sectionName_("Nikon1") + : IfdMakerNote(nikon1MnTagInfo, alloc), ifdItem_("Nikon1") { } @@ -198,7 +198,7 @@ namespace Exiv2 { }; Nikon2MakerNote::Nikon2MakerNote(bool alloc) - : IfdMakerNote(nikon2MnTagInfo, alloc), sectionName_("Nikon2") + : IfdMakerNote(nikon2MnTagInfo, alloc), ifdItem_("Nikon2") { } @@ -383,7 +383,7 @@ namespace Exiv2 { }; Nikon3MakerNote::Nikon3MakerNote(bool alloc) - : IfdMakerNote(nikon3MnTagInfo, alloc), sectionName_("Nikon3") + : IfdMakerNote(nikon3MnTagInfo, alloc), ifdItem_("Nikon3") { absOffset_ = false; } diff --git a/src/nikonmn.hpp b/src/nikonmn.hpp index 9b740b42..ca129721 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.3 $ + @version $Name: $ $Revision: 1.4 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 17-May-04, ahu: created
@@ -103,8 +103,8 @@ namespace Exiv2 { //! @name Accessors //@{ Nikon1MakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Nikon1") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Nikon1") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -149,8 +149,8 @@ namespace Exiv2 { */ static const RegisterMakerNote register_; - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class Nikon1MakerNote @@ -182,8 +182,8 @@ namespace Exiv2 { //@{ int checkHeader() const; Nikon2MakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Nikon2") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Nikon2") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -206,8 +206,8 @@ namespace Exiv2 { //@} private: - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class Nikon2MakerNote @@ -236,8 +236,8 @@ namespace Exiv2 { //@{ int checkHeader() const; Nikon3MakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Nikon3") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Nikon3") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -258,8 +258,8 @@ namespace Exiv2 { //@} private: - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class Nikon3MakerNote diff --git a/src/sigmamn.cpp b/src/sigmamn.cpp index b5181d70..daa62e51 100644 --- a/src/sigmamn.cpp +++ b/src/sigmamn.cpp @@ -20,7 +20,7 @@ */ /* File: sigmamn.cpp - Version: $Name: $ $Revision: 1.8 $ + Version: $Name: $ $Revision: 1.9 $ Author(s): Andreas Huggel (ahu) History: 02-Apr-04, ahu: created Credits: Sigma and Foveon MakerNote implemented according to the specification @@ -29,7 +29,7 @@ */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.8 $ $RCSfile: sigmamn.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: sigmamn.cpp,v $"); // ***************************************************************************** // included header files @@ -83,7 +83,7 @@ namespace Exiv2 { }; SigmaMakerNote::SigmaMakerNote(bool alloc) - : IfdMakerNote(sigmaMnTagInfo, alloc), sectionName_("Sigma") + : IfdMakerNote(sigmaMnTagInfo, alloc), ifdItem_("Sigma") { } diff --git a/src/sigmamn.hpp b/src/sigmamn.hpp index 87e5cdd8..0ae6d3d3 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.6 $ + @version $Name: $ $Revision: 1.7 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 02-Apr-04, ahu: created @@ -105,8 +105,8 @@ namespace Exiv2 { //@{ int checkHeader() const; SigmaMakerNote* clone(bool alloc =true) const; - //! Return the name of the makernote section ("Sigma") - std::string sectionName(uint16 tag) const { return sectionName_; } + //! Return the name of the makernote item ("Sigma") + std::string ifdItem() const { return ifdItem_; } std::ostream& printTag(std::ostream& os, uint16 tag, const Value& value) const; @@ -148,8 +148,8 @@ namespace Exiv2 { */ static const RegisterMakerNote register_; - //! The section name (second part of the key) used for makernote tags - std::string sectionName_; + //! The item name (second part of the key) used for makernote tags + std::string ifdItem_; }; // class SigmaMakerNote diff --git a/src/taglist.cpp b/src/taglist.cpp index 249ae020..d576afb2 100644 --- a/src/taglist.cpp +++ b/src/taglist.cpp @@ -3,13 +3,13 @@ Abstract: Print a simple comma separated list of tags defined in Exiv2 File: taglist.cpp - Version: $Name: $ $Revision: 1.8 $ + Version: $Name: $ $Revision: 1.9 $ Author(s): Andreas Huggel (ahu) History: 07-Jan-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.8 $ $RCSfile: taglist.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: taglist.cpp,v $"); #include "makernote.hpp" #include "nikonmn.hpp" @@ -33,28 +33,28 @@ try { case 2: { MakerNote* pMakerNote = 0; - std::string section(argv[1]); - if (section == "Iptc") { + std::string item(argv[1]); + if (item == "Iptc") { IptcDataSets::dataSetList(std::cout); break; } - if (section == "Canon") { + if (item == "Canon") { pMakerNote = new CanonMakerNote; } - else if (section == "Fuji") { + else if (item == "Fujifilm") { pMakerNote = new FujiMakerNote; } - else if (section == "Sigma") { + else if (item == "Sigma") { pMakerNote = new SigmaMakerNote; } - else if (section == "Nikon1") { + else if (item == "Nikon1") { pMakerNote = new Nikon1MakerNote; } - else if (section == "Nikon2") { + else if (item == "Nikon2") { pMakerNote = new Nikon2MakerNote; } - else if (section == "Nikon3") { + else if (item == "Nikon3") { pMakerNote = new Nikon3MakerNote; } @@ -76,7 +76,8 @@ try { break; } if (rc) { - std::cout << "Usage: " << argv[0] << " [SectionName|Iptc]\n" + std::cout << "Usage: " << argv[0] + << " [Canon|Fujifilm|Nikon1|Nikon2|Nikon3|Sigma|Iptc]\n" << "Print Exif tags, MakerNote tags, or Iptc datasets\n"; } return rc; diff --git a/src/tags.awk b/src/tags.awk index 4f10c8bc..0670ab4a 100644 --- a/src/tags.awk +++ b/src/tags.awk @@ -1,12 +1,12 @@ ################################################################################ # File : tags.awk -# Version : $Name: $ $Revision: 1.3 $ +# Version : $Name: $ $Revision: 1.4 $ # Author(s): Andreas Huggel (ahu) # History : 07-Feb-04, ahu: created # # Description: # Awk script to convert a taglist to XML format used in the documentation. -# $ taglist [SectionName] | awk -f tags.awk > tags.xml +# $ taglist [itemName] | awk -f tags.awk > tags.xml ################################################################################ BEGIN { diff --git a/src/tags.cpp b/src/tags.cpp index b399c67d..8ad58f06 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -20,13 +20,13 @@ */ /* File: tags.cpp - Version: $Name: $ $Revision: 1.32 $ + Version: $Name: $ $Revision: 1.33 $ Author(s): Andreas Huggel (ahu) History: 15-Jan-04, ahu: created */ // ***************************************************************************** #include "rcsid.hpp" -EXIV2_RCSID("@(#) $Name: $ $Revision: 1.32 $ $RCSfile: tags.cpp,v $"); +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.33 $ $RCSfile: tags.cpp,v $"); // ***************************************************************************** // included header files @@ -50,15 +50,16 @@ namespace Exiv2 { { } + // Important: IFD item must be unique! const IfdInfo ExifTags::ifdInfo_[] = { - IfdInfo(ifdIdNotSet, "(Unknown IFD)", "(Unknown data area)"), + IfdInfo(ifdIdNotSet, "(Unknown IFD)", "(Unknown item)"), IfdInfo(ifd0, "IFD0", "Image"), - IfdInfo(exifIfd, "Exif", "Image"), - IfdInfo(gpsIfd, "GPSInfo", "Image"), + IfdInfo(exifIfd, "Exif", "Photo"), // just to avoid 'Exif.Exif.*' keys + IfdInfo(gpsIfd, "GPSInfo", "GPSInfo"), IfdInfo(makerIfd, "Makernote", "Makernote"), - IfdInfo(iopIfd, "Iop", "Image"), + IfdInfo(iopIfd, "Iop", "Iop"), IfdInfo(ifd1, "IFD1", "Thumbnail"), - IfdInfo(lastIfdId, "(Last IFD info)", "(Last IFD info)") + IfdInfo(lastIfdId, "(Last IFD info)", "(Last IFD item)") }; SectionInfo::SectionInfo( @@ -265,6 +266,8 @@ namespace Exiv2 { 0 }; + const char* ExifTags::familyName_ = "Exif"; + int ExifTags::tagInfoIdx(uint16 tag, IfdId ifdId) { const TagInfo* tagInfo = tagInfos_[ifdId]; @@ -276,17 +279,6 @@ namespace Exiv2 { return idx; } - int ExifTags::tagInfoIdx(const std::string& tagName, 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].name_ == tagName) break; - } - return idx; - } - const char* ExifTags::tagName(uint16 tag, IfdId ifdId) { int idx = tagInfoIdx(tag, ifdId); @@ -317,6 +309,17 @@ namespace Exiv2 { return sectionInfo_[tagInfo[idx].sectionId_].desc_; } + uint16 ExifTags::tag(const std::string& tagName, IfdId ifdId) + { + 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; + } + return tagInfo[idx].tag_; + } + const char* ExifTags::ifdName(IfdId ifdId) { return ifdInfo_[ifdId].name_; @@ -343,8 +346,8 @@ namespace Exiv2 { std::string ExifTags::makeKey(uint16 tag, IfdId ifdId) { - return std::string(ifdItem(ifdId)) - + "." + std::string(sectionName(tag, ifdId)) + return std::string(familyName()) + + "." + std::string(ifdItem(ifdId)) + "." + std::string(tagName(tag, ifdId)); } @@ -352,41 +355,31 @@ namespace Exiv2 { // we find, it doesn't verify whether this is the only match. std::pair ExifTags::decomposeKey(const std::string& key) { - // Get the IFD, section name and tag name parts of the 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 ifdItem = key.substr(0, pos1); + 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 sectionName = key.substr(pos0, pos1 - pos0); + std::string ifdItem = key.substr(pos0, pos1 - pos0); pos0 = pos1 + 1; std::string tagName = key.substr(pos0); if (tagName == "") throw Error("Invalid key"); - // Check if this is a MakerNote key, stop processing if it is - if (ifdItem == ifdInfo_[makerIfd].item_) { - return std::make_pair(0xffff, makerIfd); + // Find IfdId + int i; + for (i = int(lastIfdId) - 1; i > 0; --i) { + if (ifdInfo_[i].item_ == ifdItem) break; } + IfdId ifdId = IfdId(i); - // Use the parts of the key to find tag and IFD id - IfdId ifdId = ifdIdNotSet; - uint16 tag = 0xffff; + if (ifdId == ifdIdNotSet) return std::make_pair(0xffff, ifdId); - SectionId s = sectionId(sectionName); - if (s == sectionIdNotSet) return std::make_pair(tag, ifdId); - - for (int i = 0; i < lastIfdId; ++i) { - if (ifdInfo_[i].item_ == ifdItem) { - ifdId = ifdInfo_[i].ifdId_; - int k = tagInfoIdx(tagName, ifdId); - if (k != -1 && tagInfos_[ifdId][k].sectionId_ == s) { - tag = tagInfos_[ifdId][k].tag_; - break; - } - } - } - return std::make_pair(tag, ifdId); + return std::make_pair(tag(tagName, ifdId), ifdId); } // ExifTags::decomposeKey std::ostream& ExifTags::printTag(std::ostream& os, diff --git a/src/tags.hpp b/src/tags.hpp index c9de0095..3e5eec73 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.24 $ + @version $Name: $ $Revision: 1.25 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
@@ -72,7 +72,8 @@ namespace Exiv2 { IfdInfo(IfdId ifdId, const char* name, const char* item); IfdId ifdId_; //!< IFD id const char* name_; //!< IFD name - const char* item_; //!< Related image item + //! Related IFD item. This is also an IFD name, unique for each IFD. + const char* item_; }; //! Contains information pertaining to one section @@ -113,6 +114,9 @@ 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. @param tag The tag @@ -167,7 +171,7 @@ namespace Exiv2 { static SectionId sectionId(const std::string& sectionName); /*! @brief Return the key for the tag and IFD id. The key is of the form - 'ifdItem.sectionName.tagName'. + 'Exif.ifdItem.tagName'. */ static std::string makeKey(uint16 tag, IfdId ifdId); /*! @@ -187,7 +191,8 @@ namespace Exiv2 { private: static int tagInfoIdx(uint16 tag, IfdId ifdId); - static int tagInfoIdx(const std::string& tagName, IfdId ifdId); + + static const char* familyName_; static const IfdInfo ifdInfo_[]; static const SectionInfo sectionInfo_[]; diff --git a/src/write-test.cpp b/src/write-test.cpp index 24eb7be5..caa2d20b 100644 --- a/src/write-test.cpp +++ b/src/write-test.cpp @@ -3,7 +3,7 @@ Abstract : ExifData write unit tests Author(s): Andreas Huggel (ahu) - Version : $Name: $ $Revision: 1.7 $ + Version : $Name: $ $Revision: 1.8 $ Test procedure: $ rm -f test.jpg thumb.jpg iii ttt; @@ -59,77 +59,77 @@ try { std::cerr << "Case 1: "; std::cerr << "Non-intrusive change to the standard Exif metadata\n"; testCase(testFile, "test1.jpg", "thumb1", - "Image.DateTime.DateTimeOriginal", + "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22"); break; case 2: std::cerr << "Case 2: "; std::cerr << "Non-intrusive change to the makernote metadata\n"; testCase(testFile, "test2.jpg", "thumb2", - "Makernote.Canon.OwnerName", + "Exif.Canon.OwnerName", "Chan YeeSend"); break; case 3: std::cerr << "Case 3: "; std::cerr << "Non-intrusive change to the Exif metadata (w/o makernote)\n"; testCase(testFile, "test3.jpg", "thumb3", - "Image.DateTime.DateTimeOriginal", + "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22"); break; case 4: std::cerr << "Case 4: "; std::cerr << "Intrusive change to the standard Exif metadata\n"; testCase(testFile, "test4.jpg", "thumb4", - "Image.DateTime.DateTimeOriginal", + "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22 and twenty seconds"); break; case 5: std::cerr << "Case 5: "; std::cerr << "Intrusive change to the Canon makernote metadata\n"; testCase(testFile, "test5.jpg", "thumb5", - "Makernote.Canon.OwnerName", + "Exif.Canon.OwnerName", "Frau Chan YeeSend und Herr Andreas Huggel"); break; case 6: std::cerr << "Case 6: "; std::cerr << "Intrusive change to the Exif metadata (w/o makernote)\n"; testCase(testFile, "test6.jpg", "thumb6", - "Image.DateTime.DateTimeOriginal", + "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22 and twenty seconds"); break; case 7: std::cerr << "Case 7: "; std::cerr << "Intrusive change to the Fujifilm makernote metadata\n"; testCase(testFile, "test7.jpg", "thumb7", - "Makernote.Fujifilm.Quality", + "Exif.Fujifilm.Quality", "Typical Fujifilm Quality"); break; case 8: std::cerr << "Case 8: "; std::cerr << "Intrusive change to the Sigma makernote metadata\n"; testCase(testFile, "test8.jpg", "thumb8", - "Makernote.Sigma.ResolutionMode", + "Exif.Sigma.ResolutionMode", "Sigma HI resolution"); break; case 9: std::cerr << "Case 9: "; std::cerr << "Intrusive change to the Nikon1 makernote metadata\n"; testCase(testFile, "test9.jpg", "thumb9", - "Makernote.Nikon1.Quality", + "Exif.Nikon1.Quality", "Typical Nikon1 Quality"); break; case 10: std::cerr << "Case 10: "; std::cerr << "Intrusive change to the Nikon2 makernote metadata\n"; testCase(testFile, "test10.jpg", "thumb10", - "Makernote.Nikon2.0x0002", + "Exif.Nikon2.0x0002", "Nikon2 Version 2"); break; case 11: std::cerr << "Case 11: "; std::cerr << "Intrusive change to the Nikon3 makernote metadata\n"; testCase(testFile, "test11.jpg", "thumb11", - "Makernote.Nikon3.Quality", + "Exif.Nikon3.Quality", "Typical Nikon3 Quality"); break; @@ -159,6 +159,7 @@ void testCase(const std::string& file1, const std::string& key, const std::string& value) { + ExifKey ek(key); ExifData ed1; std::cerr << "---> Reading file " << file1 << "\n"; @@ -169,9 +170,9 @@ void testCase(const std::string& file1, } std::cerr << "---> Modifying Exif data\n"; - Exiv2::ExifData::iterator pos = ed1.findKey(key); + Exiv2::ExifData::iterator pos = ed1.findKey(ek); if (pos == ed1.end()) { - throw Error("Metadatum with key = " + key + " not found"); + throw Error("Metadatum with key = " + ek.key() + " not found"); } pos->setValue(value); diff --git a/src/write2-test.cpp b/src/write2-test.cpp index bbf26e08..dac072ad 100644 --- a/src/write2-test.cpp +++ b/src/write2-test.cpp @@ -3,7 +3,7 @@ Abstract : ExifData write unit tests for Exif data created from scratch File : write2-test.cpp - Version : $Name: $ $Revision: 1.4 $ + Version : $Name: $ $Revision: 1.5 $ Author(s): Andreas Huggel (ahu) History : 26-Jun-04, ahu: created @@ -31,7 +31,7 @@ try { std::cout <<"----- One IFD0 tag\n"; Exiv2::ExifData ed1; - Exiv2::Exifdatum md1(Exiv2::ExifKey("Image.OtherTags.Model")); + Exiv2::Exifdatum md1(Exiv2::ExifKey("Exif.Image.Model")); md1.setValue("Test 1"); ed1.add(md1); write(file, ed1); @@ -39,7 +39,7 @@ try { std::cout <<"\n----- One Exif tag\n"; Exiv2::ExifData ed2; - Exiv2::Exifdatum md2(Exiv2::ExifKey("Image.DateTime.DateTimeOriginal")); + Exiv2::Exifdatum md2(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal")); md2.setValue("Test 2"); ed2.add(md2); write(file, ed2); @@ -49,7 +49,7 @@ try { std::cout <<"\n----- One IOP tag\n"; Exiv2::ExifData ed3; - Exiv2::Exifdatum md3(Exiv2::ExifKey("Image.Interoperability.InteroperabilityVersion")); + Exiv2::Exifdatum md3(Exiv2::ExifKey("Exif.Iop.InteroperabilityVersion")); md3.setValue("Test 3"); ed3.add(md3); write(file, ed3); @@ -57,7 +57,7 @@ try { std::cout <<"\n----- One GPS tag\n"; Exiv2::ExifData ed4; - Exiv2::Exifdatum md4(Exiv2::ExifKey("Image.GPS.GPSVersionID")); + Exiv2::Exifdatum md4(Exiv2::ExifKey("Exif.GPSInfo.GPSVersionID")); md4.setValue("Test 4"); ed4.add(md4); write(file, ed4); @@ -66,11 +66,11 @@ try { // Todo: Fix this std::cout <<"\n----- One IFD1 tag\n"; Exiv2::ExifData ed5; - Exiv2::Exifdatum md5(Exiv2::ExifKey("Thumbnail.OtherTags.Artist")); + Exiv2::Exifdatum md5(Exiv2::ExifKey("Exif.Thumbnail.Artist")); md5.setValue("Test 5"); ed5.add(md5); - Exiv2::Exifdatum md6(Exiv2::ExifKey("Image.OtherTags.Model")); + Exiv2::Exifdatum md6(Exiv2::ExifKey("Exif.Image.Model")); md6.setValue("Test 5 (Fix me!)"); ed5.add(md6);