[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r1228 - in Extractor: . src/plugins src/plugins/exiv2
From: |
grothoff |
Subject: |
[GNUnet-SVN] r1228 - in Extractor: . src/plugins src/plugins/exiv2 |
Date: |
Sun, 3 Jul 2005 12:44:50 -0700 (PDT) |
Author: grothoff
Date: 2005-07-03 12:43:52 -0700 (Sun, 03 Jul 2005)
New Revision: 1228
Added:
Extractor/src/plugins/exiv2/actions.cpp
Extractor/src/plugins/exiv2/actions.hpp
Extractor/src/plugins/exiv2/addmoddel.cpp
Extractor/src/plugins/exiv2/basicio.cpp
Extractor/src/plugins/exiv2/basicio.hpp
Extractor/src/plugins/exiv2/canonmn.cpp
Extractor/src/plugins/exiv2/canonmn.hpp
Extractor/src/plugins/exiv2/datasets.cpp
Extractor/src/plugins/exiv2/datasets.hpp
Extractor/src/plugins/exiv2/doxygen.hpp
Extractor/src/plugins/exiv2/error.cpp
Extractor/src/plugins/exiv2/error.hpp
Extractor/src/plugins/exiv2/exif.cpp
Extractor/src/plugins/exiv2/exif.hpp
Extractor/src/plugins/exiv2/exifcomment.cpp
Extractor/src/plugins/exiv2/exifprint.cpp
Extractor/src/plugins/exiv2/exiv2.cpp
Extractor/src/plugins/exiv2/exiv2.hpp
Extractor/src/plugins/exiv2/exiv2extractor.cc
Extractor/src/plugins/exiv2/fujimn.cpp
Extractor/src/plugins/exiv2/fujimn.hpp
Extractor/src/plugins/exiv2/futils.cpp
Extractor/src/plugins/exiv2/futils.hpp
Extractor/src/plugins/exiv2/ifd.cpp
Extractor/src/plugins/exiv2/ifd.hpp
Extractor/src/plugins/exiv2/image.cpp
Extractor/src/plugins/exiv2/image.hpp
Extractor/src/plugins/exiv2/iptc.cpp
Extractor/src/plugins/exiv2/iptc.hpp
Extractor/src/plugins/exiv2/iptceasy.cpp
Extractor/src/plugins/exiv2/iptcprint.cpp
Extractor/src/plugins/exiv2/jpgimage.cpp
Extractor/src/plugins/exiv2/jpgimage.hpp
Extractor/src/plugins/exiv2/makernote.cpp
Extractor/src/plugins/exiv2/makernote.hpp
Extractor/src/plugins/exiv2/metacopy.cpp
Extractor/src/plugins/exiv2/metacopy.hpp
Extractor/src/plugins/exiv2/metadatum.cpp
Extractor/src/plugins/exiv2/metadatum.hpp
Extractor/src/plugins/exiv2/mn.hpp
Extractor/src/plugins/exiv2/nikonmn.cpp
Extractor/src/plugins/exiv2/nikonmn.hpp
Extractor/src/plugins/exiv2/olympusmn.cpp
Extractor/src/plugins/exiv2/olympusmn.hpp
Extractor/src/plugins/exiv2/panasonicmn.cpp
Extractor/src/plugins/exiv2/panasonicmn.hpp
Extractor/src/plugins/exiv2/rcsid.hpp
Extractor/src/plugins/exiv2/sigmamn.cpp
Extractor/src/plugins/exiv2/sigmamn.hpp
Extractor/src/plugins/exiv2/sonymn.cpp
Extractor/src/plugins/exiv2/sonymn.hpp
Extractor/src/plugins/exiv2/taglist.cpp
Extractor/src/plugins/exiv2/tags.cpp
Extractor/src/plugins/exiv2/tags.hpp
Extractor/src/plugins/exiv2/types.cpp
Extractor/src/plugins/exiv2/types.hpp
Extractor/src/plugins/exiv2/utils.cpp
Extractor/src/plugins/exiv2/utils.hpp
Extractor/src/plugins/exiv2/value.cpp
Extractor/src/plugins/exiv2/value.hpp
Removed:
Extractor/src/plugins/exiv2extractor.cc
Modified:
Extractor/configure.ac
Extractor/src/plugins/Makefile.am
Log:
adding exiv2
Modified: Extractor/configure.ac
===================================================================
--- Extractor/configure.ac 2005-07-03 19:32:53 UTC (rev 1227)
+++ Extractor/configure.ac 2005-07-03 19:43:52 UTC (rev 1228)
@@ -279,6 +279,7 @@
src/plugins/printable/Makefile
src/plugins/hash/Makefile
src/plugins/thumbnail/Makefile
+src/plugins/exiv2/Makefile
src/test/Makefile
])
Modified: Extractor/src/plugins/Makefile.am
===================================================================
--- Extractor/src/plugins/Makefile.am 2005-07-03 19:32:53 UTC (rev 1227)
+++ Extractor/src/plugins/Makefile.am 2005-07-03 19:43:52 UTC (rev 1228)
@@ -62,7 +62,6 @@
libextractor_zip.la \
libextractor_lower.la \
libextractor_translit.la \
- libextractor_exiv2.la \
$(extraqt) \
$(extraogg)
@@ -253,7 +252,3 @@
libextractor_translit_la_LDFLAGS = \
$(PLUGINFLAGS)
-libextractor_exiv2_la_SOURCES = \
- exiv2extractor.cc
-libextractor_exiv2_la_LDFLAGS = \
- -lexiv2 $(PLUGINFLAGS)
Added: Extractor/src/plugins/exiv2/actions.cpp
===================================================================
--- Extractor/src/plugins/exiv2/actions.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/actions.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,1331 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: actions.cpp
+ Version: $Rev: 583 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 08-Dec-03, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: actions.cpp 583 2005-06-12 06:41:40Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "actions.hpp"
+#include "image.hpp"
+#include "exiv2.hpp"
+#include "utils.hpp"
+#include "types.hpp"
+#include "exif.hpp"
+#include "canonmn.hpp"
+#include "iptc.hpp"
+#include "futils.hpp"
+#ifndef EXV_HAVE_TIMEGM
+# include "timegm.h"
+#endif
+
+// + standard includes
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+#include <cstring>
+#include <cstdio>
+#include <ctime>
+#include <cmath>
+#include <cassert>
+#include <sys/types.h> // for stat()
+#include <sys/stat.h> // for stat()
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // for stat()
+#endif
+
+//
*****************************************************************************
+// local declarations
+namespace {
+
+ // Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type,
+ // returns 0 if successful
+ int str2Tm(const std::string& timeStr, struct tm* tm);
+
+ // Convert a string "YYYY:MM:DD HH:MI:SS" to a UTC time, -1 on error
+ time_t str2Time(const std::string& timeStr);
+
+ // Convert a UTC time to a string "YYYY:MM:DD HH:MI:SS", "" on error
+ std::string time2Str(time_t time);
+
+ /*!
+ @brief Copy metadata from source to target according to Params::copyXyz
+
+ @param source Source file path
+ @param target Target file path. An *.exv file is created if target
doesn't
+ exist.
+ @param preserve Indicates if existing metadata in the target file should
+ be kept.
+ @return 0 if successful, else an error code
+ */
+ int metacopy(const std::string& source,
+ const std::string& target,
+ bool preserve);
+}
+
+//
*****************************************************************************
+// class member definitions
+namespace Action {
+
+ Task::AutoPtr Task::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ TaskFactory* TaskFactory::instance_ = 0;
+
+ TaskFactory& TaskFactory::instance()
+ {
+ if (0 == instance_) {
+ instance_ = new TaskFactory;
+ }
+ return *instance_;
+ } // TaskFactory::instance
+
+ void TaskFactory::registerTask(TaskType type, Task::AutoPtr task)
+ {
+ Registry::iterator i = registry_.find(type);
+ if (i != registry_.end()) {
+ delete i->second;
+ }
+ registry_[type] = task.release();
+ } // TaskFactory::registerTask
+
+ TaskFactory::TaskFactory()
+ {
+ // Register a prototype of each known task
+ registerTask(adjust, Task::AutoPtr(new Adjust));
+ registerTask(print, Task::AutoPtr(new Print));
+ registerTask(rename, Task::AutoPtr(new Rename));
+ registerTask(erase, Task::AutoPtr(new Erase));
+ registerTask(extract, Task::AutoPtr(new Extract));
+ registerTask(insert, Task::AutoPtr(new Insert));
+ registerTask(modify, Task::AutoPtr(new Modify));
+ } // TaskFactory c'tor
+
+ Task::AutoPtr TaskFactory::create(TaskType type)
+ {
+ Registry::const_iterator i = registry_.find(type);
+ if (i != registry_.end() && i->second != 0) {
+ Task* t = i->second;
+ return t->clone();
+ }
+ return Task::AutoPtr(0);
+ } // TaskFactory::create
+
+ int Print::run(const std::string& path)
+ try {
+ path_ = path;
+ int rc = 0;
+ switch (Params::instance().printMode_) {
+ case Params::pmSummary: rc = printSummary(); break;
+ case Params::pmInterpreted: rc = printInterpreted(); break;
+ case Params::pmValues: rc = printValues(); break;
+ case Params::pmHexdump: rc = printHexdump(); break;
+ case Params::pmIptc: rc = printIptc(); break;
+ case Params::pmComment: rc = printComment(); break;
+ }
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e) {
+ std::cerr << "Exiv2 exception in print action for file "
+ << path << ":\n" << e << "\n";
+ return 1;
+ } // Print::run
+
+ int Print::printSummary()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path_
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ align_ = 16;
+
+ // Filename
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Filename" << ": " << path_ << std::endl;
+
+ // Filesize
+ struct stat buf;
+ if (0 == stat(path_.c_str(), &buf)) {
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Filesize" << ": " << buf.st_size << " Bytes"
+ << std::endl;
+ }
+
+ // Camera make
+ printTag(exifData, "Exif.Image.Make", "Camera make");
+
+ // Camera model
+ printTag(exifData, "Exif.Image.Model", "Camera model");
+
+ // Image Timestamp
+ printTag(exifData, "Exif.Photo.DateTimeOriginal", "Image timestamp");
+
+ // Image number
+ // Todo: Image number for cameras other than Canon
+ 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, "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) {
+ std::cout << "1/" << static_cast<long>(tmp) << " s";
+ }
+ else {
+ std::cout << static_cast<long>(1/tmp) << " s";
+ }
+ }
+ }
+ std::cout << std::endl;
+
+ // Aperture
+ // Get if from FNumber and, failing that, try ApertureValue
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Aperture" << ": ";
+ 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);
+ }
+ }
+ std::cout << std::endl;
+
+ // Exposure bias
+ printTag(exifData, "Exif.Photo.ExposureBiasValue", "Exposure bias");
+
+ // Flash
+ printTag(exifData, "Exif.Photo.Flash", "Flash");
+
+ // Todo: Flash bias, flash energy
+ // Todo: Implement this for other cameras
+ bool done = false;
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Flash bias" << ": ";
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs2.FlashBias");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Panasonic.FlashBias");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Olympus.FlashBias");
+ }
+ std::cout << std::endl;
+
+ // Actual focal length and 35 mm equivalent
+ // Todo: Calculate 35 mm equivalent a la jhead
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Focal length" << ": ";
+ 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 << ")";
+ }
+ }
+ std::cout << std::endl;
+
+ // Subject distance
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Subject distance" << ": ";
+ done = false;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Photo.SubjectDistance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs2.SubjectDistance");
+ }
+ std::cout << std::endl;
+
+ // ISO speed
+ // from ISOSpeedRatings or the Makernote
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "ISO speed" << ": ";
+ done = false;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Photo.ISOSpeedRatings");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs1.ISOSpeed");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon1.ISOSpeed");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon2.ISOSpeed");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon3.ISOSpeed");
+ }
+ std::cout << std::endl;
+
+ // Exposure mode
+ // From ExposureProgram or Canon Makernote
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Exposure mode" << ": ";
+ done = false;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Photo.ExposureProgram");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs1.ExposureProgram");
+ }
+ std::cout << std::endl;
+
+ // 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;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs1.Macro");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Fujifilm.Macro");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Olympus.Macro");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Panasonic.Macro");
+ }
+ std::cout << std::endl;
+
+ // Image quality setting (compression)
+ // Todo: Implement this for other cameras
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Image quality" << ": ";
+ done = false;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs1.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Fujifilm.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Sigma.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon1.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon2.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon3.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Olympus.Quality");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Panasonic.Quality");
+ }
+ std::cout << std::endl;
+
+ // Exif Resolution
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Exif Resolution" << ": ";
+ long xdim = 0;
+ long ydim = 0;
+ md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
+ if (md != exifData.end()) xdim = md->toLong();
+ 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;
+ }
+ std::cout << std::endl;
+
+ // White balance
+ // Todo: Implement this for other cameras
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "White balance" << ": ";
+ done = false;
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.CanonCs2.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Fujifilm.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Sigma.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon1.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon2.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Nikon3.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Olympus.WhiteBalance");
+ }
+ if (!done) {
+ done = 0 != printTag(exifData, "Exif.Panasonic.WhiteBalance");
+ }
+ std::cout << std::endl;
+
+ // Thumbnail
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << "Thumbnail" << ": ";
+ std::string thumbExt = exifData.thumbnailExtension();
+ if (thumbExt.empty()) {
+ std::cout << "None";
+ }
+ else {
+ Exiv2::DataBuf buf = exifData.copyThumbnail();
+ std::cout << exifData.thumbnailFormat() << ", "
+ << buf.size_ << " Bytes";
+ }
+ std::cout << std::endl;
+
+ // Copyright
+ printTag(exifData, "Exif.Image.Copyright", "Copyright");
+
+ // Exif Comment
+ printTag(exifData, "Exif.Photo.UserComment", "Exif comment");
+ std::cout << std::endl;
+
+ return 0;
+ } // Print::printSummary
+
+ int Print::printTag(const Exiv2::ExifData& exifData,
+ const std::string& key,
+ const std::string& label) const
+ {
+ int rc = 0;
+ if (!label.empty()) {
+ // Print the label in any case for the moment (to see what's
missing)
+ std::cout << std::setw(align_) << std::setfill(' ') << std::left
+ << label << ": ";
+ }
+ Exiv2::ExifKey ek(key);
+ Exiv2::ExifData::const_iterator md = exifData.findKey(ek);
+ if (md != exifData.end()) {
+ std::cout << *md;
+ rc = 1;
+ }
+ if (!label.empty()) std::cout << std::endl;
+ return rc;
+ } // Print::printTag
+
+ int Print::printInterpreted()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path_
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ Exiv2::ExifData::const_iterator md;
+ for (md = exifData.begin(); md != exifData.end(); ++md) {
+ std::cout << std::setw(44) << std::setfill(' ') << std::left
+ << md->key() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->count() << " "
+ << std::dec << *md
+ << std::endl;
+ }
+
+ return 0;
+ } // Print::printInterpreted
+
+ int Print::printValues()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path_
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ Exiv2::ExifData::const_iterator end = exifData.end();
+ Exiv2::ExifData::const_iterator md;
+ for (md = exifData.begin(); md != end; ++md) {
+ std::cout << "0x" << std::setw(4) << std::setfill('0') <<
std::right
+ << std::hex << md->tag() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->ifdName() << " "
+ << std::setw(27) << std::setfill(' ') << std::left
+ << md->tagName() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->count() << " "
+ << std::dec << md->value()
+ << std::endl;
+ }
+
+ return 0;
+ } // Print::printValues
+
+ int Print::printIptc()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::IptcData &iptcData = image->iptcData();
+ if (iptcData.empty()) {
+ std::cerr << path_
+ << ": No Iptc data found in the file\n";
+ return -3;
+ }
+ Exiv2::IptcData::const_iterator end = iptcData.end();
+ Exiv2::IptcData::const_iterator md;
+ for (md = iptcData.begin(); md != end; ++md) {
+ std::cout << std::setw(44) << std::setfill(' ') << std::left
+ << md->key() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->count() << " "
+ << std::dec << md->value()
+ << std::endl;
+ }
+
+ return 0;
+ } // Print::printIptc
+
+ int Print::printHexdump()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path_
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ Exiv2::ExifData::const_iterator md;
+ for (md = exifData.begin(); md != exifData.end(); ++md) {
+ std::cout << std::setw(4) << std::setfill(' ') << std::left
+ << md->ifdName() << " "
+ << "0x" << std::setw(4) << std::setfill('0') <<
std::right
+ << std::hex << md->tag() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->count() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->size() << " "
+ << std::setw(27) << std::setfill(' ') << std::left
+ << md->tagName() << std::endl;
+ Exiv2::DataBuf buf(md->size());
+ md->copy(buf.pData_, exifData.byteOrder());
+ Exiv2::hexdump(std::cout, buf.pData_, buf.size_);
+ }
+
+ return 0;
+ } // Print::printHexdump
+
+ int Print::printComment()
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ if (Params::instance().verbose_) {
+ std::cout << "Jpeg comment: ";
+ }
+ std::cout << image->comment() << std::endl;
+ return 0;
+ } // Print::printComment
+
+ Print::AutoPtr Print::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Print* Print::clone_() const
+ {
+ return new Print(*this);
+ }
+
+ int Rename::run(const std::string& path)
+ try {
+ if (!Exiv2::fileExists(path, true)) {
+ std::cerr << path
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
+ Exiv2::ExifData::iterator md = exifData.findKey(key);
+ if (md == exifData.end()) {
+ std::cerr << "Metadatum with key `" << key << "' "
+ << "not found in the file " << path << "\n";
+ return 1;
+ }
+ std::string v = md->toString();
+ if (v.length() == 0 || v[0] == ' ') {
+ std::cerr << "Image file creation timestamp not set in the file "
+ << path << "\n";
+ return 1;
+ }
+ // Assemble the new filename from the timestamp
+ struct tm tm;
+ if (str2Tm(v, &tm) != 0) {
+ std::cerr << "Failed to parse timestamp `" << v
+ << "' in the file " << path << "\n";
+ return 1;
+ }
+ const size_t max = 1024;
+ char basename[max];
+ memset(basename, 0x0, max);
+ if (strftime(basename, max, Params::instance().format_.c_str(), &tm)
== 0) {
+ std::cerr << "Filename format yields empty filename for the file "
+ << path << "\n";
+ return 1;
+ }
+ std::string newPath
+ = Util::dirname(path) + EXV_SEPERATOR_STR + basename +
Util::suffix(path);
+ if ( Util::dirname(newPath) == Util::dirname(path)
+ && Util::basename(newPath) == Util::basename(path)) {
+ if (Params::instance().verbose_) {
+ std::cout << "This file already has the correct name" <<
std::endl;
+ }
+ return 0;
+ }
+
+ bool go = true;
+ int seq = 1;
+ std::string s;
+ Params::FileExistsPolicy fileExistsPolicy
+ = Params::instance().fileExistsPolicy_;
+ while (go) {
+ if (Exiv2::fileExists(newPath)) {
+ switch (fileExistsPolicy) {
+ case Params::overwritePolicy:
+ go = false;
+ break;
+ case Params::renamePolicy:
+ newPath = Util::dirname(path)
+ + EXV_SEPERATOR_STR + basename
+ + "_" + Exiv2::toString(seq++)
+ + Util::suffix(path);
+ break;
+ case Params::askPolicy:
+ std::cout << Params::instance().progname()
+ << ": File `" << newPath
+ << "' exists. [O]verwrite, [r]ename or [s]kip? ";
+ std::cin >> s;
+ switch (s[0]) {
+ case 'o':
+ case 'O':
+ go = false;
+ break;
+ case 'r':
+ case 'R':
+ fileExistsPolicy = Params::renamePolicy;
+ newPath = Util::dirname(path)
+ + EXV_SEPERATOR_STR + basename
+ + "_" + Exiv2::toString(seq++)
+ + Util::suffix(path);
+ break;
+ default: // skip
+ return 0;
+ break;
+ }
+ }
+ }
+ else {
+ go = false;
+ }
+ }
+
+ if (Params::instance().verbose_) {
+ std::cout << "Renaming file to " << newPath << std::endl;
+ }
+
+ // Workaround for MinGW rename which does not overwrite existing files
+ remove(newPath.c_str());
+ if (::rename(path.c_str(), newPath.c_str()) == -1) {
+ std::cerr << Params::instance().progname()
+ << ": Failed to rename "
+ << path << " to " << newPath << ": "
+ << Exiv2::strError() << "\n";
+ return 1;
+ }
+ return 0;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in rename action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Rename::run
+
+ Rename::AutoPtr Rename::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Rename* Rename::clone_() const
+ {
+ return new Rename(*this);
+ }
+
+ int Erase::run(const std::string& path)
+ try {
+ path_ = path;
+
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ // Thumbnail must be before Exif
+ int rc = 0;
+ if (Params::instance().target_ & Params::ctThumb) {
+ rc = eraseThumbnail(image.get());
+ }
+ if (0 == rc && Params::instance().target_ & Params::ctExif) {
+ rc = eraseExifData(image.get());
+ }
+ if (0 == rc && Params::instance().target_ & Params::ctIptc) {
+ rc = eraseIptcData(image.get());
+ }
+ if (0 == rc && Params::instance().target_ & Params::ctComment) {
+ rc = eraseComment(image.get());
+ }
+ if (0 == rc) {
+ image->writeMetadata();
+ }
+
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in erase action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Erase::run
+
+ int Erase::eraseThumbnail(Exiv2::Image* image) const
+ {
+ Exiv2::ExifData &exifData = image->exifData();
+ std::string thumbExt = exifData.thumbnailExtension();
+ if (thumbExt.empty()) {
+ return 0;
+ }
+ long delta = exifData.eraseThumbnail();
+ if (Params::instance().verbose_) {
+ std::cout << "Erasing " << delta
+ << " Bytes of thumbnail data" << std::endl;
+ }
+ return 0;
+ }
+
+ int Erase::eraseExifData(Exiv2::Image* image) const
+ {
+ if (Params::instance().verbose_ && image->exifData().count() > 0) {
+ std::cout << "Erasing Exif data from the file" << std::endl;
+ }
+ image->clearExifData();
+ return 0;
+ }
+
+ int Erase::eraseIptcData(Exiv2::Image* image) const
+ {
+ if (Params::instance().verbose_ && image->iptcData().count() > 0) {
+ std::cout << "Erasing Iptc data from the file" << std::endl;
+ }
+ image->clearIptcData();
+ return 0;
+ }
+
+ int Erase::eraseComment(Exiv2::Image* image) const
+ {
+ if (Params::instance().verbose_ && image->comment().size() > 0) {
+ std::cout << "Erasing Jpeg comment from the file" << std::endl;
+ }
+ image->clearComment();
+ return 0;
+ }
+
+ Erase::AutoPtr Erase::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Erase* Erase::clone_() const
+ {
+ return new Erase(*this);
+ }
+
+ int Extract::run(const std::string& path)
+ try {
+ path_ = path;
+ int rc = 0;
+ if (Params::instance().target_ & Params::ctThumb) {
+ rc = writeThumbnail();
+ }
+ if (Params::instance().target_ & ~Params::ctThumb) {
+ std::string directory = Params::instance().directory_;
+ if (directory.empty()) directory = Util::dirname(path_);
+ std::string exvPath = directory + EXV_SEPERATOR_STR
+ + Util::basename(path_, true) + ".exv";
+ if (!Params::instance().force_ && Exiv2::fileExists(exvPath)) {
+ std::cout << Params::instance().progname()
+ << ": Overwrite `" << exvPath << "'? ";
+ std::string s;
+ std::cin >> s;
+ if (s[0] != 'y' && s[0] != 'Y') return 0;
+ }
+ rc = metacopy(path_, exvPath, false);
+ }
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in extract action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Extract::run
+
+ int Extract::writeThumbnail() const
+ {
+ if (!Exiv2::fileExists(path_, true)) {
+ std::cerr << path_
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path_
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+
+ std::string directory = Params::instance().directory_;
+ if (directory.empty()) directory = Util::dirname(path_);
+ std::string thumb = directory + EXV_SEPERATOR_STR
+ + Util::basename(path_, true) + "-thumb";
+ std::string thumbExt = exifData.thumbnailExtension();
+ int rc = 0;
+ if (thumbExt.empty()) {
+ std::cerr << path_ << ": Image does not contain an Exif
thumbnail\n";
+ }
+ else {
+ if (Params::instance().verbose_) {
+ Exiv2::DataBuf buf = exifData.copyThumbnail();
+ std::cout << "Writing "
+ << exifData.thumbnailFormat() << " thumbnail ("
+ << buf.size_ << " Bytes) to file "
+ << thumb << thumbExt << std::endl;
+ }
+ if (!Params::instance().force_ && Exiv2::fileExists(thumb +
thumbExt)) {
+ std::cout << Params::instance().progname()
+ << ": Overwrite `" << thumb + thumbExt << "'? ";
+ std::string s;
+ std::cin >> s;
+ if (s[0] != 'y' && s[0] != 'Y') return 0;
+ }
+ rc = exifData.writeThumbnail(thumb);
+ if (rc) {
+ std::cerr << thumb << ": Exif data doesn't contain a
thumbnail\n";
+ }
+ }
+ return rc;
+ } // Extract::writeThumbnail
+
+ Extract::AutoPtr Extract::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Extract* Extract::clone_() const
+ {
+ return new Extract(*this);
+ }
+
+ int Insert::run(const std::string& path)
+ try {
+ if (!Exiv2::fileExists(path, true)) {
+ std::cerr << path
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ int rc = 0;
+ if (Params::instance().target_ & Params::ctThumb) {
+ rc = insertThumbnail(path);
+ }
+ if ( rc == 0
+ && Params::instance().target_ & Params::ctExif
+ || Params::instance().target_ & Params::ctIptc
+ || Params::instance().target_ & Params::ctComment) {
+ std::string directory = Params::instance().directory_;
+ if (directory.empty()) directory = Util::dirname(path);
+ std::string exvPath = directory + EXV_SEPERATOR_STR
+ + Util::basename(path, true) + ".exv";
+ rc = metacopy(exvPath, path, true);
+ }
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in insert action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Insert::run
+
+ int Insert::insertThumbnail(const std::string& path) const
+ {
+ std::string directory = Params::instance().directory_;
+ if (directory.empty()) directory = Util::dirname(path);
+ std::string thumbPath = directory + EXV_SEPERATOR_STR
+ + Util::basename(path, true) + "-thumb.jpg";
+ if (!Exiv2::fileExists(thumbPath, true)) {
+ std::cerr << thumbPath
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ if (!Exiv2::fileExists(path, true)) {
+ std::cerr << path
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ exifData.setJpegThumbnail(thumbPath);
+ image->writeMetadata();
+
+ return 0;
+ } // Insert::insertThumbnail
+
+ Insert::AutoPtr Insert::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Insert* Insert::clone_() const
+ {
+ return new Insert(*this);
+ }
+
+ int Modify::run(const std::string& path)
+ try {
+ if (!Exiv2::fileExists(path, true)) {
+ std::cerr << path
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ image_ = Exiv2::ImageFactory::open(path);
+ assert(image_.get() != 0);
+ image_->readMetadata();
+
+ // loop through command table and apply each command
+ ModifyCmds& modifyCmds = Params::instance().modifyCmds_;
+ ModifyCmds::const_iterator i = modifyCmds.begin();
+ ModifyCmds::const_iterator end = modifyCmds.end();
+ for (; i != end; ++i) {
+ switch (i->cmdId_) {
+ case add:
+ addMetadatum(*i);
+ break;
+ case set:
+ setMetadatum(*i);
+ break;
+ case del:
+ delMetadatum(*i);
+ break;
+ default:
+ // Todo: complain
+ break;
+ }
+ }
+
+ // Save both exif and iptc metadata
+ image_->writeMetadata();
+
+ return 0;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in modify action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Modify::run
+
+ void Modify::addMetadatum(const ModifyCmd& modifyCmd)
+ {
+ if (Params::instance().verbose_) {
+ std::cout << "Add " << modifyCmd.key_ << " \""
+ << modifyCmd.value_ << "\" ("
+ << Exiv2::TypeInfo::typeName(modifyCmd.typeId_)
+ << ")" << std::endl;
+ }
+ Exiv2::Value::AutoPtr value = Exiv2::Value::create(modifyCmd.typeId_);
+ value->read(modifyCmd.value_);
+ if (modifyCmd.metadataId_ == exif) {
+ image_->exifData().add(Exiv2::ExifKey(modifyCmd.key_),
value.get());
+ }
+ if (modifyCmd.metadataId_ == iptc) {
+ image_->iptcData().add(Exiv2::IptcKey(modifyCmd.key_),
value.get());
+ }
+ }
+
+ void Modify::setMetadatum(const ModifyCmd& modifyCmd)
+ {
+ if (Params::instance().verbose_) {
+ std::cout << "Set " << modifyCmd.key_ << " \""
+ << modifyCmd.value_ << "\" ("
+ << Exiv2::TypeInfo::typeName(modifyCmd.typeId_)
+ << ")" << std::endl;
+ }
+
+ Exiv2::ExifData &exifData = image_->exifData();
+ Exiv2::IptcData &iptcData = image_->iptcData();
+ Exiv2::Metadatum* metadatum = 0;
+ if (modifyCmd.metadataId_ == exif) {
+ metadatum = &exifData[modifyCmd.key_];
+ }
+ if (modifyCmd.metadataId_ == iptc) {
+ metadatum = &iptcData[modifyCmd.key_];
+ }
+ assert(metadatum);
+ Exiv2::Value::AutoPtr value = metadatum->getValue();
+ // If a type was explicitly requested, use it; else
+ // use the current type of the metadatum, if any;
+ // or the default type
+ if (modifyCmd.explicitType_ || value.get() == 0) {
+ value = Exiv2::Value::create(modifyCmd.typeId_);
+ }
+ value->read(modifyCmd.value_);
+ metadatum->setValue(value.get());
+ }
+
+ void Modify::delMetadatum(const ModifyCmd& modifyCmd)
+ {
+ if (Params::instance().verbose_) {
+ std::cout << "Del " << modifyCmd.key_ << std::endl;
+ }
+
+ Exiv2::ExifData &exifData = image_->exifData();
+ Exiv2::IptcData &iptcData = image_->iptcData();
+ if (modifyCmd.metadataId_ == exif) {
+ Exiv2::ExifData::iterator pos =
+ exifData.findKey(Exiv2::ExifKey(modifyCmd.key_));
+ if (pos != exifData.end()) exifData.erase(pos);
+ }
+ if (modifyCmd.metadataId_ == iptc) {
+ Exiv2::IptcData::iterator pos =
+ iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_));
+ if (pos != iptcData.end()) iptcData.erase(pos);
+ }
+ }
+
+ Modify::AutoPtr Modify::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Modify* Modify::clone_() const
+ {
+ return new Modify(*this);
+ }
+
+ int Adjust::run(const std::string& path)
+ try {
+ adjustment_ = Params::instance().adjustment_;
+
+ if (!Exiv2::fileExists(path, true)) {
+ std::cerr << path
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
+ assert(image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::cerr << path
+ << ": No Exif data found in the file\n";
+ return -3;
+ }
+ int 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;
+ image->writeMetadata();
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e)
+ {
+ std::cerr << "Exiv2 exception in adjust action for file " << path
+ << ":\n" << e << "\n";
+ return 1;
+ } // Adjust::run
+
+ Adjust::AutoPtr Adjust::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Adjust* Adjust::clone_() const
+ {
+ return new Adjust(*this);
+ }
+
+ int Adjust::adjustDateTime(Exiv2::ExifData& exifData,
+ const std::string& key,
+ const std::string& path) const
+ {
+ 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;
+ }
+ std::string timeStr = md->toString();
+ if (timeStr == "" || timeStr[0] == ' ') {
+ std::cerr << path << ": Timestamp of metadatum with key `"
+ << ek << "' not set\n";
+ return 1;
+ }
+ time_t time = str2Time(timeStr);
+ if (time == (time_t)-1) {
+ std::cerr << path << ": Failed to parse or convert timestamp `"
+ << timeStr << "'\n";
+ return 1;
+ }
+ if (Params::instance().verbose_) {
+ std::cout << "Adjusting `" << ek << "' by"
+ << (adjustment_ < 0 ? " " : " +")
+ << adjustment_ << " s to ";
+ }
+ time += adjustment_;
+ timeStr = time2Str(time);
+ if (Params::instance().verbose_) {
+ std::cout << timeStr << std::endl;
+ }
+ md->setValue(timeStr);
+ return 0;
+ } // Adjust::adjustDateTime
+
+} // namespace Action
+
+//
*****************************************************************************
+// local definitions
+namespace {
+
+ int str2Tm(const std::string& timeStr, struct tm* tm)
+ {
+ if (timeStr.length() == 0 || timeStr[0] == ' ') return 1;
+ if (timeStr.length() < 19) return 2;
+ if ( timeStr[4] != ':' || timeStr[7] != ':' || timeStr[10] != ' '
+ || timeStr[13] != ':' || timeStr[16] != ':') return 3;
+ if (0 == tm) return 4;
+ memset(tm, 0x0, sizeof(struct tm));
+
+ long tmp;
+ if (!Util::strtol(timeStr.substr(0,4).c_str(), tmp)) return 5;
+ tm->tm_year = tmp - 1900;
+ if (!Util::strtol(timeStr.substr(5,2).c_str(), tmp)) return 6;
+ tm->tm_mon = tmp - 1;
+ if (!Util::strtol(timeStr.substr(8,2).c_str(), tmp)) return 7;
+ tm->tm_mday = tmp;
+ if (!Util::strtol(timeStr.substr(11,2).c_str(), tmp)) return 8;
+ tm->tm_hour = tmp;
+ if (!Util::strtol(timeStr.substr(14,2).c_str(), tmp)) return 9;
+ tm->tm_min = tmp;
+ if (!Util::strtol(timeStr.substr(17,2).c_str(), tmp)) return 10;
+ tm->tm_sec = tmp;
+
+ return 0;
+ } // str2Tm
+
+ time_t str2Time(const std::string& timeStr)
+ {
+ struct tm tm;
+ if (str2Tm(timeStr, &tm) != 0) return (time_t)-1;
+ time_t t = timegm(&tm);
+ return t;
+ }
+
+ std::string time2Str(time_t time)
+ {
+ struct tm* tm = gmtime(&time);
+ if (0 == tm) return "";
+
+ std::ostringstream os;
+ os << std::setfill('0')
+ << tm->tm_year + 1900 << ":"
+ << std::setw(2) << tm->tm_mon + 1 << ":"
+ << std::setw(2) << tm->tm_mday << " "
+ << std::setw(2) << tm->tm_hour << ":"
+ << std::setw(2) << tm->tm_min << ":"
+ << std::setw(2) << tm->tm_sec;
+
+ return os.str();
+ } // time2Str
+
+ int metacopy(const std::string& source,
+ const std::string& target,
+ bool preserve)
+ {
+ if (!Exiv2::fileExists(source, true)) {
+ std::cerr << source
+ << ": Failed to open the file\n";
+ return -1;
+ }
+ Exiv2::Image::AutoPtr sourceImage = Exiv2::ImageFactory::open(source);
+ assert(sourceImage.get() != 0);
+ sourceImage->readMetadata();
+
+ Exiv2::Image::AutoPtr targetImage;
+ if (Exiv2::fileExists(target)) {
+ targetImage = Exiv2::ImageFactory::open(target);
+ assert(targetImage.get() != 0);
+ if (preserve) targetImage->readMetadata();
+ }
+ else {
+ targetImage
+ = Exiv2::ImageFactory::create(Exiv2::Image::exv, target);
+ assert(targetImage.get() != 0);
+ }
+ if ( Params::instance().target_ & Params::ctExif
+ && !sourceImage->exifData().empty()) {
+ if (Params::instance().verbose_) {
+ std::cout << "Writing Exif data from " << source
+ << " to " << target << std::endl;
+ }
+ targetImage->setExifData(sourceImage->exifData());
+ }
+ if ( Params::instance().target_ & Params::ctIptc
+ && !sourceImage->iptcData().empty()) {
+ if (Params::instance().verbose_) {
+ std::cout << "Writing Iptc data from " << source
+ << " to " << target << std::endl;
+ }
+ targetImage->setIptcData(sourceImage->iptcData());
+ }
+ if ( Params::instance().target_ & Params::ctComment
+ && !sourceImage->comment().empty()) {
+ if (Params::instance().verbose_) {
+ std::cout << "Writing Jpeg comment from " << source
+ << " to " << target << std::endl;
+ }
+ targetImage->setComment(sourceImage->comment());
+ }
+ try {
+ targetImage->writeMetadata();
+ }
+ catch (const Exiv2::AnyError& e) {
+ std::cerr << target <<
+ ": Could not write metadata to file: " << e << "\n";
+ }
+
+ return 0;
+ } // metacopy
+}
Added: Extractor/src/plugins/exiv2/actions.hpp
===================================================================
--- Extractor/src/plugins/exiv2/actions.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/actions.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,328 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file actions.hpp
+ @brief Implements base class Task, TaskFactory and the various supported
+ actions (derived from Task).
+ @version $Rev: 575 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 11-Dec-03, ahu: created
+ */
+#ifndef ACTIONS_HPP_
+#define ACTIONS_HPP_
+
+//
*****************************************************************************
+// included header files
+
+// + standard includes
+#include <string>
+#include <map>
+
+#include "exiv2.hpp"
+#include "image.hpp"
+#include "exif.hpp"
+#include "iptc.hpp"
+
+//
*****************************************************************************
+// class declarations
+
+namespace Exiv2 {
+ class ExifData;
+ class Image;
+}
+
+//
*****************************************************************************
+// namespace extensions
+/*!
+ @brief Contains all action classes (task subclasses).
+ */
+namespace Action {
+
+ //! Enumerates all tasks
+ enum TaskType { none, adjust, print, rename, erase, extract, insert,
modify };
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Abstract base class for all concrete actions.
+
+ Task provides a simple interface that actions must implement and a few
+ commonly used helpers.
+ */
+ class Task {
+ public:
+ //! Shortcut for an auto pointer.
+ typedef std::auto_ptr<Task> AutoPtr;
+ //! Virtual destructor.
+ virtual ~Task() {}
+ //! Virtual copy construction.
+ AutoPtr clone() const;
+ /*!
+ @brief Application interface to perform a task.
+
+ @param path Path of the file to process.
+ @return 0 if successful.
+ */
+ virtual int run(const std::string& path) =0;
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual Task* clone_() const =0;
+
+ }; // class Task
+
+ /*!
+ @brief Task factory.
+
+ Creates an instance of the task of the requested type. The factory is
+ implemented as a singleton, which can be accessed only through the static
+ member function instance().
+ */
+ class TaskFactory {
+ public:
+ /*!
+ @brief Get access to the task factory.
+
+ Clients access the task factory exclusively through
+ this method.
+ */
+ static TaskFactory& instance();
+
+ /*!
+ @brief Create a task.
+
+ @param type Identifies the type of task to create.
+ @return An auto pointer that owns a task of the requested type. If
+ the task type is not supported, the pointer is 0.
+ @remark The caller of the function should check the content of the
+ returned auto pointer and take appropriate action (e.g.,
throw
+ an exception) if it is 0.
+ */
+ Task::AutoPtr create(TaskType type);
+
+ /*!
+ @brief Register a task prototype together with its type.
+
+ The task factory creates new tasks of a given type by cloning its
+ associated prototype. Additional tasks can be registered. If called
+ for a type which already exists in the list, the corresponding
+ prototype is replaced.
+
+ @param type Task type.
+ @param task Pointer to the prototype. Ownership is transfered to the
+ task factory. That's what the auto pointer indicates.
+ */
+ void registerTask(TaskType type, Task::AutoPtr task);
+
+ private:
+ //! Prevent construction other than through instance().
+ TaskFactory();
+ //! Prevent copy construction: not implemented.
+ TaskFactory(const TaskFactory& rhs);
+
+ //! Pointer to the one and only instance of this class.
+ static TaskFactory* instance_;
+ //! Type used to store Task prototype classes
+ typedef std::map<TaskType, Task*> Registry;
+ //! List of task types and corresponding prototypes.
+ Registry registry_;
+
+ }; // class TaskFactory
+
+ //! %Print the Exif (or other metadata) of a file to stdout
+ class Print : public Task {
+ public:
+ virtual ~Print() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Print> AutoPtr;
+ AutoPtr clone() const;
+
+ //! Print the Jpeg comment
+ int printComment();
+ //! Print uninterpreted Iptc information
+ int printIptc();
+ //! Print Exif summary information
+ int printSummary();
+ //! Print the interpreted value for each Exif tag
+ int printInterpreted();
+ //! Print uninterpreted Exif information
+ int printValues();
+ //! Print Exif information in hexdump format
+ int printHexdump();
+ /*!
+ @brief Print one summary line with a label (if provided) and
requested
+ data. A line break is printed only if a label is provided.
+ @return 1 if a line was written, 0 if the key was not found.
+ */
+ int printTag(const Exiv2::ExifData& exifData,
+ const std::string& key,
+ const std::string& label ="") const;
+
+ private:
+ virtual Print* clone_() const;
+
+ std::string path_;
+ int align_; // for the alignment of the summary output
+ }; // class Print
+
+ /*!
+ @brief %Rename a file to its metadate creation timestamp,
+ in the specified format.
+ */
+ class Rename : public Task {
+ public:
+ virtual ~Rename() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Rename> AutoPtr;
+ AutoPtr clone() const;
+
+ private:
+ virtual Rename* clone_() const;
+ }; // class Rename
+
+ //! %Adjust the Exif (or other metadata) timestamps
+ class Adjust : public Task {
+ public:
+ virtual ~Adjust() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Adjust> AutoPtr;
+ AutoPtr clone() const;
+
+ private:
+ virtual Adjust* clone_() const;
+ int adjustDateTime(Exiv2::ExifData& exifData,
+ const std::string& key,
+ const std::string& path) const;
+
+ long adjustment_;
+ }; // class Adjust
+
+ /*!
+ @brief %Erase the entire exif data or only the thumbnail section.
+ */
+ class Erase : public Task {
+ public:
+ virtual ~Erase() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Erase> AutoPtr;
+ AutoPtr clone() const;
+
+ /*!
+ @brief Delete the thumbnail image, incl IFD1 metadata from the file.
+ */
+ int eraseThumbnail(Exiv2::Image* image) const;
+ /*!
+ @brief Erase the complete Exif data block from the file.
+ */
+ int eraseExifData(Exiv2::Image* image) const;
+ /*!
+ @brief Erase all Iptc data from the file.
+ */
+ int eraseIptcData(Exiv2::Image* image) const;
+ /*!
+ @brief Erase Jpeg comment from the file.
+ */
+ int eraseComment(Exiv2::Image* image) const;
+
+ private:
+ virtual Erase* clone_() const;
+ std::string path_;
+
+ }; // class Erase
+
+ /*!
+ @brief %Extract the entire exif data or only the thumbnail section.
+ */
+ class Extract : public Task {
+ public:
+ virtual ~Extract() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Extract> AutoPtr;
+ AutoPtr clone() const;
+
+ /*!
+ @brief Write the thumbnail image to a file. The filename is composed
by
+ removing the suffix from the image filename and appending
+ "-thumb" and the appropriate suffix (".jpg" or ".tif"),
depending
+ on the format of the Exif thumbnail image.
+ */
+ int writeThumbnail() const;
+
+ private:
+ virtual Extract* clone_() const;
+ std::string path_;
+
+ }; // class Extract
+
+ /*!
+ @brief %Insert the Exif data from corresponding *.exv files.
+ */
+ class Insert : public Task {
+ public:
+ virtual ~Insert() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Insert> AutoPtr;
+ AutoPtr clone() const;
+
+ /*!
+ @brief Insert a Jpeg thumbnail image from a file into file \em path.
+ The filename of the thumbanail is expected to be the image
+ filename (\em path) minus its suffix plus "-thumb.jpg".
+ */
+ int insertThumbnail(const std::string& path) const;
+
+ private:
+ virtual Insert* clone_() const;
+
+ }; // class Insert
+
+ /*!
+ @brief %Modify the Exif data according to the commands in the
+ modification table.
+ */
+ class Modify : public Task {
+ public:
+ virtual ~Modify() {}
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Modify> AutoPtr;
+ AutoPtr clone() const;
+ Modify() {}
+
+ private:
+ virtual Modify* clone_() const;
+ //! Copy contructor needed because of AutoPtr memeber
+ Modify(const Modify& src) {}
+
+ //! Add a metadatum according to \em modifyCmd
+ void addMetadatum(const ModifyCmd& modifyCmd);
+ //! Set a metadatum according to \em modifyCmd
+ void setMetadatum(const ModifyCmd& modifyCmd);
+ //! Delete a metadatum according to \em modifyCmd
+ void delMetadatum(const ModifyCmd& modifyCmd);
+
+ Exiv2::Image::AutoPtr image_; //!< Image to modify
+ }; // class Modify
+
+} // namespace Action
+
+#endif // #ifndef ACTIONS_HPP_
Added: Extractor/src/plugins/exiv2/addmoddel.cpp
===================================================================
--- Extractor/src/plugins/exiv2/addmoddel.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/addmoddel.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,109 @@
+// ***************************************************************** -*- C++
-*-
+// addmoddel.cpp, $Rev: 560 $
+// Sample program showing how to add, modify and delete Exif metadata.
+
+#include "image.hpp"
+#include "exif.hpp"
+#include <iostream>
+#include <iomanip>
+#include <cassert>
+
+int main(int argc, char* const argv[])
+try {
+ if (argc != 2) {
+ std::cout << "Usage: " << argv[0] << " file\n";
+ return 1;
+ }
+ std::string file(argv[1]);
+
+ // Container for exif metadata. This is an example of creating
+ // exif metadata from scratch. If you want to add, modify, delete
+ // metadata that exists in an image, start with ImageFactory::open
+ Exiv2::ExifData exifData;
+
+ //
*************************************************************************
+ // Add to the Exif data
+
+ // This is the quickest way to add (simple) Exif data. If a metadatum for
+ // a given key already exists, its value is overwritten. Otherwise a new
+ // tag is added.
+ exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue
+ exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue
+ exifData["Exif.Image.XResolution"] = int32_t(-2); // LongValue
+ exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); //
RationalValue
+ std::cout << "Added a few tags the quick way.\n";
+
+ // Create a ASCII string value (note the use of create)
+ Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
+ // 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
+ Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
+ exifData.add(key, v.get());
+ std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n";
+
+ // Now create a more interesting value (without using the create method)
+ Exiv2::URationalValue::AutoPtr rv(new Exiv2::URationalValue);
+ // Set two rational components from a string
+ rv->read("1/2 1/3");
+ // Add more elements through the extended interface of rational value
+ 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 = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
+ exifData.add(key, rv.get());
+ std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n";
+
+ //
*************************************************************************
+ // Modify Exif data
+
+ // Since we know that the metadatum exists (or we don't mind creating a new
+ // tag if it doesn't), we can simply do this:
+ Exiv2::Exifdatum& tag = exifData["Exif.Photo.DateTimeOriginal"];
+ std::string date = tag.toString();
+ date.replace(0, 4, "2000");
+ tag.setValue(date);
+ std::cout << "Modified key \"" << key
+ << "\", new value \"" << tag.value() << "\"\n";
+
+ // Alternatively, we can use findKey()
+ key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
+ Exiv2::ExifData::iterator pos = exifData.findKey(key);
+ if (pos == exifData.end()) throw Exiv2::Error(1, "Key not found");
+ // Get a pointer to a copy of the value
+ v = pos->getValue();
+ // Downcast the Value pointer to its actual type
+ Exiv2::URationalValue* prv =
dynamic_cast<Exiv2::URationalValue*>(v.release());
+ if (prv == 0) throw Exiv2::Error(1, "Downcast failed");
+ rv = Exiv2::URationalValue::AutoPtr(prv);
+ // Modify the value directly through the interface of URationalValue
+ rv->value_[2] = std::make_pair(88,77);
+ // Copy the modified value back to the metadatum
+ pos->setValue(rv.get());
+ std::cout << "Modified key \"" << key
+ << "\", new value \"" << pos->value() << "\"\n";
+
+ //
*************************************************************************
+ // Delete metadata from the Exif data container
+
+ // Delete the metadatum at iterator position pos
+ key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
+ pos = exifData.findKey(key);
+ if (pos == exifData.end()) throw Exiv2::Error(1, "Key not found");
+ exifData.erase(pos);
+ std::cout << "Deleted key \"" << key << "\"\n";
+
+ //
*************************************************************************
+ // Finally, write the remaining Exif data to the image file
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
+ assert(image.get() != 0);
+
+ image->setExifData(exifData);
+ image->writeMetadata();
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return -1;
+}
Added: Extractor/src/plugins/exiv2/basicio.cpp
===================================================================
--- Extractor/src/plugins/exiv2/basicio.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/basicio.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,500 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: basicio.cpp
+ Version: $Rev: 566 $
+ Author(s): Brad Schick (brad) <address@hidden>
+ History: 04-Dec-04, brad: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: basicio.cpp 566 2005-04-26 15:27:41Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "basicio.hpp"
+#include "futils.hpp"
+#include "types.hpp"
+#include "error.hpp"
+
+// + standard includes
+#include <string>
+#include <cassert>
+#include <cstdio> // for remove()
+#include <sys/types.h> // for stat()
+#include <sys/stat.h> // for stat()
+#ifdef EXV_HAVE_PROCESS_H
+# include <process.h>
+#endif
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // for getpid, stat
+#endif
+
+#if defined WIN32 && !defined __CYGWIN__
+# include <io.h>
+#endif
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ FileIo::FileIo(const std::string& path) :
+ path_(path), fp_(0), opMode_(opSeek)
+ {
+ }
+
+ FileIo::~FileIo()
+ {
+ close();
+ }
+
+ BasicIo::AutoPtr FileIo::temporary() const
+ {
+ BasicIo::AutoPtr basicIo;
+
+ struct stat buf;
+ int ret = stat(path_.c_str(), &buf);
+
+ // If file is > 1MB then use a file, otherwise use memory buffer
+ if (ret != 0 || buf.st_size > 1048576) {
+ pid_t pid = getpid();
+ std::string tmpname = path_ + toString(pid);
+ std::auto_ptr<FileIo> fileIo(new FileIo(tmpname));
+ if (fileIo->open("w+b") != 0) {
+ throw Error(10, path_, "w+b", strError());
+ }
+ basicIo = fileIo;
+ }
+ else {
+ basicIo.reset(new MemIo);
+ }
+
+ return basicIo;
+ }
+
+ int FileIo::switchMode(OpMode opMode)
+ {
+ assert(fp_ != 0);
+ if (opMode_ == opMode) return 0;
+ OpMode oldOpMode = opMode_;
+ opMode_ = opMode;
+
+ bool reopen = true;
+ std::string mode = "r+b";
+
+ switch(opMode) {
+ case opRead:
+ // Flush if current mode allows reading, else reopen (in mode "r+b"
+ // as in this case we know that we can write to the file)
+ if ( openMode_[0] == 'r'
+ || openMode_.substr(0, 2) == "w+"
+ || openMode_.substr(0, 2) == "a+") reopen = false;
+ break;
+ case opWrite:
+ // Flush if current mode allows writing, else reopen
+ if ( openMode_.substr(0, 2) == "r+"
+ || openMode_[0] == 'w'
+ || openMode_[0] == 'a') reopen = false;
+ break;
+ case opSeek:
+ reopen = false;
+ break;
+ }
+
+ if (!reopen) {
+ // Don't do anything when switching _from_ opSeek mode; we
+ // flush when switching _to_ opSeek.
+ if (oldOpMode == opSeek) return 0;
+
+ // Flush. On msvcrt fflush does not do the job
+ fseek(fp_, 0, SEEK_CUR);
+ return 0;
+ }
+
+ // Reopen the file
+ long offset = ftell(fp_);
+ if (offset == -1) return -1;
+ if (open(mode) != 0) return 1;
+ return fseek(fp_, offset, SEEK_SET);
+ }
+
+ long FileIo::write(const byte* data, long wcount)
+ {
+ assert(fp_ != 0);
+ if (switchMode(opWrite) != 0) return 0;
+ return (long)fwrite(data, 1, wcount, fp_);
+ }
+
+ long FileIo::write(BasicIo& src)
+ {
+ assert(fp_ != 0);
+ if (static_cast<BasicIo*>(this) == &src) return 0;
+ if (!src.isopen()) return 0;
+ if (switchMode(opWrite) != 0) return 0;
+
+ byte buf[4096];
+ long readCount = 0;
+ long writeCount = 0;
+ long writeTotal = 0;
+ while ((readCount = src.read(buf, sizeof(buf)))) {
+ writeTotal += writeCount = (long)fwrite(buf, 1, readCount, fp_);
+ if (writeCount != readCount) {
+ // try to reset back to where write stopped
+ src.seek(writeCount-readCount, BasicIo::cur);
+ break;
+ }
+ }
+
+ return writeTotal;
+ }
+
+ void FileIo::transfer(BasicIo& src)
+ {
+ const bool wasOpen = (fp_ != 0);
+ const std::string lastMode(openMode_);
+
+ FileIo *fileIo = dynamic_cast<FileIo*>(&src);
+ if (fileIo) {
+ // Optimization if this is another instance of FileIo
+ close();
+ fileIo->close();
+ // MSVCRT rename that does not overwrite existing files
+ if (remove(path_.c_str()) != 0) {
+ throw Error(2, path_, strError(), "::remove");
+ }
+ if (rename(fileIo->path_.c_str(), path_.c_str()) == -1) {
+ throw Error(17, fileIo->path_, path_, strError());
+ }
+ remove(fileIo->path_.c_str());
+ }
+ else{
+ // Generic handling, reopen both to reset to start
+ if (open("w+b") != 0) {
+ throw Error(10, path_, "w+b", strError());
+ }
+ if (src.open() != 0) {
+ throw Error(9, src.path(), strError());
+ }
+ write(src);
+ src.close();
+ }
+
+ if (wasOpen) {
+ if (open(lastMode) != 0) {
+ throw Error(10, path_, lastMode, strError());
+ }
+ }
+ else close();
+
+ if (error() || src.error()) throw Error(18, path_, strError());
+ }
+
+ int FileIo::putb(byte data)
+ {
+ assert(fp_ != 0);
+ if (switchMode(opWrite) != 0) return EOF;
+ return putc(data, fp_);
+ }
+
+ int FileIo::seek(long offset, Position pos)
+ {
+ assert(fp_ != 0);
+ int fileSeek;
+ if (pos == BasicIo::cur) {
+ fileSeek = SEEK_CUR;
+ }
+ else if (pos == BasicIo::beg) {
+ fileSeek = SEEK_SET;
+ }
+ else {
+ assert(pos == BasicIo::end);
+ fileSeek = SEEK_END;
+ }
+
+ if (switchMode(opSeek) != 0) return 1;
+ return fseek(fp_, offset, fileSeek);
+ }
+
+ long FileIo::tell() const
+ {
+ assert(fp_ != 0);
+ return ftell(fp_);
+ }
+
+
+ long FileIo::size() const
+ {
+ if (fp_ != 0) {
+ fflush(fp_);
+#if defined WIN32 && !defined __CYGWIN__
+ // This is required on msvcrt before stat after writing to a file
+ _commit(_fileno(fp_));
+#endif
+ }
+
+ struct stat buf;
+ int ret = stat(path_.c_str(), &buf);
+
+ if (ret != 0) return -1;
+ return buf.st_size;
+ }
+
+ int FileIo::open()
+ {
+ // Default open is in read-only binary mode
+ return open("rb");
+ }
+
+ int FileIo::open(const std::string& mode)
+ {
+ if (fp_ != 0) {
+ fclose(fp_);
+ }
+
+ openMode_ = mode;
+ opMode_ = opSeek;
+ fp_ = fopen(path_.c_str(), mode.c_str());
+ if (!fp_) return 1;
+ return 0;
+ }
+
+ bool FileIo::isopen() const
+ {
+ return fp_ != 0;
+ }
+
+ int FileIo::close()
+ {
+ if (fp_ != 0) {
+ fclose(fp_);
+ fp_= 0;
+ }
+ return 0;
+ }
+
+ DataBuf FileIo::read(long rcount)
+ {
+ assert(fp_ != 0);
+ DataBuf buf(rcount);
+ long readCount = read(buf.pData_, buf.size_);
+ buf.size_ = readCount;
+ return buf;
+ }
+
+ long FileIo::read(byte* buf, long rcount)
+ {
+ assert(fp_ != 0);
+ if (switchMode(opRead) != 0) return 0;
+ return (long)fread(buf, 1, rcount, fp_);
+ }
+
+ int FileIo::getb()
+ {
+ assert(fp_ != 0);
+ if (switchMode(opRead) != 0) return EOF;
+ return getc(fp_);
+ }
+
+ int FileIo::error() const
+ {
+ return fp_ != 0 ? ferror(fp_) : 0;
+ }
+
+ bool FileIo::eof() const
+ {
+ assert(fp_ != 0);
+ return feof(fp_) != 0;
+ }
+
+ std::string FileIo::path() const
+ {
+ return path_;
+ }
+
+ MemIo::MemIo(const byte* data, long size)
+ {
+ // If copying data is too slow it might be worth
+ // creating a readonly MemIo variant
+ data_.reserve(size);
+ data_.assign(data, data+size);
+ idx_ = 0;
+ }
+
+ BasicIo::AutoPtr MemIo::temporary() const
+ {
+ return BasicIo::AutoPtr(new MemIo);
+ }
+
+ void MemIo::checkSize(long wcount)
+ {
+ ByteVector::size_type need = wcount + idx_;
+ if (need > data_.size()) {
+ data_.resize(need);
+ }
+ }
+
+ long MemIo::write(const byte* data, long wcount)
+ {
+ checkSize(wcount);
+ // According to Josuttis 6.2.3 this is safe
+ memcpy(&data_[idx_], data, wcount);
+ idx_ += wcount;
+ return wcount;
+ }
+
+ void MemIo::transfer(BasicIo& src)
+ {
+ MemIo *memIo = dynamic_cast<MemIo*>(&src);
+ if (memIo) {
+ // Optimization if this is another instance of MemIo
+ data_.swap(memIo->data_);
+ idx_ = 0;
+ }
+ else{
+ // Generic reopen to reset position to start
+ data_.clear();
+ idx_ = 0;
+ if (src.open() != 0) {
+ throw Error(9, src.path(), strError());
+ }
+ write(src);
+ src.close();
+ }
+ if (error() || src.error()) throw Error(19, strError());
+ }
+
+ long MemIo::write(BasicIo& src)
+ {
+ if (static_cast<BasicIo*>(this)==&src) return 0;
+ if (!src.isopen()) return 0;
+
+ byte buf[4096];
+ long readCount = 0;
+ long writeTotal = 0;
+ while ((readCount = src.read(buf, sizeof(buf)))) {
+ write(buf, readCount);
+ writeTotal += readCount;
+ }
+
+ return writeTotal;
+ }
+
+ int MemIo::putb(byte data)
+ {
+ checkSize(1);
+ data_[idx_++] = data;
+ return data;
+ }
+
+ int MemIo::seek(long offset, Position pos)
+ {
+ ByteVector::size_type newIdx;
+
+ if (pos == BasicIo::cur ) {
+ newIdx = idx_ + offset;
+ }
+ else if (pos == BasicIo::beg) {
+ newIdx = offset;
+ }
+ else {
+ assert(pos == BasicIo::end);
+ newIdx = data_.size() + offset;
+ }
+
+ if (newIdx < 0 || newIdx > data_.size()) return 1;
+ idx_ = newIdx;
+ return 0;
+ }
+
+ long MemIo::tell() const
+ {
+ return (long)idx_;
+ }
+
+ long MemIo::size() const
+ {
+ return (long)data_.size();
+ }
+
+ int MemIo::open()
+ {
+ idx_ = 0;
+ return 0;
+ }
+
+ bool MemIo::isopen() const
+ {
+ return true;
+ }
+
+ int MemIo::close()
+ {
+ return 0;
+ }
+
+ DataBuf MemIo::read(long rcount)
+ {
+ DataBuf buf(rcount);
+ long readCount = read(buf.pData_, buf.size_);
+ buf.size_ = readCount;
+ return buf;
+ }
+
+ long MemIo::read(byte* buf, long rcount)
+ {
+ long avail = (long)(data_.size() - idx_);
+ long allow = std::min(rcount, avail);
+
+ // According to Josuttis 6.2.3 this is safe
+ memcpy(buf, &data_[idx_], allow);
+ idx_ += allow;
+ return allow;
+ }
+
+ int MemIo::getb()
+ {
+ if (idx_ == data_.size())
+ return EOF;
+ return data_[idx_++];
+ }
+
+ int MemIo::error() const
+ {
+ return 0;
+ }
+
+ bool MemIo::eof() const
+ {
+ return idx_ == data_.size();
+ }
+
+ std::string MemIo::path() const
+ {
+ return "MemIo";
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/basicio.hpp
===================================================================
--- Extractor/src/plugins/exiv2/basicio.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/basicio.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,642 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file basicio.hpp
+ @brief Simple binary IO abstraction
+ @version $Rev: 565 $
+ @author Brad Schick (brad)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 04-Dec-04, brad: created
+ */
+#ifndef BASICIO_HPP_
+#define BASICIO_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <cstdio>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief An interface for simple binary IO.
+
+ Designed to have semantics and names similar to those of C style FILE*
+ operations. Subclasses should all behave the same so that they can be
+ interchanged.
+ */
+ class BasicIo
+ {
+ public:
+ //! BasicIo auto_ptr type
+ typedef std::auto_ptr<BasicIo> AutoPtr;
+
+ //! Seek starting positions
+ enum Position { beg, cur, end };
+
+ //! @name Creators
+ //@{
+ //! Destructor
+ virtual ~BasicIo() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Open the IO source using the default access mode. The
+ default mode should allow for reading and writing.
+
+ This method can also be used to "reopen" an IO source which will
+ flush any unwritten data and reset the IO position to the start.
+ Subclasses may provide custom methods to allow for
+ opening IO sources differently.
+
+ @return 0 if successful;<BR>
+ Nonzero if failure.
+ */
+ virtual int open() = 0;
+ /*!
+ @brief Close the IO source. After closing a BasicIo instance can not
+ be read or written. Closing flushes any unwritten data. It is
+ safe to call close on a closed instance.
+ @return 0 if successful;<BR>
+ Nonzero if failure.
+ */
+ virtual int close() = 0;
+ /*!
+ @brief Write data to the IO source. Current IO position is advanced
+ by the number of bytes written.
+ @param data Pointer to data. Data must be at least \em wcount
+ bytes long
+ @param wcount Number of bytes to be written.
+ @return Number of bytes written to IO source successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(const byte* data, long wcount) = 0;
+ /*!
+ @brief Write data that is read from another BasicIo instance to
+ the IO source. Current IO position is advanced by the number
+ of bytes written.
+ @param src Reference to another BasicIo instance. Reading start
+ at the source's current IO position
+ @return Number of bytes written to IO source successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(BasicIo& src) = 0;
+ /*!
+ @brief Write one byte to the IO source. Current IO position is
+ advanced by one byte.
+ @param data The single byte to be written.
+ @return The value of the byte written if successful;<BR>
+ EOF if failure;
+ */
+ virtual int putb(byte data) = 0;
+ /*!
+ @brief Read data from the IO source. Reading starts at the current
+ IO position and the position is advanced by the number of bytes
+ read.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return DataBuf instance containing the bytes read. Use the
+ DataBuf::size_ member to find the number of bytes read.
+ DataBuf::size_ will be 0 on failure.
+ */
+ virtual DataBuf read(long rcount) = 0;
+ /*!
+ @brief Read data from the IO source. Reading starts at the current
+ IO position and the position is advanced by the number of bytes
+ read.
+ @param buf Pointer to a block of memory into which the read data
+ is stored. The memory block must be at least \em rcount bytes
+ long.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return Number of bytes read from IO source successfully;<BR>
+ 0 if failure;
+ */
+ virtual long read(byte *buf, long rcount) = 0;
+ /*!
+ @brief Read one byte from the IO source. Current IO position is
+ advanced by one byte.
+ @return The byte read from the IO source if successful;<BR>
+ EOF if failure;
+ */
+ virtual int getb() = 0;
+ /*!
+ @brief Remove all data from this object's IO source and then transfer
+ data from the \em src BasicIo object into this object.
+
+ The source object is invalidated by this operation and should not be
+ used after this method returns. This method exists primarily to
+ be used with the BasicIo::temporary() method.
+
+ @param src Reference to another BasicIo instance. The entire contents
+ of src are transferred to this object. The \em src object is
+ invalidated by the method.
+ @throw Error In case of failure
+ */
+ virtual void transfer(BasicIo& src) = 0;
+ /*!
+ @brief Move the current IO position.
+ @param offset Number of bytes to move the position relative
+ to the starting position specified by \em pos
+ @param pos Position from which the seek should start
+ @return 0 if successful;<BR>
+ Nonzero if failure;
+ */
+ virtual int seek(long offset, Position pos) = 0;
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Get the current IO position.
+ @return Offset from the start of IO if successful;<BR>
+ -1 if failure;
+ */
+ virtual long tell() const = 0;
+ /*!
+ @brief Get the current size of the IO source in bytes.
+ @return Size of the IO source in bytes;<BR>
+ -1 if failure;
+ */
+ virtual long size() const = 0;
+ //!Returns true if the IO source is open, otherwise false.
+ virtual bool isopen() const = 0;
+ //!Returns 0 if the IO source is in a valid state, otherwise nonzero.
+ virtual int error() const = 0;
+ //!Returns true if the IO position has reach the end, otherwise false.
+ virtual bool eof() const = 0;
+ /*!
+ @brief Return the path to the IO resource. Often used to form
+ comprehensive error messages where only a BasicIo instance is
+ available.
+ */
+ virtual std::string path() const =0;
+ /*!
+ @brief Returns a temporary data storage location. This is often
+ needed to rewrite an IO source.
+
+ For example, data may be read from the original IO source, modified
+ in some way, and then saved to the temporary instance. After the
+ operation is complete, the BasicIo::transfer method can be used to
+ replace the original IO source with the modified version. Subclasses
+ are free to return any class that derives from BasicIo.
+
+ @return An instance of BasicIo on success
+ @throw Error In case of failure
+ */
+ virtual BasicIo::AutoPtr temporary() const = 0;
+ //@}
+
+ protected:
+ //! @name Creators
+ //@{
+ //! Default Constructor
+ BasicIo() {}
+ //@}
+ }; // class BasicIo
+
+ /*!
+ @brief Utility class that closes a BasicIo instance upon destruction.
+ Meant to be used as a stack variable in functions that need to
+ ensure BasicIo instances get closed. Useful when functions return
+ errors from many locations.
+ */
+ class IoCloser {
+ public:
+ //! @name Creators
+ //@{
+ //! Constructor, takes a BasicIo reference
+ IoCloser(BasicIo &bio) : bio_(bio) {}
+ //! Destructor, closes the BasicIo reference
+ ~IoCloser() { close(); }
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Close the BasicIo if it is open
+ void close() { if (bio_.isopen()) bio_.close(); }
+ //@}
+
+ // DATA
+ //! The BasicIo reference
+ BasicIo &bio_;
+ private:
+ // Not implemented
+ //! Copy constructor
+ IoCloser(const IoCloser&);
+ //! Assignment operator
+ IoCloser& operator=(const IoCloser&);
+ }; // class IoCloser
+
+
+ /*!
+ @brief Provides binary file IO by implementing the BasicIo
+ interface.
+ */
+ class FileIo : public BasicIo
+ {
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor that accepts the file path on which IO will be
+ performed. The constructor does not open the file, and
+ therefore never failes.
+ @param path The full path of a file
+ */
+ FileIo(const std::string& path);
+ //! Destructor. Flushes and closes an open file.
+ virtual ~FileIo();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Open the file using using the specified mode.
+
+ This method can also be used to "reopen" a file which will flush any
+ unwritten data and reset the IO position to the start. Although
+ files can be opened in binary or text mode, this class has
+ only been tested carefully in binary mode.
+
+ @param mode Specified that type of access allowed on the file.
+ Valid values match those of the C fopen command exactly.
+ @return 0 if successful;<BR>
+ Nonzero if failure.
+ */
+ int open(const std::string& mode);
+ /*!
+ @brief Open the file using using the default access mode of "rb".
+ This method can also be used to "reopen" a file which will flush
+ any unwritten data and reset the IO position to the start.
+ @return 0 if successful;<BR>
+ Nonzero if failure.
+ */
+ virtual int open();
+ /*!
+ @brief Flush and unwritten data and close the file . It is
+ safe to call close on an already closed instance.
+ @return 0 if successful;<BR>
+ Nonzero if failure;
+ */
+ virtual int close();
+ /*!
+ @brief Write data to the file. The file position is advanced
+ by the number of bytes written.
+ @param data Pointer to data. Data must be at least \em wcount
+ bytes long
+ @param wcount Number of bytes to be written.
+ @return Number of bytes written to the file successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(const byte* data, long wcount);
+ /*!
+ @brief Write data that is read from another BasicIo instance to
+ the file. The file position is advanced by the number
+ of bytes written.
+ @param src Reference to another BasicIo instance. Reading start
+ at the source's current IO position
+ @return Number of bytes written to the file successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(BasicIo& src);
+ /*!
+ @brief Write one byte to the file. The file position is
+ advanced by one byte.
+ @param data The single byte to be written.
+ @return The value of the byte written if successful;<BR>
+ EOF if failure;
+ */
+ virtual int putb(byte data);
+ /*!
+ @brief Read data from the file. Reading starts at the current
+ file position and the position is advanced by the number of
+ bytes read.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return DataBuf instance containing the bytes read. Use the
+ DataBuf::size_ member to find the number of bytes read.
+ DataBuf::size_ will be 0 on failure.
+ */
+ virtual DataBuf read(long rcount);
+ /*!
+ @brief Read data from the file. Reading starts at the current
+ file position and the position is advanced by the number of
+ bytes read.
+ @param buf Pointer to a block of memory into which the read data
+ is stored. The memory block must be at least \em rcount bytes
+ long.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return Number of bytes read from the file successfully;<BR>
+ 0 if failure;
+ */
+ virtual long read(byte *buf, long rcount);
+ /*!
+ @brief Read one byte from the file. The file position is
+ advanced by one byte.
+ @return The byte read from the file if successful;<BR>
+ EOF if failure;
+ */
+ virtual int getb();
+ /*!
+ @brief Remove the contents of the file and then transfer data from
+ the \em src BasicIo object into the empty file.
+
+ This method is optimized to simply rename the source file if the
+ source object is another FileIo instance. The source BasicIo object
+ is invalidated by this operation and should not be used after this
+ method returns. This method exists primarily to be used with
+ the BasicIo::temporary() method.
+
+ @param src Reference to another BasicIo instance. The entire contents
+ of src are transferred to this object. The \em src object is
+ invalidated by the method.
+ @throw Error In case of failure
+ */
+ virtual void transfer(BasicIo& src);
+ /*!
+ @brief Move the current file position.
+ @param offset Number of bytes to move the file position
+ relative to the starting position specified by \em pos
+ @param pos Position from which the seek should start
+ @return 0 if successful;<BR>
+ Nonzero if failure;
+ */
+ virtual int seek(long offset, Position pos);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Get the current file position.
+ @return Offset from the start of the file if successful;<BR>
+ -1 if failure;
+ */
+ virtual long tell() const;
+ /*!
+ @brief Flush any buffered writes and get the current file size
+ in bytes.
+ @note On Win32 systems the file must be closed prior to calling this
+ function.
+ @return Size of the file in bytes;<BR>
+ -1 if failure;
+ */
+ virtual long size() const;
+ //! Returns true if the file is open, otherwise false.
+ virtual bool isopen() const;
+ //! Returns 0 if the file is in a valid state, otherwise nonzero.
+ virtual int error() const;
+ //! Returns true if the file position has reach the end, otherwise
false.
+ virtual bool eof() const;
+ //! Returns the path of the file
+ virtual std::string path() const;
+ /*!
+ @brief Returns a temporary data storage location. The actual type
+ returned depends upon the size of the file represented a FileIo
+ object. For small files, a MemIo is returned while for large
files
+ a FileIo is returned. Callers should not rely on this behavior,
+ however, since it may change.
+ @return An instance of BasicIo on success
+ @throw Error If opening the temporary file fails
+ */
+ virtual BasicIo::AutoPtr temporary() const;
+ //@}
+
+ private:
+ // NOT IMPLEMENTED
+ //! Copy constructor
+ FileIo(FileIo& rhs);
+ //! Assignment operator
+ FileIo& operator=(const FileIo& rhs);
+
+ // Enumeration
+ enum OpMode { opRead, opWrite, opSeek };
+
+ // DATA
+ std::string path_;
+ std::string openMode_;
+ FILE *fp_;
+ OpMode opMode_;
+
+ // METHODS
+ /*!
+ @brief Switch to a new access mode, reopening the file if needed.
+ Optimized to only reopen the file when it is really necessary.
+ @param opMode The mode to switch to.
+ @return 0 if successful
+ */
+ int switchMode(OpMode opMode);
+
+ }; // class FileIo
+
+ /*!
+ @brief Provides binary IO on blocks of memory by implementing the
+ BasicIo interface. The current implementation makes a copy of
+ any data passed to its constructors. If writes are performed, the
+ changed data can be retrieved using the read methods (since the
+ data used in construction is never modified).
+
+ @note If read only usage of this class is common, it might be worth
+ creating a specialized readonly class or changing this one to
+ have a readonly mode.
+ */
+ class MemIo : public BasicIo
+ {
+ public:
+ //! @name Creators
+ //@{
+ //! Default constructor that results in an empty object
+ MemIo() { idx_ = 0; }
+ /*!
+ @brief Constructor that accepts a block of memory to be copied.
+ IO operations are performed on the copied memory.
+ @param data Pointer to data. Data must be at least \em size
+ bytes long
+ @param size Number of bytes to copy.
+ */
+ MemIo(const byte* data, long size);
+ //! Destructor. Releases all managed memory
+ virtual ~MemIo() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Memory IO is always open for reading and writing. This method
+ therefore only resets the IO position to the start.
+
+ @return 0
+ */
+ virtual int open();
+ /*!
+ @brief Does nothing on MemIo objects.
+ @return 0
+ */
+ virtual int close();
+ /*!
+ @brief Write data to the memory block. If needed, the size of the
+ internal memory block is expanded. The IO position is advanced
+ by the number of bytes written.
+ @param data Pointer to data. Data must be at least \em wcount
+ bytes long
+ @param wcount Number of bytes to be written.
+ @return Number of bytes written to the memory block successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(const byte* data, long wcount);
+ /*!
+ @brief Write data that is read from another BasicIo instance to
+ the memory block. If needed, the size of the internal memory
+ block is expanded. The IO position is advanced by the number
+ of bytes written.
+ @param src Reference to another BasicIo instance. Reading start
+ at the source's current IO position
+ @return Number of bytes written to the memory block successfully;<BR>
+ 0 if failure;
+ */
+ virtual long write(BasicIo& src);
+ /*!
+ @brief Write one byte to the memory block. The IO position is
+ advanced by one byte.
+ @param data The single byte to be written.
+ @return The value of the byte written if successful;<BR>
+ EOF if failure;
+ */
+ virtual int putb(byte data);
+ /*!
+ @brief Read data from the memory block. Reading starts at the current
+ IO position and the position is advanced by the number of
+ bytes read.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return DataBuf instance containing the bytes read. Use the
+ DataBuf::size_ member to find the number of bytes read.
+ DataBuf::size_ will be 0 on failure.
+ */
+ virtual DataBuf read(long rcount);
+ /*!
+ @brief Read data from the memory block. Reading starts at the current
+ IO position and the position is advanced by the number of
+ bytes read.
+ @param buf Pointer to a block of memory into which the read data
+ is stored. The memory block must be at least \em rcount bytes
+ long.
+ @param rcount Maximum number of bytes to read. Fewer bytes may be
+ read if \em rcount bytes are not available.
+ @return Number of bytes read from the memory block successfully;<BR>
+ 0 if failure;
+ */
+ virtual long read(byte *buf, long rcount);
+ /*!
+ @brief Read one byte from the memory block. The IO position is
+ advanced by one byte.
+ @return The byte read from the memory block if successful;<BR>
+ EOF if failure;
+ */
+ virtual int getb();
+ /*!
+ @brief Clear the memory clock and then transfer data from
+ the \em src BasicIo object into a new block of memory.
+
+ This method is optimized to simply swap memory block if the source
+ object is another MemIo instance. The source BasicIo instance
+ is invalidated by this operation and should not be used after this
+ method returns. This method exists primarily to be used with
+ the BasicIo::temporary() method.
+
+ @param src Reference to another BasicIo instance. The entire contents
+ of src are transferred to this object. The \em src object is
+ invalidated by the method.
+ @throw Error In case of failure
+ */
+ virtual void transfer(BasicIo& src);
+ /*!
+ @brief Move the current IO position.
+ @param offset Number of bytes to move the IO position
+ relative to the starting position specified by \em pos
+ @param pos Position from which the seek should start
+ @return 0 if successful;<BR>
+ Nonzero if failure;
+ */
+ virtual int seek(long offset, Position pos);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Get the current IO position.
+ @return Offset from the start of the memory block
+ */
+ virtual long tell() const;
+ /*!
+ @brief Get the current memory buffer size in bytes.
+ @return Size of the in memory data in bytes;<BR>
+ -1 if failure;
+ */
+ virtual long size() const;
+ //!Always returns true
+ virtual bool isopen() const;
+ //!Always returns 0
+ virtual int error() const;
+ //!Returns true if the IO position has reach the end, otherwise false.
+ virtual bool eof() const;
+ //! Returns a dummy path, indicating that memory access is used
+ virtual std::string path() const;
+ /*!
+ @brief Returns a temporary data storage location. Currently returns
+ an empty MemIo object, but callers should not rely on this
+ behavior since it may change.
+ @return An instance of BasicIo
+ */
+ virtual BasicIo::AutoPtr temporary() const;
+ //@}
+ private:
+ // NOT IMPLEMENTED
+ //! Copy constructor
+ MemIo(MemIo& rhs);
+ //! Assignment operator
+ MemIo& operator=(const MemIo& rhs);
+
+ // Typedefs
+ typedef std::vector<byte> ByteVector;
+
+ // DATA
+ ByteVector data_;
+ ByteVector::size_type idx_;
+
+ // METHODS
+ void checkSize(long wcount);
+ }; // class MemIo
+} // namespace Exiv2
+
+#endif // #ifndef BASICIO_HPP_
Added: Extractor/src/plugins/exiv2/canonmn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/canonmn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/canonmn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,934 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: canonmn.cpp
+ Version: $Rev: 569 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 18-Feb-04, ahu: created
+ 07-Mar-04, ahu: isolated as a separate component
+ Credits: Canon MakerNote implemented according to the specification
+ "EXIF MakerNote of Canon" <http://www.burren.cx/david/canon.html>
+ by David Burren
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: canonmn.cpp 569 2005-05-28 05:48:43Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "canonmn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+#include "ifd.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <cmath>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// local declarations
+namespace {
+ /*
+ @brief Convert Canon hex-based EV (modulo 0x20) to real number
+ Ported from Phil Harvey's Image::ExifTool::Canon::CanonEv
+ by Will Stokes
+
+ 0x00 -> 0
+ 0x0c -> 0.33333
+ 0x10 -> 0.5
+ 0x14 -> 0.66666
+ 0x20 -> 1
+ ..
+ 160 -> 5
+ 128 -> 4
+ 143 -> 4.46875
+ */
+ float canonEv(long val);
+}
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ CanonMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("Canon", "*",
createCanonMakerNote);
+
+ MakerNoteFactory::registerMakerNote(
+ canonIfdId, MakerNote::AutoPtr(new CanonMakerNote));
+ MakerNoteFactory::registerMakerNote(
+ canonCs1IfdId, MakerNote::AutoPtr(new CanonMakerNote));
+ MakerNoteFactory::registerMakerNote(
+ canonCs2IfdId, MakerNote::AutoPtr(new CanonMakerNote));
+ MakerNoteFactory::registerMakerNote(
+ canonCfIfdId, MakerNote::AutoPtr(new CanonMakerNote));
+
+ ExifTags::registerMakerTagInfo(canonIfdId, tagInfo_);
+ ExifTags::registerMakerTagInfo(canonCs1IfdId, tagInfoCs1_);
+ ExifTags::registerMakerTagInfo(canonCs2IfdId, tagInfoCs2_);
+ ExifTags::registerMakerTagInfo(canonCfIfdId, tagInfoCf_);
+ }
+ //! @endcond
+
+ // Canon MakerNote Tag Info
+ const TagInfo CanonMakerNote::tagInfo_[] = {
+ TagInfo(0x0000, "0x0000", "Unknown", canonIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0001, "CameraSettings1", "Various camera settings (1)",
canonIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0002, "0x0002", "Unknown", canonIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0003, "0x0003", "Unknown", canonIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0004, "CameraSettings2", "Various camera settings (2)",
canonIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0006, "ImageType", "Image type", canonIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0007, "FirmwareVersion", "Firmware version", canonIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0008, "ImageNumber", "Image number", canonIfdId, makerTags,
unsignedLong, print0x0008),
+ TagInfo(0x0009, "OwnerName", "Owner Name", canonIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x000c, "SerialNumber", "Camera serial number", canonIfdId,
makerTags, unsignedLong, print0x000c),
+ TagInfo(0x000d, "0x000d", "Unknown", canonIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000f, "CustomFunctions", "Custom Functions", canonIfdId,
makerTags, unsignedShort, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownCanonMakerNoteTag)", "Unknown CanonMakerNote
tag", canonIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ // Canon Camera Settings 1 Tag Info
+ const TagInfo CanonMakerNote::tagInfoCs1_[] = {
+ TagInfo(0x0001, "Macro", "Macro mode", canonCs1IfdId, makerTags,
unsignedShort, printCs10x0001),
+ TagInfo(0x0002, "Selftimer", "Self timer", canonCs1IfdId, makerTags,
unsignedShort, printCs10x0002),
+ TagInfo(0x0003, "Quality", "Quality", canonCs1IfdId, makerTags,
unsignedShort, printCs10x0003),
+ TagInfo(0x0004, "FlashMode", "Flash mode setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0004),
+ TagInfo(0x0005, "DriveMode", "Drive mode setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0005),
+ TagInfo(0x0006, "0x0006", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0007, "FocusMode", "Focus mode setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0007),
+ TagInfo(0x0008, "0x0008", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0009, "0x0009", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000a, "ImageSize", "Image size", canonCs1IfdId, makerTags,
unsignedShort, printCs10x000a),
+ TagInfo(0x000b, "EasyMode", "Easy shooting mode", canonCs1IfdId,
makerTags, unsignedShort, printCs10x000b),
+ TagInfo(0x000c, "DigitalZoom", "Digital zoom", canonCs1IfdId,
makerTags, unsignedShort, printCs10x000c),
+ TagInfo(0x000d, "Contrast", "Contrast setting", canonCs1IfdId,
makerTags, unsignedShort, printCs1Lnh),
+ TagInfo(0x000e, "Saturation", "Saturation setting", canonCs1IfdId,
makerTags, unsignedShort, printCs1Lnh),
+ TagInfo(0x000f, "Sharpness", "Sharpness setting", canonCs1IfdId,
makerTags, unsignedShort, printCs1Lnh),
+ TagInfo(0x0010, "ISOSpeed", "ISO speed setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0010),
+ TagInfo(0x0011, "MeteringMode", "Metering mode setting",
canonCs1IfdId, makerTags, unsignedShort, printCs10x0011),
+ TagInfo(0x0012, "FocusType", "Focus type setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0012),
+ TagInfo(0x0013, "AFPoint", "AF point selected", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0013),
+ TagInfo(0x0014, "ExposureProgram", "Exposure mode setting",
canonCs1IfdId, makerTags, unsignedShort, printCs10x0014),
+ TagInfo(0x0015, "0x0015", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0016, "0x0016", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0017, "Lens", "'long' and 'short' focal length of lens (in
'focal units') and 'focal units' per mm", canonCs1IfdId, makerTags,
unsignedShort, printCs1Lens),
+ TagInfo(0x0018, "0x0018", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0019, "0x0019", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x001a, "0x001a", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x001b, "0x001b", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x001c, "FlashActivity", "Flash activity", canonCs1IfdId,
makerTags, unsignedShort, printCs10x001c),
+ TagInfo(0x001d, "FlashDetails", "Flash details", canonCs1IfdId,
makerTags, unsignedShort, printCs10x001d),
+ TagInfo(0x001e, "0x001e", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x001f, "0x001f", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0020, "FocusMode", "Focus mode setting", canonCs1IfdId,
makerTags, unsignedShort, printCs10x0020),
+ TagInfo(0x0021, "0x0021", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0022, "0x0022", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0023, "0x0023", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0024, "0x0024", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0025, "0x0025", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0026, "0x0026", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0027, "0x0027", "Unknown", canonCs1IfdId, makerTags,
unsignedShort, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownCanonCs1Tag)", "Unknown Canon Camera Settings
1 tag", canonCs1IfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ // Canon Camera Settings 2 Tag Info
+ const TagInfo CanonMakerNote::tagInfoCs2_[] = {
+ TagInfo(0x0001, "0x0001", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0002, "ISOSpeed", "ISO speed used", canonCs2IfdId,
makerTags, unsignedShort, printCs20x0002),
+ TagInfo(0x0003, "0x0003", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0004, "0x0004", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0005, "0x0005", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0006, "0x0006", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0007, "WhiteBalance", "White balance setting",
canonCs2IfdId, makerTags, unsignedShort, printCs20x0007),
+ TagInfo(0x0008, "0x0008", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0009, "Sequence", "Sequence number (if in a continuous
burst)", canonCs2IfdId, makerTags, unsignedShort, printCs20x0009),
+ TagInfo(0x000a, "0x000a", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000b, "0x000b", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000c, "0x000c", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000d, "0x000d", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x000e, "AFPointUsed", "AF point used", canonCs2IfdId,
makerTags, unsignedShort, printCs20x000e),
+ TagInfo(0x000f, "FlashBias", "Flash bias", canonCs2IfdId, makerTags,
unsignedShort, printCs20x000f),
+ TagInfo(0x0010, "0x0010", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0011, "0x0011", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0012, "0x0012", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0013, "SubjectDistance", "Subject distance (units are not
clear)", canonCs2IfdId, makerTags, unsignedShort, printCs20x0013),
+ TagInfo(0x0014, "0x0014", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0015, "0x0015", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0016, "0x0016", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0017, "0x0017", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0018, "0x0018", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0019, "0x0019", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x001a, "0x001a", "Unknown", canonCs2IfdId, makerTags,
unsignedShort, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownCanonCs2Tag)", "Unknown Canon Camera Settings
2 tag", canonCs2IfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ // Canon Custom Function Tag Info
+ const TagInfo CanonMakerNote::tagInfoCf_[] = {
+ TagInfo(0x0001, "NoiseReduction", "Long exposure noise reduction",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0002, "ShutterAeLock", "Shutter/AE lock buttons",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0003, "MirrorLockup", "Mirror lockup", canonCfIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x0004, "ExposureLevelIncrements", "Tv/Av and exposure level",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0005, "AFAssist", "AF assist light", canonCfIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x0006, "FlashSyncSpeedAv", "Shutter speed in Av mode",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0007, "AEBSequence", "AEB sequence/auto cancellation",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0008, "ShutterCurtainSync", "Shutter curtain sync",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0009, "LensAFStopButton", "Lens AF stop button Fn. Switch",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x000a, "FillFlashAutoReduction", "Auto reduction of fill
flash", canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x000b, "MenuButtonReturn", "Menu button return position",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x000c, "SetButtonFunction", "SET button func. when shooting",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x000d, "SensorCleaning", "Sensor cleaning", canonCfIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x000e, "SuperimposedDisplay", "Superimposed display",
canonCfIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x000f, "ShutterReleaseNoCFCard", "Shutter Release W/O CF
Card", canonCfIfdId, makerTags, unsignedShort, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownCanonCfTag)", "Unknown Canon Custom Function
tag", canonCfIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ int CanonMakerNote::read(const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ int rc = IfdMakerNote::read(buf, len, byteOrder, offset);
+ if (rc) return rc;
+
+ // Decode camera settings 1 and add settings as additional entries
+ Entries::iterator cs = ifd_.findTag(0x0001);
+ if (cs != ifd_.end() && cs->type() == unsignedShort) {
+ for (uint16_t c = 1; cs->count() > c; ++c) {
+ if (c == 23 && cs->count() > 25) {
+ // Pack related lens info into one tag
+ addCsEntry(canonCs1IfdId, c, cs->offset() + c*2,
+ cs->data() + c*2, 3);
+ c += 2;
+ }
+ else {
+ addCsEntry(canonCs1IfdId, c, cs->offset() + c*2,
+ cs->data() + c*2, 1);
+ }
+ }
+ // Discard the original entry
+ ifd_.erase(cs);
+ }
+
+ // Decode camera settings 2 and add settings as additional entries
+ cs = ifd_.findTag(0x0004);
+ if (cs != ifd_.end() && cs->type() == unsignedShort) {
+ for (uint16_t c = 1; cs->count() > c; ++c) {
+ addCsEntry(canonCs2IfdId, c, cs->offset() + c*2,
+ cs->data() + c*2, 1);
+ }
+ // Discard the original entry
+ ifd_.erase(cs);
+ }
+
+ // Decode custom functions and add each as an additional entry
+ cs = ifd_.findTag(0x000f);
+ if (cs != ifd_.end() && cs->type() == unsignedShort) {
+ for (uint16_t c = 1; cs->count() > c; ++c) {
+ addCsEntry(canonCfIfdId, c, cs->offset() + c*2,
+ cs->data() + c*2, 1);
+ }
+ // Discard the original entry
+ ifd_.erase(cs);
+ }
+
+ // Copy remaining ifd entries
+ entries_.insert(entries_.begin(), ifd_.begin(), ifd_.end());
+
+ // Set idx
+ int idx = 0;
+ Entries::iterator e = entries_.end();
+ for (Entries::iterator i = entries_.begin(); i != e; ++i) {
+ i->setIdx(++idx);
+ }
+
+ return 0;
+ }
+
+ void CanonMakerNote::addCsEntry(IfdId ifdId,
+ uint16_t tag,
+ long offset,
+ const byte* data,
+ int count)
+ {
+ Entry e(false);
+ e.setIfdId(ifdId);
+ e.setTag(tag);
+ e.setOffset(offset);
+ e.setValue(unsignedShort, count, data, 2*count);
+ add(e);
+ }
+
+ void CanonMakerNote::add(const Entry& entry)
+ {
+ assert(alloc_ == entry.alloc());
+ assert( entry.ifdId() == canonIfdId
+ || entry.ifdId() == canonCs1IfdId
+ || entry.ifdId() == canonCs2IfdId
+ || entry.ifdId() == canonCfIfdId);
+ // allow duplicates
+ entries_.push_back(entry);
+ }
+
+ long CanonMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset)
+ {
+ if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
+
+ assert(ifd_.alloc());
+ ifd_.clear();
+
+ // Add all standard Canon entries to the IFD
+ Entries::const_iterator end = entries_.end();
+ for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
+ if (i->ifdId() == canonIfdId) {
+ ifd_.add(*i);
+ }
+ }
+ // Collect camera settings 1 entries and add the original Canon tag
+ Entry cs1;
+ if (assemble(cs1, canonCs1IfdId, 0x0001, byteOrder_)) {
+ ifd_.erase(0x0001);
+ ifd_.add(cs1);
+ }
+ // Collect camera settings 2 entries and add the original Canon tag
+ Entry cs2;
+ if (assemble(cs2, canonCs2IfdId, 0x0004, byteOrder_)) {
+ ifd_.erase(0x0004);
+ ifd_.add(cs2);
+ }
+ // Collect custom function entries and add the original Canon tag
+ Entry cf;
+ if (assemble(cf, canonCfIfdId, 0x000f, byteOrder_)) {
+ ifd_.erase(0x000f);
+ ifd_.add(cf);
+ }
+
+ return IfdMakerNote::copy(buf, byteOrder_, offset);
+ } // CanonMakerNote::copy
+
+ void CanonMakerNote::updateBase(byte* pNewBase)
+ {
+ byte* pBase = ifd_.updateBase(pNewBase);
+ if (absOffset_ && !alloc_) {
+ Entries::iterator end = entries_.end();
+ for (Entries::iterator pos = entries_.begin(); pos != end; ++pos) {
+ pos->updateBase(pBase, pNewBase);
+ }
+ }
+ } // CanonMakerNote::updateBase
+
+ long CanonMakerNote::size() const
+ {
+ Ifd ifd(canonIfdId, 0, alloc_); // offset doesn't matter
+
+ // Add all standard Canon entries to the IFD
+ Entries::const_iterator end = entries_.end();
+ for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
+ if (i->ifdId() == canonIfdId) {
+ ifd.add(*i);
+ }
+ }
+ // Collect camera settings 1 entries and add the original Canon tag
+ Entry cs1(alloc_);
+ if (assemble(cs1, canonCs1IfdId, 0x0001, littleEndian)) {
+ ifd.erase(0x0001);
+ ifd.add(cs1);
+ }
+ // Collect camera settings 2 entries and add the original Canon tag
+ Entry cs2(alloc_);
+ if (assemble(cs2, canonCs2IfdId, 0x0004, littleEndian)) {
+ ifd.erase(0x0004);
+ ifd.add(cs2);
+ }
+ // Collect custom function entries and add the original Canon tag
+ Entry cf(alloc_);
+ if (assemble(cf, canonCfIfdId, 0x000f, littleEndian)) {
+ ifd.erase(0x000f);
+ ifd.add(cf);
+ }
+
+ return headerSize() + ifd.size() + ifd.dataSize();
+ } // CanonMakerNote::size
+
+ long CanonMakerNote::assemble(Entry& e,
+ IfdId ifdId,
+ uint16_t tag,
+ ByteOrder byteOrder) const
+ {
+ DataBuf buf(1024);
+ memset(buf.pData_, 0x0, 1024);
+ uint16_t len = 0;
+ Entries::const_iterator end = entries_.end();
+ for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
+ if (i->ifdId() == ifdId) {
+ uint16_t pos = i->tag() * 2;
+ uint16_t size = pos + static_cast<uint16_t>(i->size());
+ assert(size <= 1024);
+ memcpy(buf.pData_ + pos, i->data(), i->size());
+ if (len < size) len = size;
+ }
+ }
+ if (len > 0) {
+ // Number of shorts in the buffer (rounded up)
+ uint16_t s = (len+1) / 2;
+ us2Data(buf.pData_, s*2, byteOrder);
+
+ e.setIfdId(canonIfdId);
+ e.setIdx(0); // don't care
+ e.setTag(tag);
+ e.setOffset(0); // will be calculated when the IFD is written
+ e.setValue(unsignedShort, s, buf.pData_, s*2);
+ }
+ return len;
+ } // CanonMakerNote::assemble
+
+ Entries::const_iterator CanonMakerNote::findIdx(int idx) const
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByIdx(idx));
+ }
+
+ CanonMakerNote::CanonMakerNote(bool alloc)
+ : IfdMakerNote(canonIfdId, alloc)
+ {
+ }
+
+ CanonMakerNote::CanonMakerNote(const CanonMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ entries_ = rhs.entries_;
+ }
+
+ CanonMakerNote::AutoPtr CanonMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ CanonMakerNote* CanonMakerNote::create_(bool alloc) const
+ {
+ return new CanonMakerNote(alloc);
+ }
+
+ CanonMakerNote::AutoPtr CanonMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ CanonMakerNote* CanonMakerNote::clone_() const
+ {
+ return new CanonMakerNote(*this);
+ }
+
+ std::ostream& CanonMakerNote::print0x0008(std::ostream& os,
+ const Value& value)
+ {
+ std::string n = value.toString();
+ return os << n.substr(0, n.length() - 4) << "-"
+ << n.substr(n.length() - 4);
+ }
+
+ std::ostream& CanonMakerNote::print0x000c(std::ostream& os,
+ const Value& value)
+ {
+ std::istringstream is(value.toString());
+ uint32_t l;
+ is >> l;
+ return os << std::setw(4) << std::setfill('0') << std::hex
+ << ((l & 0xffff0000) >> 16)
+ << std::setw(5) << std::setfill('0') << std::dec
+ << (l & 0x0000ffff);
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0001(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 1: os << "On"; break;
+ case 2: os << "Off"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0002(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ if (l == 0) {
+ os << "Off";
+ }
+ else {
+ os << l / 10.0 << " s";
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0003(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 2: os << "Normal"; break;
+ case 3: os << "Fine"; break;
+ case 5: os << "Superfine"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0004(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Off"; break;
+ case 1: os << "Auto"; break;
+ case 2: os << "On"; break;
+ case 3: os << "Red-eye"; break;
+ case 4: os << "Slow sync"; break;
+ case 5: os << "Auto + red-eye"; break;
+ case 6: os << "On + red-eye"; break;
+ case 16: os << "External"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0005(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Single / timer"; break;
+ case 1: os << "Continuous"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0007(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "One shot"; break;
+ case 1: os << "AI servo"; break;
+ case 2: os << "AI Focus"; break;
+ case 3: os << "MF"; break;
+ case 4: os << "Single"; break;
+ case 5: os << "Continuous"; break;
+ case 6: os << "MF"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x000a(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Large"; break;
+ case 1: os << "Medium"; break;
+ case 2: os << "Small"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x000b(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Full auto"; break;
+ case 1: os << "Manual"; break;
+ case 2: os << "Landscape"; break;
+ case 3: os << "Fast shutter"; break;
+ case 4: os << "Slow shutter"; break;
+ case 5: os << "Night"; break;
+ case 6: os << "B&W"; break;
+ case 7: os << "Sepia"; break;
+ case 8: os << "Portrait"; break;
+ case 9: os << "Sports"; break;
+ case 10: os << "Macro / close-up"; break;
+ case 11: os << "Pan focus"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x000c(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "None"; break;
+ case 1: os << "2x"; break;
+ case 2: os << "4x"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs1Lnh(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0xffff: os << "Low"; break;
+ case 0x0000: os << "Normal"; break;
+ case 0x0001: os << "High"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0010(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "n/a"; break;
+ case 15: os << "Auto"; break;
+ case 16: os << "50"; break;
+ case 17: os << "100"; break;
+ case 18: os << "200"; break;
+ case 19: os << "400"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0011(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 3: os << "Evaluative"; break;
+ case 4: os << "Partial"; break;
+ case 5: os << "Center weighted"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0012(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Manual"; break;
+ case 1: os << "Auto"; break;
+ case 3: os << "Close-up (macro)"; break;
+ case 8: os << "Locked (pan mode)"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0013(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0x3000: os << "None (MF)"; break;
+ case 0x3001: os << "Auto-selected"; break;
+ case 0x3002: os << "Right"; break;
+ case 0x3003: os << "Center"; break;
+ case 0x3004: os << "Left"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0014(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Easy shooting"; break;
+ case 1: os << "Program"; break;
+ case 2: os << "Shutter priority"; break;
+ case 3: os << "Aperture priority"; break;
+ case 4: os << "Manual"; break;
+ case 5: os << "A-DEP"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x001c(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Did not fire"; break;
+ case 1: os << "Fired"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x001d(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ bool coma = false;
+ if (l & 0x4000) {
+ if (coma) os << ", ";
+ os << "External TTL";
+ coma = true;
+ }
+ if (l & 0x2000) {
+ if (coma) os << ", ";
+ os << "Internal flash";
+ coma = true;
+ }
+ if (l & 0x0800) {
+ if (coma) os << ", ";
+ os << "FP sync used";
+ coma = true;
+ }
+ if (l & 0x0080) {
+ if (coma) os << ", ";
+ os << "Rear curtain sync used";
+ coma = true;
+ }
+ if (l & 0x0010) {
+ if (coma) os << ", ";
+ os << "FP sync enabled";
+ coma = true;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs10x0020(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Single"; break;
+ case 1: os << "Continuous"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs1Lens(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ if (value.count() < 3) return os << value;
+
+ float fu = value.toFloat(2);
+ float len1 = value.toLong(0) / fu;
+ float len2 = value.toLong(1) / fu;
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(1)
+ << len2 << " - " << len1 << " mm";
+ os.copyfmt(oss);
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x0002(std::ostream& os,
+ const Value& value)
+ {
+ // Ported from Exiftool by Will Stokes
+ return os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x0007(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Sunny"; break;
+ case 2: os << "Cloudy"; break;
+ case 3: os << "Tungsten"; break;
+ case 4: os << "Fluorescent"; break;
+ case 5: os << "Flash"; break;
+ case 6: os << "Custom"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x0009(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ os << l << "";
+ // Todo: determine unit
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x000e(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ long num = (l & 0xf000) >> 12;
+ os << num << " focus points; ";
+ long used = l & 0x0fff;
+ if (used == 0) {
+ os << "none";
+ }
+ else {
+ bool coma = false;
+ if (l & 0x0004) {
+ if (coma) os << ", ";
+ os << "left";
+ coma = true;
+ }
+ if (l & 0x0002) {
+ if (coma) os << ", ";
+ os << "center";
+ coma = true;
+ }
+ if (l & 0x0001) {
+ if (coma) os << ", ";
+ os << "right";
+ coma = true;
+ }
+ }
+ os << " used";
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x000f(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ switch (l) {
+ case 0xffc0: os << "-2 EV"; break;
+ case 0xffcc: os << "-1.67 EV"; break;
+ case 0xffd0: os << "-1.50 EV"; break;
+ case 0xffd4: os << "-1.33 EV"; break;
+ case 0xffe0: os << "-1 EV"; break;
+ case 0xffec: os << "-0.67 EV"; break;
+ case 0xfff0: os << "-0.50 EV"; break;
+ case 0xfff4: os << "-0.33 EV"; break;
+ case 0x0000: os << "0 EV"; break;
+ case 0x000c: os << "0.33 EV"; break;
+ case 0x0010: os << "0.50 EV"; break;
+ case 0x0014: os << "0.67 EV"; break;
+ case 0x0020: os << "1 EV"; break;
+ case 0x002c: os << "1.33 EV"; break;
+ case 0x0030: os << "1.50 EV"; break;
+ case 0x0034: os << "1.67 EV"; break;
+ case 0x0040: os << "2 EV"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& CanonMakerNote::printCs20x0013(std::ostream& os,
+ const Value& value)
+ {
+ if (value.typeId() != unsignedShort) return os << value;
+ long l = value.toLong();
+ if (l == 0xffff) {
+ os << "Infinite";
+ }
+ else {
+ os << l << "";
+ }
+ return os;
+ }
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createCanonMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new CanonMakerNote(alloc));
+ }
+
+} // namespace Exiv2
+
+//
*****************************************************************************
+// local definitions
+namespace {
+
+ float canonEv(long val)
+ {
+ // temporarily remove sign
+ int sign = 1;
+ if (val < 0) {
+ sign = -1;
+ val = -val;
+ }
+ // remove fraction
+ float frac = static_cast<float>(val & 0x1f);
+ val -= long(frac);
+ // convert 1/3 (0x0c) and 2/3 (0x14) codes
+ if (frac == 0x0c) {
+ frac = 32.0f / 3;
+ }
+ else if (frac == 0x14) {
+ frac = 64.0f / 3;
+ }
+ return sign * (val + frac) / 32.0f;
+ }
+
+}
Added: Extractor/src/plugins/exiv2/canonmn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/canonmn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/canonmn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,238 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file canonmn.hpp
+ @brief Canon MakerNote implemented according to the specification
+ <a href="http://www.burren.cx/david/canon.html">
+ EXIF MakerNote of Canon</a> by David Burren<br>
+ and with reference to tag information from
+ <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/">
+ ExifTool</a> by Phil Harvey
+ @version $Rev: 569 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 18-Feb-04, ahu: created<BR>
+ 07-Mar-04, ahu: isolated as a separate component
+ */
+#ifndef CANONMN_HPP_
+#define CANONMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createCanonMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Canon cameras
+ class CanonMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %CanonMakerNote auto pointer.
+ typedef std::auto_ptr<CanonMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ CanonMakerNote(bool alloc =true);
+ //! Copy constructor
+ CanonMakerNote(const CanonMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~CanonMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int read(const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+ long copy(byte* buf, ByteOrder byteOrder, long offset);
+ void add(const Entry& entry);
+ Entries::iterator begin() { return entries_.begin(); }
+ Entries::iterator end() { return entries_.end(); }
+ void updateBase(byte* pNewBase);
+ //@}
+
+ //! @name Accessors
+ //@{
+ Entries::const_iterator begin() const { return entries_.begin(); }
+ Entries::const_iterator end() const { return entries_.end(); }
+ Entries::const_iterator findIdx(int idx) const;
+ long size() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Canon %MakerNote tags
+ //@{
+ //! Print the image number
+ static std::ostream& print0x0008(std::ostream& os, const Value& value);
+ //! Print the serial number of the camera
+ static std::ostream& print0x000c(std::ostream& os, const Value& value);
+
+ //! Macro mode
+ static std::ostream& printCs10x0001(std::ostream& os, const Value&
value);
+ //! Self timer
+ static std::ostream& printCs10x0002(std::ostream& os, const Value&
value);
+ //! Quality
+ static std::ostream& printCs10x0003(std::ostream& os, const Value&
value);
+ //! Flash mode
+ static std::ostream& printCs10x0004(std::ostream& os, const Value&
value);
+ //! Drive mode
+ static std::ostream& printCs10x0005(std::ostream& os, const Value&
value);
+ //! Focus mode (G1 seems to use field 32 in preference to this)
+ static std::ostream& printCs10x0007(std::ostream& os, const Value&
value);
+ //! Image size
+ static std::ostream& printCs10x000a(std::ostream& os, const Value&
value);
+ //! Easy shooting
+ static std::ostream& printCs10x000b(std::ostream& os, const Value&
value);
+ //! Digital zoom
+ static std::ostream& printCs10x000c(std::ostream& os, const Value&
value);
+ //! ISO
+ static std::ostream& printCs10x0010(std::ostream& os, const Value&
value);
+ //! Metering mode
+ static std::ostream& printCs10x0011(std::ostream& os, const Value&
value);
+ //! Focus type
+ static std::ostream& printCs10x0012(std::ostream& os, const Value&
value);
+ //! AF point selected
+ static std::ostream& printCs10x0013(std::ostream& os, const Value&
value);
+ //! Exposure mode
+ static std::ostream& printCs10x0014(std::ostream& os, const Value&
value);
+ //! Flash activity
+ static std::ostream& printCs10x001c(std::ostream& os, const Value&
value);
+ //! Flash details
+ static std::ostream& printCs10x001d(std::ostream& os, const Value&
value);
+ //! Focus mode (G1 seems to use this in preference to field 7)
+ static std::ostream& printCs10x0020(std::ostream& os, const Value&
value);
+ //! Low, normal, high print function
+ static std::ostream& printCs1Lnh(std::ostream& os, const Value& value);
+ //! Camera lens information
+ static std::ostream& printCs1Lens(std::ostream& os, const Value&
value);
+ //! ISO speed used
+ static std::ostream& printCs20x0002(std::ostream& os, const Value&
value);
+ //! White balance
+ static std::ostream& printCs20x0007(std::ostream& os, const Value&
value);
+ //! Sequence number
+ static std::ostream& printCs20x0009(std::ostream& os, const Value&
value);
+ //! AF point used
+ static std::ostream& printCs20x000e(std::ostream& os, const Value&
value);
+ //! Flash bias
+ static std::ostream& printCs20x000f(std::ostream& os, const Value&
value);
+ //! Subject distance
+ static std::ostream& printCs20x0013(std::ostream& os, const Value&
value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! @name Manipulators
+ //@{
+ //! Add a camera settings entry to the makernote entries
+ void addCsEntry(IfdId ifdId,
+ uint16_t tag,
+ long offset,
+ const byte* data,
+ int count);
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Assemble special Canon entries into an entry with the original tag
+ long assemble(Entry& e,
+ IfdId ifdId,
+ uint16_t tag,
+ ByteOrder byteOrder) const;
+ //! Internal virtual create function.
+ CanonMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ CanonMakerNote* clone_() const;
+ //@}
+
+ // DATA
+ //! Container to store Makernote entries (instead of Ifd)
+ Entries entries_;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+ static const TagInfo tagInfoCs1_[];
+ static const TagInfo tagInfoCs2_[];
+ static const TagInfo tagInfoCf_[];
+
+ }; // class CanonMakerNote
+
+ static CanonMakerNote::RegisterMn registerCanonMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef CANONMN_HPP_
Added: Extractor/src/plugins/exiv2/datasets.cpp
===================================================================
--- Extractor/src/plugins/exiv2/datasets.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/datasets.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,392 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: datasets.cpp
+ Version: $Rev: 560 $
+ Author(s): Brad Schick (brad) <address@hidden>
+ History: 24-Jul-04, brad: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: datasets.cpp 560 2005-04-17 11:51:32Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "datasets.hpp"
+#include "error.hpp"
+#include "types.hpp"
+#include "value.hpp"
+#include "metadatum.hpp"
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ DataSet::DataSet(
+ uint16_t number,
+ const char* name,
+ const char* desc,
+ bool mandatory,
+ bool repeatable,
+ uint32_t minbytes,
+ uint32_t maxbytes,
+ TypeId type,
+ uint16_t recordId,
+ const char* photoshop
+ )
+ : number_(number), name_(name), desc_(desc), mandatory_(mandatory),
+ repeatable_(repeatable), minbytes_(minbytes), maxbytes_(maxbytes),
+ type_(type), recordId_(recordId), photoshop_(photoshop)
+ {
+ }
+
+ RecordInfo::RecordInfo(
+ uint16_t recordId,
+ const char* name,
+ const char* desc
+ )
+ : recordId_(recordId), name_(name), desc_(desc)
+ {
+ }
+
+ const RecordInfo IptcDataSets::recordInfo_[] = {
+ RecordInfo(IptcDataSets::invalidRecord, "(invalid)", "(invalid)"),
+ RecordInfo(IptcDataSets::envelope, "Envelope", "IIM envelope record"),
+ RecordInfo(IptcDataSets::application2, "Application2", "IIM
application record 2"),
+ };
+
+ static const DataSet envelopeRecord[] = {
+ DataSet(IptcDataSets::ModelVersion, "ModelVersion", "Version of IIM
part 1", true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::Destination, "Destination", "Routing
information", false, true, 0, 1024, Exiv2::string, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::FileFormat, "FileFormat", "IIM appendix A file
format", true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::FileVersion, "FileVersion", "File format
version", true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::ServiceId, "ServiceId", "Identifies the provider
and product", true, false, 0, 10, Exiv2::string, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::EnvelopeNumber, "EnvelopeNumber", "Combined
unique identification", true, false, 8, 8, Exiv2::string,
IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::ProductId, "ProductId", "Identifies service
subset", false, true, 0, 32, Exiv2::string, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::EnvelopePriority, "EnvelopePriority", "Envelope
handling priority", false, false, 1, 1, Exiv2::string, IptcDataSets::envelope,
""),
+ DataSet(IptcDataSets::DateSent, "DateSent", "Date material was sent",
true, false, 8, 8, Exiv2::date, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::TimeSent, "TimeSent", "Time material was sent",
false, false, 11, 11, Exiv2::time, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::CharacterSet, "CharacterSet", "Specifies
character sets", false, false, 0, 32, Exiv2::undefined, IptcDataSets::envelope,
""),
+ DataSet(IptcDataSets::UNO, "UNO", "Unique Name of Object", false,
false, 14, 80, Exiv2::string, IptcDataSets::envelope, ""),
+ DataSet(IptcDataSets::ARMId, "ARMId", "Abstract Relationship Method
identifier", false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope,
""),
+ DataSet(IptcDataSets::ARMVersion, "ARMVersion", "Abstract Relationship
Method version", false, false, 2, 2, Exiv2::unsignedShort,
IptcDataSets::envelope, ""),
+ DataSet(0xffff, "(Invalid)", "(Invalid)", false, false, 0, 0,
Exiv2::unsignedShort, IptcDataSets::envelope, "")
+ };
+
+ static const DataSet application2Record[] = {
+ DataSet(IptcDataSets::RecordVersion, "RecordVersion", "Version of IIM
part 2", true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::ObjectType, "ObjectType", "IIM appendix G object
type", false, false, 3, 67, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ObjectAttribute, "ObjectAttribute", "IIM
appendix G object attribute", false, true, 4, 68, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ObjectName, "ObjectName", "Shorthand reference
of content", false, false, 0, 64, Exiv2::string, IptcDataSets::application2,
"Document title"),
+ DataSet(IptcDataSets::EditStatus, "EditStatus", "Content status",
false, false, 0, 64, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::EditorialUpdate, "EditorialUpdate", "Indicates
the type of update", false, false, 2, 2, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Urgency, "Urgency", "Editorial urgency of
content", false, false, 1, 1, Exiv2::string, IptcDataSets::application2,
"Urgency"),
+ DataSet(IptcDataSets::Subject, "Subject", "Structured definition of
the subject", false, true, 13, 236, Exiv2::string, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::Category, "Category", "Identifies the subject",
false, false, 0, 3, Exiv2::string, IptcDataSets::application2, "Category"),
+ DataSet(IptcDataSets::SuppCategory, "SuppCategory", "Refines the
subject", false, true, 0, 32, Exiv2::string, IptcDataSets::application2,
"Supplemental Categories"),
+ DataSet(IptcDataSets::FixtureId, "FixtureId", "Identifies content that
recurs", false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Keywords, "Keywords", "Information retrieval
words", false, true, 0, 64, Exiv2::string, IptcDataSets::application2,
"Keywords"),
+ DataSet(IptcDataSets::LocationCode, "LocationCode", "ISO country code
for content", false, true, 3, 3, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::LocationName, "LocationName", "Full country name
for content", false, true, 0, 64, Exiv2::string, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::ReleaseDate, "ReleaseDate", "Earliest intended
usable date", false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ReleaseTime, "ReleaseTime", "Earliest intended
usable time", false, false, 11, 11, Exiv2::time, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::ExpirationDate, "ExpirationDate", "Latest
intended usable date", false, false, 8, 8, Exiv2::date,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ExpirationTime, "ExpirationTime", "Latest
intended usable time", false, false, 11, 11, Exiv2::time,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::SpecialInstructions, "SpecialInstructions",
"Editorial usage instructions", false, false, 0, 256, Exiv2::string,
IptcDataSets::application2, "Instructions"),
+ DataSet(IptcDataSets::ActionAdvised, "ActionAdvised", "Action provided
to previous data", false, false, 2, 2, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ReferenceService, "ReferenceService", "Service
Identifier of a prior envelope", false, true, 0, 10, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ReferenceDate, "ReferenceDate", "Date of a prior
envelope", false, true, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ReferenceNumber, "ReferenceNumber", "Envelope
Number of a prior envelope", false, true, 8, 8, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::DateCreated, "DateCreated", "Creation date of
intellectual content", false, false, 8, 8, Exiv2::date,
IptcDataSets::application2, "Date created"),
+ DataSet(IptcDataSets::TimeCreated, "TimeCreated", "Creation time of
intellectual content", false, false, 11, 11, Exiv2::time,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::DigitizationDate, "DigitizationDate", "Creation
date of digital representation", false, false, 8, 8, Exiv2::date,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::DigitizationTime, "DigitizationTime", "Creation
time of digital representation", false, false, 11, 11, Exiv2::time,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Program, "Program", "Content creation program",
false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ProgramVersion, "ProgramVersion", "Content
creation program version", false, false, 0, 10, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ObjectCycle, "ObjectCycle", "Morning, evening,
or both", false, false, 1, 1, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Byline, "Byline", "Name of content creator",
false, true, 0, 32, Exiv2::string, IptcDataSets::application2, "Author"),
+ DataSet(IptcDataSets::BylineTitle, "BylineTitle", "Title of content
creator", false, true, 0, 32, Exiv2::string, IptcDataSets::application2,
"Authors Position"),
+ DataSet(IptcDataSets::City, "City", "City of content origin", false,
false, 0, 32, Exiv2::string, IptcDataSets::application2, "City"),
+ DataSet(IptcDataSets::SubLocation, "SubLocation", "Location within
city", false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ProvinceState, "ProvinceState", "Province/State
of content origin", false, false, 0, 32, Exiv2::string,
IptcDataSets::application2, "State/Province"),
+ DataSet(IptcDataSets::CountryCode, "CountryCode", "ISO country code of
content origin", false, false, 3, 3, Exiv2::string, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::CountryName, "CountryName", "Full country name
of content origin", false, false, 0, 64, Exiv2::string,
IptcDataSets::application2, "Country"),
+ DataSet(IptcDataSets::TransmissionReference, "TransmissionReference",
"Location of original transmission", false, false, 0, 32, Exiv2::string,
IptcDataSets::application2, "Transmission Reference"),
+ DataSet(IptcDataSets::Headline, "Headline", "Content synopsis", false,
false, 0, 256, Exiv2::string, IptcDataSets::application2, "Headline"),
+ DataSet(IptcDataSets::Credit, "Credit", "Content provider", false,
false, 0, 32, Exiv2::string, IptcDataSets::application2, "Credit"),
+ DataSet(IptcDataSets::Source, "Source", "Original owner of content",
false, false, 0, 32, Exiv2::string, IptcDataSets::application2, "Source"),
+ DataSet(IptcDataSets::Copyright, "Copyright", "Necessary copyright
notice", false, false, 0, 128, Exiv2::string, IptcDataSets::application2,
"Copyright notice"),
+ DataSet(IptcDataSets::Contact, "Contact", "Person or organisation to
contact", false, true, 0, 128, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Caption, "Caption", "Content description",
false, false, 0, 2000, Exiv2::string, IptcDataSets::application2,
"Description"),
+ DataSet(IptcDataSets::Writer, "Writer", "Person responsible for
caption", false, true, 0, 32, Exiv2::string, IptcDataSets::application2,
"Description writer"),
+ DataSet(IptcDataSets::RasterizedCaption, "RasterizedCaption", "Black
and white caption image", false, false, 7360, 7360, Exiv2::undefined,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ImageType, "ImageType", "Color components in an
image", false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::ImageOrientation, "ImageOrientation", "Indicates
the layout of an image", false, false, 1, 1, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Language, "Language", "ISO 639:1988 language
code", false, false, 2, 3, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::AudioType, "AudioType", "Information about audio
content", false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::AudioRate, "AudioRate", "Sampling rate of audio
content", false, false, 6, 6, Exiv2::string, IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::AudioResolution, "AudioResolution", "Sampling
resolution of audio content", false, false, 2, 2, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::AudioDuration, "AudioDuration", "Duration of
audio content", false, false, 6, 6, Exiv2::string, IptcDataSets::application2,
""),
+ DataSet(IptcDataSets::AudioOutcue, "AudioOutcue", "Final words or
sounds of audio content", false, false, 0, 64, Exiv2::string,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::PreviewFormat, "PreviewFormat", "IIM appendix A
file format of preview", false, false, 2, 2, Exiv2::unsignedShort,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::PreviewVersion, "PreviewVersion", "File format
version of preview", false, false, 2, 2, Exiv2::unsignedShort,
IptcDataSets::application2, ""),
+ DataSet(IptcDataSets::Preview, "Preview", "Binary preview data",
false, false, 0, 256000, Exiv2::undefined, IptcDataSets::application2, ""),
+ DataSet(0xffff, "(Invalid)", "(Invalid)", false, false, 0, 0,
Exiv2::unsignedShort, IptcDataSets::application2, "")
+ };
+
+ static const DataSet unknownDataSet(0xffff, "Unknown dataset", "Unknown
dataset", false, true, 0, 0xffffffff, Exiv2::string,
IptcDataSets::invalidRecord, "Unknown dataset");
+
+ // Dataset lookup lists.This is an array with pointers to one list per
IIM4 Record.
+ // The record id is used as the index into the array.
+ const DataSet* IptcDataSets::records_[] = {
+ 0,
+ envelopeRecord, application2Record,
+ 0
+ };
+
+ int IptcDataSets::dataSetIdx(uint16_t number, uint16_t recordId)
+ {
+ if( recordId != envelope && recordId != application2 ) return -1;
+ const DataSet* dataSet = records_[recordId];
+ if (dataSet == 0) return -1;
+ int idx;
+ for (idx = 0; dataSet[idx].number_ != number; ++idx) {
+ if (dataSet[idx].number_ == 0xffff) return -1;
+ }
+ return idx;
+ }
+
+ int IptcDataSets::dataSetIdx(const std::string& dataSetName, uint16_t
recordId)
+ {
+ if( recordId != envelope && recordId != application2 ) return -1;
+ const DataSet* dataSet = records_[recordId];
+ if (dataSet == 0) return -1;
+ int idx;
+ for (idx = 0; dataSet[idx].name_ != dataSetName; ++idx) {
+ if (dataSet[idx].number_ == 0xffff) return -1;
+ }
+ return idx;
+ }
+
+ TypeId IptcDataSets::dataSetType(uint16_t number, uint16_t recordId)
+ {
+ int idx = dataSetIdx(number, recordId);
+ if (idx == -1) return unknownDataSet.type_;
+ return records_[recordId][idx].type_;
+ }
+
+ std::string IptcDataSets::dataSetName(uint16_t number, uint16_t recordId)
+ {
+ int idx = dataSetIdx(number, recordId);
+ if (idx != -1) return records_[recordId][idx].name_;
+
+ std::ostringstream os;
+ os << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << number;
+ return os.str();
+ }
+
+ const char* IptcDataSets::dataSetDesc(uint16_t number, uint16_t recordId)
+ {
+ int idx = dataSetIdx(number, recordId);
+ if (idx == -1) return unknownDataSet.desc_;
+ return records_[recordId][idx].desc_;
+ }
+
+ const char* IptcDataSets::dataSetPsName(uint16_t number, uint16_t recordId)
+ {
+ int idx = dataSetIdx(number, recordId);
+ if (idx == -1) return unknownDataSet.photoshop_;
+ return records_[recordId][idx].photoshop_;
+ }
+
+ bool IptcDataSets::dataSetRepeatable(uint16_t number, uint16_t recordId)
+ {
+ int idx = dataSetIdx(number, recordId);
+ if (idx == -1) return unknownDataSet.repeatable_;
+ return records_[recordId][idx].repeatable_;
+ }
+
+ uint16_t IptcDataSets::dataSet(const std::string& dataSetName,
+ uint16_t recordId)
+ {
+ uint16_t dataSet;
+ int idx = dataSetIdx(dataSetName, recordId);
+ if (idx != -1) {
+ // dataSetIdx checks the range of recordId
+ dataSet = records_[recordId][idx].number_;
+ }
+ else {
+ if (!isHex(dataSetName, 4, "0x")) throw Error(4, dataSetName);
+ std::istringstream is(dataSetName);
+ is >> std::hex >> dataSet;
+ }
+ return dataSet;
+ }
+
+ std::string IptcDataSets::recordName(uint16_t recordId)
+ {
+ if (recordId == envelope || recordId == application2) {
+ return recordInfo_[recordId].name_;
+ }
+
+ std::ostringstream os;
+ os << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << recordId;
+ return os.str();
+ }
+
+ const char* IptcDataSets::recordDesc(uint16_t recordId)
+ {
+ if (recordId != envelope && recordId != application2) {
+ return unknownDataSet.desc_;
+ }
+ return recordInfo_[recordId].desc_;
+ }
+
+ uint16_t IptcDataSets::recordId(const std::string& recordName)
+ {
+ uint16_t i;
+ for (i = application2; i > 0; --i) {
+ if (recordInfo_[i].name_ == recordName) break;
+ }
+ if (i == 0) {
+ if (!isHex(recordName, 4, "0x")) throw Error(5, recordName);
+ std::istringstream is(recordName);
+ is >> std::hex >> i;
+ }
+ return i;
+ }
+
+ void IptcDataSets::dataSetList(std::ostream& os)
+ {
+ const int count = sizeof(records_)/sizeof(records_[0]);
+ for (int i=0; i < count; ++i) {
+ const DataSet *record = records_[i];
+ for (int j=0; record != 0 && record[j].number_ != 0xffff; ++j) {
+ os << record[j] << "\n";
+ }
+ }
+ } // IptcDataSets::dataSetList
+
+ const char* IptcKey::familyName_ = "Iptc";
+
+ IptcKey::IptcKey(const std::string& key)
+ : key_(key)
+ {
+ decomposeKey();
+ }
+
+ IptcKey::IptcKey(uint16_t tag, uint16_t record)
+ : tag_(tag), record_(record)
+ {
+ makeKey();
+ }
+
+ IptcKey::IptcKey(const IptcKey& rhs)
+ : tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_)
+ {
+ }
+
+ IptcKey& IptcKey::operator=(const IptcKey& rhs)
+ {
+ if (this == &rhs) return *this;
+ Key::operator=(rhs);
+ tag_ = rhs.tag_;
+ record_ = rhs.record_;
+ key_ = rhs.key_;
+ return *this;
+ }
+
+ IptcKey::AutoPtr IptcKey::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ IptcKey* IptcKey::clone_() const
+ {
+ return new IptcKey(*this);
+ }
+
+ void IptcKey::decomposeKey()
+ {
+ // Get the family name, record name and dataSet name parts of the key
+ std::string::size_type pos1 = key_.find('.');
+ if (pos1 == std::string::npos) throw Error(6, key_);
+ std::string familyName = key_.substr(0, pos1);
+ if (familyName != std::string(familyName_)) {
+ throw Error(6, key_);
+ }
+ std::string::size_type pos0 = pos1 + 1;
+ pos1 = key_.find('.', pos0);
+ if (pos1 == std::string::npos) throw Error(6, key_);
+ std::string recordName = key_.substr(pos0, pos1 - pos0);
+ if (recordName == "") throw Error(6, key_);
+ std::string dataSetName = key_.substr(pos1 + 1);
+ if (dataSetName == "") throw Error(6, key_);
+
+ // Use the parts of the key to find dataSet and recordId
+ uint16_t recId = IptcDataSets::recordId(recordName);
+ uint16_t dataSet = IptcDataSets::dataSet(dataSetName, recId);
+
+ // Possibly translate hex name parts (0xabcd) to real names
+ recordName = IptcDataSets::recordName(recId);
+ dataSetName = IptcDataSets::dataSetName(dataSet, recId);
+
+ tag_ = dataSet;
+ record_ = recId;
+ key_ = familyName + "." + recordName + "." + dataSetName;
+ } // IptcKey::decomposeKey
+
+ void IptcKey::makeKey()
+ {
+ key_ = std::string(familyName_)
+ + "." + IptcDataSets::recordName(record_)
+ + "." + IptcDataSets::dataSetName(tag_, record_);
+ }
+
+ //
*************************************************************************
+ // free functions
+
+ std::ostream& operator<<(std::ostream& os, const DataSet& dataSet)
+ {
+ IptcKey iptcKey(dataSet.number_, dataSet.recordId_);
+ return os << dataSet.name_ << ", "
+ << std::dec << dataSet.number_ << ", "
+ << "0x" << std::setw(4) << std::setfill('0')
+ << std::right << std::hex << dataSet.number_ << ", "
+ << IptcDataSets::recordName(dataSet.recordId_) << ", "
+ << std::boolalpha << dataSet.mandatory_ << ", "
+ << dataSet.repeatable_ << ", "
+ << std::dec << dataSet.minbytes_ << ", "
+ << dataSet.maxbytes_ << ", "
+ << iptcKey.key() << ", "
+ << TypeInfo::typeName(
+ IptcDataSets::dataSetType(dataSet.number_,
+ dataSet.recordId_)) << ", "
+ << dataSet.desc_;
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/datasets.hpp
===================================================================
--- Extractor/src/plugins/exiv2/datasets.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/datasets.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,358 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file datasets.hpp
+ @brief Iptc dataSet and type information
+ @version $Rev: 560 $
+ @author Brad Schick (brad) <address@hidden>
+ @date 24-Jul-04, brad: created
+ */
+#ifndef DATASETS_HPP_
+#define DATASETS_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "metadatum.hpp"
+
+// + standard includes
+#include <string>
+#include <utility> // for std::pair
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ //! Contains information about one record
+ struct RecordInfo {
+ //! Constructor
+ RecordInfo(uint16_t recordId, const char* name, const char* desc);
+ uint16_t recordId_; //!< Record id
+ const char* name_; //!< Record name (one word)
+ const char* desc_; //!< Record description
+ };
+
+ //! Dataset information
+ struct DataSet {
+ //! Constructor
+ DataSet(
+ uint16_t number,
+ const char* name,
+ const char* desc,
+ bool mandatory,
+ bool repeatable,
+ uint32_t minbytes,
+ uint32_t maxbytes,
+ TypeId type,
+ uint16_t recordId,
+ const char* photoshop
+ );
+ uint16_t number_; //!< Dataset number
+ const char* name_; //!< Dataset name
+ const char* desc_; //!< Dataset description
+ bool mandatory_; //!< True if dataset is
mandatory
+ bool repeatable_; //!< True if dataset is
repeatable
+ uint32_t minbytes_; //!< Minimum number of bytes
+ uint32_t maxbytes_; //!< Maximum number of bytes
+ TypeId type_; //!< Exiv2 default type
+ uint16_t recordId_; //!< Record id
+ const char* photoshop_; //!< Photoshop string
+ }; // struct DataSet
+
+ //! Container for Iptc dataset information. Implemented as a static class.
+ class IptcDataSets {
+ public:
+ /*!
+ @name Record identifiers
+ @brief Record identifiers to logically group dataSets. There are
other
+ possible record types, but they are not standardized by the
Iptc
+ IIM4 standard (and not commonly used in images).
+ */
+ //@{
+ static const uint16_t invalidRecord = 0;
+ static const uint16_t envelope = 1;
+ static const uint16_t application2 = 2;
+ //@}
+
+ //! @name Dataset identifiers
+ //@{
+ static const uint16_t ModelVersion = 0;
+ static const uint16_t Destination = 5;
+ static const uint16_t FileFormat = 20;
+ static const uint16_t FileVersion = 22;
+ static const uint16_t ServiceId = 30;
+ static const uint16_t EnvelopeNumber = 40;
+ static const uint16_t ProductId = 50;
+ static const uint16_t EnvelopePriority = 60;
+ static const uint16_t DateSent = 70;
+ static const uint16_t TimeSent = 80;
+ static const uint16_t CharacterSet = 90;
+ static const uint16_t UNO = 100;
+ static const uint16_t ARMId = 120;
+ static const uint16_t ARMVersion = 122;
+ static const uint16_t RecordVersion = 0;
+ static const uint16_t ObjectType = 3;
+ static const uint16_t ObjectAttribute = 4;
+ static const uint16_t ObjectName = 5;
+ static const uint16_t EditStatus = 7;
+ static const uint16_t EditorialUpdate = 8;
+ static const uint16_t Urgency = 10;
+ static const uint16_t Subject = 12;
+ static const uint16_t Category = 15;
+ static const uint16_t SuppCategory = 20;
+ static const uint16_t FixtureId = 22;
+ static const uint16_t Keywords = 25;
+ static const uint16_t LocationCode = 26;
+ static const uint16_t LocationName = 27;
+ static const uint16_t ReleaseDate = 30;
+ static const uint16_t ReleaseTime = 35;
+ static const uint16_t ExpirationDate = 37;
+ static const uint16_t ExpirationTime = 38;
+ static const uint16_t SpecialInstructions = 40;
+ static const uint16_t ActionAdvised = 42;
+ static const uint16_t ReferenceService = 45;
+ static const uint16_t ReferenceDate = 47;
+ static const uint16_t ReferenceNumber = 50;
+ static const uint16_t DateCreated = 55;
+ static const uint16_t TimeCreated = 60;
+ static const uint16_t DigitizationDate = 62;
+ static const uint16_t DigitizationTime = 63;
+ static const uint16_t Program = 65;
+ static const uint16_t ProgramVersion = 70;
+ static const uint16_t ObjectCycle = 75;
+ static const uint16_t Byline = 80;
+ static const uint16_t BylineTitle = 85;
+ static const uint16_t City = 90;
+ static const uint16_t SubLocation = 92;
+ static const uint16_t ProvinceState = 95;
+ static const uint16_t CountryCode = 100;
+ static const uint16_t CountryName = 101;
+ static const uint16_t TransmissionReference = 103;
+ static const uint16_t Headline = 105;
+ static const uint16_t Credit = 110;
+ static const uint16_t Source = 115;
+ static const uint16_t Copyright = 116;
+ static const uint16_t Contact = 118;
+ static const uint16_t Caption = 120;
+ static const uint16_t Writer = 122;
+ static const uint16_t RasterizedCaption = 125;
+ static const uint16_t ImageType = 130;
+ static const uint16_t ImageOrientation = 131;
+ static const uint16_t Language = 135;
+ static const uint16_t AudioType = 150;
+ static const uint16_t AudioRate = 151;
+ static const uint16_t AudioResolution = 152;
+ static const uint16_t AudioDuration = 153;
+ static const uint16_t AudioOutcue = 154;
+ static const uint16_t PreviewFormat = 200;
+ static const uint16_t PreviewVersion = 201;
+ static const uint16_t Preview = 202;
+ //@}
+
+ private:
+ //! Prevent construction: not implemented.
+ IptcDataSets() {}
+ //! Prevent copy-construction: not implemented.
+ IptcDataSets(const IptcDataSets& rhs);
+ //! Prevent assignment: not implemented.
+ IptcDataSets& operator=(const IptcDataSets& rhs);
+
+ public:
+ /*!
+ @brief Return the name of the dataset.
+ @param number The dataset number
+ @param recordId The Iptc record Id
+ @return The name of the dataset or a string containing the
hexadecimal
+ value of the dataset in the form "0x01ff", if this is an
unknown
+ dataset.
+ */
+ static std::string dataSetName(uint16_t number, uint16_t recordId);
+ /*!
+ @brief Return the description of the dataset.
+ @param number The dataset number
+ @param recordId The Iptc record Id
+ @return The description of the dataset
+ */
+ static const char* dataSetDesc(uint16_t number, uint16_t recordId);
+ /*!
+ @brief Return the photohsop name of a given dataset.
+ @param number The dataset number
+ @param recordId The Iptc record Id
+ @return The name used by photoshop for a dataset or an empty
+ string if photoshop does not use the dataset.
+ */
+ static const char* dataSetPsName(uint16_t number, uint16_t recordId);
+ /*!
+ @brief Check if a given dataset is repeatable
+ @param number The dataset number
+ @param recordId The Iptc record Id
+ @return true if the given dataset is repeatable otherwise false
+ */
+ static bool dataSetRepeatable(uint16_t number, uint16_t recordId);
+ /*!
+ @brief Return the dataSet number for dataset name and record id
+
+ @param dataSetName dataSet name
+ @param recordId recordId
+
+ @return dataSet number
+
+ @throw Error if the \em dataSetName or \em recordId are invalid
+ */
+ static uint16_t dataSet(const std::string& dataSetName, uint16_t
recordId);
+ //! Return the type for dataSet number and Record id
+ static TypeId dataSetType(uint16_t number, uint16_t recordId);
+ /*!
+ @brief Return the name of the Record
+ @param recordId The record id
+ @return The name of the record or a string containing the hexadecimal
+ value of the record in the form "0x01ff", if this is an
+ unknown record.
+ */
+ static std::string recordName(uint16_t recordId);
+ /*!
+ @brief Return the description of a record
+ @param recordId Record Id number
+ @return the description of the Record
+ */
+ static const char* recordDesc(uint16_t recordId);
+ /*!
+ @brief Return the Id number of a record
+ @param recordName Name of a record type
+ @return the Id number of a Record
+ @throw Error if the record is not known;
+ */
+ static uint16_t recordId(const std::string& recordName);
+ //! Print a list of all dataSets to output stream
+ static void dataSetList(std::ostream& os);
+
+ private:
+ static int dataSetIdx(uint16_t number, uint16_t recordId);
+ static int dataSetIdx(const std::string& dataSetName, uint16_t
recordId);
+
+ static const DataSet* records_[];
+ static const RecordInfo recordInfo_[];
+
+ }; // class IptcDataSets
+
+ /*!
+ @brief Concrete keys for Iptc metadata.
+ */
+ class IptcKey : public Key {
+ public:
+ //! Shortcut for an %IptcKey auto pointer.
+ typedef std::auto_ptr<IptcKey> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor to create an Iptc key from a key string.
+
+ @param key The key string.
+ @throw Error if the first part of the key is not '<b>Iptc</b>' or
+ the remaining parts of the key cannot be parsed and
+ converted to a record name and a dataset name.
+ */
+ explicit IptcKey(const std::string& key);
+ /*!
+ @brief Constructor to create an Iptc key from dataset and record ids.
+ @param tag Dataset id
+ @param record Record id
+ */
+ IptcKey(uint16_t tag, uint16_t record);
+ //! Copy constructor
+ IptcKey(const IptcKey& rhs);
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Assignment operator.
+ */
+ IptcKey& operator=(const IptcKey& rhs);
+ //@}
+
+ //! @name Accessors
+ //@{
+ virtual std::string key() const { return key_; }
+ virtual const char* familyName() const { return familyName_; }
+ /*!
+ @brief Return the name of the group (the second part of the key).
+ For Iptc keys, the group name is the record name.
+ */
+ virtual std::string groupName() const { return recordName(); }
+ virtual std::string tagName() const
+ { return IptcDataSets::dataSetName(tag_, record_); }
+ virtual uint16_t tag() const { return tag_; }
+
+ AutoPtr clone() const;
+ //! Return the name of the record
+ std::string recordName() const
+ { return IptcDataSets::recordName(record_); }
+ //! Return the record id
+ uint16_t record() const { return record_; }
+ //@}
+
+ protected:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Set the key corresponding to the dataset and record id.
+ The key is of the form '<b>Iptc</b>.recordName.dataSetName'.
+ */
+ void makeKey();
+ /*!
+ @brief Parse and convert the key string into dataset and record id.
+ Updates data members if the string can be decomposed, or
throws
+ \em Error.
+
+ @throw Error if the key cannot be decomposed.
+ */
+ void decomposeKey();
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual IptcKey* clone_() const;
+
+ // DATA
+ static const char* familyName_;
+
+ uint16_t tag_; //!< Tag value
+ uint16_t record_; //!< Record value
+ std::string key_; //!< Key
+
+ }; // class IptcKey
+
+//
*****************************************************************************
+// free functions
+
+ //! Output operator for dataSet
+ std::ostream& operator<<(std::ostream& os, const DataSet& dataSet);
+
+} // namespace Exiv2
+
+#endif // #ifndef DATASETS_HPP_
Added: Extractor/src/plugins/exiv2/doxygen.hpp
===================================================================
--- Extractor/src/plugins/exiv2/doxygen.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/doxygen.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,133 @@
+// ***************************************************************** -*- C++
-*-
+/*!
+ @file doxygen.hpp
+ @brief Additional documentation, this file contains no source code
+ @version $Rev: 581 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 07-Feb-04, ahu: created
+ */
+/*!
+ @mainpage Exif and Iptc metadata manipulation library and tools v0.7
+
+ @section overview Exiv2 Overview
+
+ %Exiv2 comprises of a C++ library and a command line utility to access image
+ metadata. %Exiv2 is free software. The homepage of %Exiv2 is at
+ <A
HREF="http://home.arcor.de/ahuggel/exiv2">http://home.arcor.de/ahuggel/exiv2</A>.
+
+ The %Exiv2 library provides
+ - full read and write access to the Exif and Iptc metadata of an image
through
+ %Exiv2 keys and standard C++ iterators
+ - a smart Iptc implementation that does not effect data that programs like
+ Photoshop store in the same image segment
+ - Exif %MakerNote support:
+ - %MakerNote tags can be accessed just like any other Exif metadata
+ - a sophisticated write algorithm avoids corrupting the %MakerNote:
+ <br> 1) the %MakerNote is not re-located if possible at all,
and
+ <br> 2) %MakerNote %Ifd offsets are re-calculated if the
+ %MakerNote needs to be moved (for known %Ifd
%MakerNotes)
+ - new camera make/model specific %MakerNotes can be added to the library
with
+ minimum effort in OO-fashion (by subclassing %MakerNote or %IfdMakerNote)
+ - extract and delete methods for Exif thumbnails (both, Jpeg and Tiff
thumbnails)
+ - set methods for Exif thumbnails (Jpeg only, Tiff thumbnails can be set
from
+ individual tags)
+ - complete API documentation (by Doxygen)
+ - generic lower-level classes to access %Ifd (%Image File Directory) data
+ structures
+
+ @section getting-started Getting started
+
+ <A HREF="getting-started.html">A few pointers</A> to get you started with
+ the %Exiv2 library without delay.
+
+ @section metadata Supported Exif and MakerNote tags and Iptc datasets
+
+ - <A HREF="tags-exif.html">Standard Exif tags</A>
+ - <A HREF="tags-canon.html">Canon MakerNote tags</A>
+ - <A HREF="tags-fujifilm.html">Fujifilm MakerNote tags</A>
+ - <A HREF="tags-nikon.html">Nikon MakerNote tags</A>
+ - <A HREF="tags-olympus.html">Olympus MakerNote tags</A>
+ - <A HREF="tags-panasonic.html">Panasonic MakerNote tags</A>
+ - <A HREF="tags-sigma.html">Sigma/Foveon MakerNote tags</A>
+ - <A HREF="tags-sony.html">Sony MakerNote tags</A>
+ - <A HREF="tags-iptc.html">Iptc datasets</A>
+
+ @section makernote MakerNote Formats and Specifications
+
+ A summary of <A HREF="makernote.html">MakerNote structures</A> with links to
+ publicly available specifications.
+
+ @section supp Support
+
+ <p>There is now a
+ <a title="Exiv2 forum" href="http://uk.groups.yahoo.com/group/exiv2">Yahoo!
group for Exiv2 help and discussions</a>.</p>
+ <p><a title="Join the Exiv2 forum"
href="http://uk.groups.yahoo.com/group/exiv2/join">Join the group</a> to post
and receive messages or use <em><a title="Post to the Exiv2 forum"
href="http://uk.groups.yahoo.com/group/exiv2/post">exiv2user/password</a></em>
to post anonymously. Bug reports can be submitted directly to the
+<a title="Issue tracker" href="http://dev.robotbattle.com/bugs/main_page.php"
+
onclick="document.images['tracker'].src='http://www.whatcounter.com/dlcount.php?id=ahu&url='+this.href">
+bug tracking system</a>.</p>
+
+ @section devel Development
+
+ <p>%Exiv2 is maintained in a publicly available subversion repository.
+ There is a <a title="Last 50 commits"
href="http://dev.robotbattle.com/cmtinfo_svn.php?r=10">
+ live list with the latest commits</a> to the repository, and you can
+ <a title="Online source code repository"
href="http://dev.robotbattle.com/~cvsuser/cgi-bin/ns_viewcvs.cgi/exiv2/trunk/">
+ browse the source code</a> online.
+ </p>
+ <p>To check-out the current source code from the repository, you need a
+ <a title="Get Subversion!"
+ href="http://subversion.tigris.org/project_packages.html">subversion
client</a>.
+ If you use a command line client, change to the directory where you want to
keep
+ the source code and type:</p>
+
+ @verbatim $ svn checkout svn://dev.robotbattle.com/exiv2/trunk . @endverbatim
+
+ <p>To download the test data and test drivers for version 0.7 from
+ the repository, change to your local exiv2-0.7 directory and use the
+ following command:
+ </p>
+
+ @verbatim $ svn export svn://dev.robotbattle.com/exiv2/tags/0.7/test
@endverbatim
+
+ <P>If you'd like to contribute code, please <A
HREF="mailto:address@hidden">contact me</A>.
+
+ @section license License
+
+ <P>Copyright (C) 2004, 2005 Andreas Huggel <address@hidden></P>
+
+ <P>%Exiv2 is free software; you can redistribute it and/or modify it under
the
+ terms of the <a href="gpl-license.html">GNU General Public License</a> as
+ published by the Free Software Foundation; either version 2 of the License,
or
+ (at your option) any later version.</P>
+
+ <P>%Exiv2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.</P>
+
+ <P>You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.</P>
+
+*/
+/*!
+ @example addmoddel.cpp
+ Sample usage of high-level metadata operations.
+ */
+/*!
+ @example exifprint.cpp
+ Sample program to print Exif data from an image.
+ */
+/*!
+ @example exifcomment.cpp
+ Sample program showing how to set the Exif comment of an image.
+ */
+/*!
+ @example iptcprint.cpp
+ Sample program to print the Iptc metadata of an image
+ */
+/*!
+ @example iptceasy.cpp
+ The quickest way to access, set or modify Iptc metadata
+ */
Added: Extractor/src/plugins/exiv2/error.cpp
===================================================================
--- Extractor/src/plugins/exiv2/error.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/error.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,121 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: error.cpp
+ Version: $Rev: 563 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 02-Apr-05, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: error.cpp 563 2005-04-21 07:21:53Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "error.hpp"
+
+// + standard includes
+#include <string>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ const ErrMsg Error::errMsg_[] = {
+ ErrMsg( -1, "Error %0: arg1=%1, arg2=%2, arg3=%3."),
+ ErrMsg( 0, "Success"),
+ ErrMsg( 1, "%1"), // %1=error message
+
+ ErrMsg( 2, "%1: %2 (%3)"), // %1=path, %2=strerror, %3=function that
failed
+ // ErrMsg( 3, ""),
+
+ ErrMsg( 4, "Invalid dataset name `%1'"), // %1=dataset name
+ ErrMsg( 5, "Invalid record name `%1'"), // %1=record name
+ ErrMsg( 6, "Invalid key `%1'"), // %1=key
+ ErrMsg( 7, "Invalid tag name or ifdId `%1', ifdId %2"), // %1=tag
name, %2=ifdId
+ ErrMsg( 8, "Value not set"),
+ ErrMsg( 9, "%1: Failed to open the data source: %2"), // %1=path,
%2=strerror
+ ErrMsg( 10, "%1: Failed to open file (%2): %3"), // %1=path, %2=mode,
%3=strerror
+ ErrMsg( 11, "%1: The file contains data of an unknown image type"), //
%1=path
+ ErrMsg( 12, "The memory contains data of an unknown image type"),
+ ErrMsg( 13, "Image type %1 is not supported"), // %1=image type
+ ErrMsg( 14, "Failed to read image data"),
+ ErrMsg( 15, "This does not look like a JPEG image"),
+ ErrMsg( 16, "MakerTagInfo registry full"),
+ ErrMsg( 17, "%1: Failed to rename file to %2: %3"), // %1=old path,
%2=new path, %3=strerror
+ ErrMsg( 18, "%1: Transfer failed: %2"), // %1=path, %2=strerror
+ ErrMsg( 19, "Memory transfer failed: %1"), // %1=strerror
+ ErrMsg( 20, "Failed to read input data"),
+ ErrMsg( 21, "Failed to write image"),
+ ErrMsg( 22, "Input data does not contain a valid image"),
+ ErrMsg( 23, "Failed to create Makernote for ifdId %1"), // %1=ifdId
+ ErrMsg( 24, "Entry::setValue: Value too large (tag=%1, size=%2,
requested=%3)"), // %1=tag, %2=dataSize, %3=required size
+ ErrMsg( 25, "Entry::setDataArea: Value too large (tag=%1, size=%2,
requested=%3)"), // %1=tag, %2=dataAreaSize, %3=required size
+ ErrMsg( 26, "Offset out of range"),
+ ErrMsg( 27, "Unsupported data area offset type"),
+ ErrMsg( 28, "Invalid charset: `%1'"), // %1=charset name
+ ErrMsg( 29, "Unsupported date format"),
+ ErrMsg( 30, "Unsupported time format"),
+
+ // Last error message (message is not used)
+ ErrMsg( -2, "(Unknown Error)")
+ };
+
+ int Error::errorIdx(int code)
+ {
+ int idx;
+ for (idx = 0; errMsg_[idx].code_ != code; ++idx) {
+ if (errMsg_[idx].code_ == -2) return 0;
+ }
+ return idx;
+ }
+
+ std::string Error::what() const
+ {
+ int idx = errorIdx(code_);
+ std::string msg = std::string(errMsg_[idx].message_);
+ std::string::size_type pos;
+ pos = msg.find("%0");
+ if (pos != std::string::npos) {
+ msg.replace(pos, 2, toString(code_));
+ }
+ if (count_ > 0) {
+ pos = msg.find("%1");
+ if (pos != std::string::npos) {
+ msg.replace(pos, 2, arg1_);
+ }
+ }
+ if (count_ > 1) {
+ pos = msg.find("%2");
+ if (pos != std::string::npos) {
+ msg.replace(pos, 2, arg2_);
+ }
+ }
+ if (count_ > 2) {
+ pos = msg.find("%3");
+ if (pos != std::string::npos) {
+ msg.replace(pos, 2, arg3_);
+ }
+ }
+ return msg;
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/error.hpp
===================================================================
--- Extractor/src/plugins/exiv2/error.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/error.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,148 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file error.hpp
+ @brief Error class for exceptions
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 15-Jan-04, ahu: created<BR>
+ 11-Feb-04, ahu: isolated as a component
+ */
+#ifndef ERROR_HPP_
+#define ERROR_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ //! Helper structure defining an error message
+ struct ErrMsg {
+ //! Constructor
+ ErrMsg(int code, const char* message)
+ : code_(code), message_(message)
+ {
+ }
+ int code_; //!< Error code
+ const char* message_; //!< Error message
+ };
+
+ /*!
+ @brief Error class interface. Allows the definition and use of a
hierarchy
+ of error classes which can all be handled in one catch block.
+ */
+ class AnyError {
+ public:
+ //! @name Creators
+ //@{
+ //! Virtual destructor.
+ virtual ~AnyError()
+ {
+ }
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Return the error code.
+ virtual int code() const =0;
+ /*!
+ @brief Return the error message. Consider using the output operator
+ operator<<(std::ostream &os, const AnyError& error) instead.
+ @note Unlike std::exception::what(), this function returns an
+ std::string.
+ */
+ virtual std::string what() const =0;
+ }; // AnyError
+
+ //! %AnyBase output operator
+ inline std::ostream& operator<<(std::ostream& os, const AnyError& error)
+ {
+ return os << error.what();
+ }
+
+ /*!
+ @brief Simple error class used for exceptions. An output operator is
+ provided to print errors to a stream.
+ */
+ class Error : public AnyError {
+ public:
+ //! @name Creators
+ //@{
+ //! Constructor taking only an error code
+ explicit Error(int code)
+ : code_(code), count_(0)
+ {
+ }
+ //! Constructor taking an error code and one argument
+ template<typename A>
+ Error(int code, const A& arg1)
+ : code_(code), count_(1), arg1_(toString(arg1))
+ {
+ }
+ //! Constructor taking an error code and two arguments
+ template<typename A, typename B>
+ Error(int code, const A& arg1, const B& arg2)
+ : code_(code), count_(2),
+ arg1_(toString(arg1)), arg2_(toString(arg2))
+ {
+ }
+ //! Constructor taking an error code and three arguments
+ template<typename A, typename B, typename C>
+ Error(int code, const A& arg1, const B& arg2, const C& arg3)
+ : code_(code), count_(3),
+ arg1_(toString(arg1)), arg2_(toString(arg2)),
arg3_(toString(arg3))
+ {
+ }
+ //@}
+
+ //! @name Accessors
+ //@{
+ virtual int code() const { return code_; }
+ virtual std::string what() const;
+ //@}
+
+ private:
+ static int errorIdx(int code);
+
+ // DATA
+ int code_; //!< Error code
+ int count_; //!< Number of arguments
+ std::string arg1_; //!< First argument
+ std::string arg2_; //!< Second argument
+ std::string arg3_; //!< Third argument
+
+ static const ErrMsg errMsg_[]; //!< List of error messages
+ }; // class Error
+
+} // namespace Exiv2
+
+#endif // #ifndef ERROR_HPP_
Added: Extractor/src/plugins/exiv2/exif.cpp
===================================================================
--- Extractor/src/plugins/exiv2/exif.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exif.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,1230 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: exif.cpp
+ Version: $Rev: 569 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: exif.cpp 569 2005-05-28 05:48:43Z ahuggel $");
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr, e.g, by
+// calling make like this: make DEFS=-DDEBUG_MAKERNOTE exif.o
+//#define DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "exif.hpp"
+#include "types.hpp"
+#include "basicio.hpp"
+#include "error.hpp"
+#include "value.hpp"
+#include "ifd.hpp"
+#include "tags.hpp"
+#include "jpgimage.hpp"
+#include "makernote.hpp"
+#include "futils.hpp"
+
+// + standard includes
+#include <iostream>
+#include <sstream>
+#include <utility>
+#include <algorithm>
+#include <map>
+#include <cstring>
+#include <cassert>
+#include <cstdio>
+#include <sys/types.h> // for stat()
+#include <sys/stat.h> // for stat()
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // for stat()
+#endif
+
+//
*****************************************************************************
+// local declarations
+namespace {
+
+ /*
+ Set the data of the entry identified by tag in ifd to an unsigned long
+ with the value of offset. If no entry with this tag exists in ifd, an
+ entry of type unsigned long with one component is created.
+ */
+ void setOffsetTag(Exiv2::Ifd& ifd,
+ int idx,
+ uint16_t tag,
+ uint32_t offset,
+ Exiv2::ByteOrder byteOrder);
+
+ // Read file path into a DataBuf, which is returned.
+ Exiv2::DataBuf readFile(const std::string& path);
+
+}
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder)
+ : key_(ExifKey::AutoPtr(new ExifKey(e)))
+ {
+ setValue(e, byteOrder);
+ }
+
+ Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue)
+ : key_(key.clone())
+ {
+ if (pValue) value_ = pValue->clone();
+ }
+
+ Exifdatum::~Exifdatum()
+ {
+ }
+
+ Exifdatum::Exifdatum(const Exifdatum& rhs)
+ : Metadatum(rhs)
+ {
+ if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
+ if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
+ }
+
+ Exifdatum& Exifdatum::operator=(const Exifdatum& rhs)
+ {
+ if (this == &rhs) return *this;
+ Metadatum::operator=(rhs);
+
+ key_.reset();
+ if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
+
+ value_.reset();
+ if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
+
+ return *this;
+ } // Exifdatum::operator=
+
+ Exifdatum& Exifdatum::operator=(const std::string& value)
+ {
+ setValue(value);
+ return *this;
+ }
+
+ Exifdatum& Exifdatum::operator=(const uint16_t& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const uint32_t& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const URational& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const int16_t& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const int32_t& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const Rational& value)
+ {
+ return Exiv2::setValue(*this, value);
+ }
+
+ Exifdatum& Exifdatum::operator=(const Value& value)
+ {
+ setValue(&value);
+ return *this;
+ }
+
+ void Exifdatum::setValue(const Value* pValue)
+ {
+ value_.reset();
+ if (pValue) value_ = pValue->clone();
+ }
+
+ void Exifdatum::setValue(const Entry& e, ByteOrder byteOrder)
+ {
+ value_ = Value::create(TypeId(e.type()));
+ value_->read(e.data(), e.count() * e.typeSize(), byteOrder);
+ value_->setDataArea(e.dataArea(), e.sizeDataArea());
+ }
+
+ void Exifdatum::setValue(const std::string& value)
+ {
+ if (value_.get() == 0) {
+ TypeId type = ExifTags::tagType(tag(), ifdId());
+ value_ = Value::create(type);
+ }
+ value_->read(value);
+ }
+
+ int TiffThumbnail::setDataArea(ExifData& exifData, Ifd* pIfd1,
+ const byte* buf, long len) const
+ {
+ // Create a DataBuf that can hold all strips
+ ExifData::const_iterator sizes;
+ ExifKey key("Exif.Thumbnail.StripByteCounts");
+ sizes = exifData.findKey(key);
+ if (sizes == exifData.end()) return 2;
+
+ long totalSize = 0;
+ for (long i = 0; i < sizes->count(); ++i) {
+ totalSize += sizes->toLong(i);
+ }
+ DataBuf stripsBuf(totalSize);
+
+ // Copy all strips into the data buffer. For each strip remember its
+ // offset from the start of the data buffer
+ ExifData::iterator stripOffsets;
+ key = ExifKey("Exif.Thumbnail.StripOffsets");
+ stripOffsets = exifData.findKey(key);
+ if (stripOffsets == exifData.end()) return 2;
+ if (stripOffsets->count() != sizes->count()) return 2;
+
+ std::ostringstream os; // for the strip offsets
+ long currentOffset = 0;
+ long firstOffset = stripOffsets->toLong(0);
+ long lastOffset = 0;
+ long lastSize = 0;
+ for (long i = 0; i < stripOffsets->count(); ++i) {
+ long offset = stripOffsets->toLong(i);
+ lastOffset = offset;
+ long size = sizes->toLong(i);
+ lastSize = size;
+ if (len < offset + size) return 1;
+
+ memcpy(stripsBuf.pData_ + currentOffset, buf + offset, size);
+ os << currentOffset << " ";
+ currentOffset += size;
+ }
+
+ // Set StripOffsets data area and relative offsets
+ stripOffsets->setDataArea(stripsBuf.pData_, stripsBuf.size_);
+ stripOffsets->setValue(os.str());
+
+ // Set corresponding data area at IFD1, if it is a contiguous area
+ if (pIfd1 && firstOffset + totalSize == lastOffset + lastSize) {
+ Ifd::iterator pos = pIfd1->findTag(0x0111);
+ assert(pos != pIfd1->end());
+ pos->setDataArea(buf + firstOffset, totalSize);
+ }
+
+ return 0;
+ } // TiffThumbnail::read
+
+ const char* TiffThumbnail::format() const
+ {
+ return "TIFF";
+ }
+
+ const char* TiffThumbnail::extension() const
+ {
+ return ".tif";
+ }
+
+ DataBuf TiffThumbnail::copy(const ExifData& exifData) const
+ {
+ // Create a TIFF header and IFD1
+ TiffHeader tiffHeader(exifData.byteOrder());
+ Ifd ifd1(ifd1Id);
+
+ // Populate IFD (without Exif and GPS tags) from metadata
+ addToIfd(ifd1, exifData.begin(), exifData.end(), exifData.byteOrder());
+ ifd1.erase(0x8769);
+ ifd1.erase(0x8825);
+ ifd1.sortByTag();
+
+ long size = tiffHeader.size() + ifd1.size() + ifd1.dataSize();
+ DataBuf buf(size);
+ long len = tiffHeader.copy(buf.pData_);
+ len += ifd1.copy(buf.pData_ + len, exifData.byteOrder(), len);
+ assert(len == size);
+ return buf;
+ }
+
+ int JpegThumbnail::setDataArea(ExifData& exifData, Ifd* pIfd1,
+ const byte* buf, long len) const
+ {
+ ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");
+ ExifData::iterator format = exifData.findKey(key);
+ if (format == exifData.end()) return 1;
+ long offset = format->toLong();
+ key = ExifKey("Exif.Thumbnail.JPEGInterchangeFormatLength");
+ ExifData::const_iterator length = exifData.findKey(key);
+ if (length == exifData.end()) return 1;
+ long size = length->toLong();
+ if (len < offset + size) return 2;
+ format->setDataArea(buf + offset, size);
+ format->setValue("0");
+ if (pIfd1) {
+ Ifd::iterator pos = pIfd1->findTag(0x0201);
+ assert(pos != pIfd1->end());
+ pos->setDataArea(buf + offset, size);
+ }
+ return 0;
+ } // JpegThumbnail::setDataArea
+
+ const char* JpegThumbnail::format() const
+ {
+ return "JPEG";
+ }
+
+ const char* JpegThumbnail::extension() const
+ {
+ return ".jpg";
+ }
+
+ DataBuf JpegThumbnail::copy(const ExifData& exifData) const
+ {
+ ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");
+ ExifData::const_iterator format = exifData.findKey(key);
+ if (format == exifData.end()) return DataBuf();
+ return format->dataArea();
+ }
+
+ ExifData::ExifData()
+ : pTiffHeader_(0),
+ pIfd0_(0), pExifIfd_(0), pIopIfd_(0), pGpsIfd_(0), pIfd1_(0),
+ pMakerNote_(0), size_(0), pData_(0), compatible_(true)
+ {
+ }
+
+ ExifData::ExifData(const ExifData& rhs)
+ : exifMetadata_(rhs.exifMetadata_), pTiffHeader_(0),
+ pIfd0_(0), pExifIfd_(0), pIopIfd_(0), pGpsIfd_(0), pIfd1_(0),
+ pMakerNote_(0), size_(0), pData_(0), compatible_(rhs.compatible_)
+ {
+ pData_ = new byte[rhs.size_];
+ size_ = rhs.size_;
+ memcpy(pData_, rhs.pData_, rhs.size_);
+
+ if (rhs.pTiffHeader_) {
+ pTiffHeader_ = new TiffHeader(*rhs.pTiffHeader_);
+ }
+ if (rhs.pIfd0_) {
+ pIfd0_ = new Ifd(*rhs.pIfd0_);
+ pIfd0_->updateBase(pData_);
+ }
+ if (rhs.pExifIfd_) {
+ pExifIfd_ = new Ifd(*rhs.pExifIfd_);
+ pExifIfd_->updateBase(pData_);
+ }
+ if (rhs.pIopIfd_) {
+ pIopIfd_ = new Ifd(*rhs.pIopIfd_);
+ pIopIfd_->updateBase(pData_);
+ }
+ if (rhs.pGpsIfd_) {
+ pGpsIfd_ = new Ifd(*rhs.pGpsIfd_);
+ pGpsIfd_->updateBase(pData_);
+ }
+ if (rhs.pIfd1_) {
+ pIfd1_ = new Ifd(*rhs.pIfd1_);
+ pIfd1_->updateBase(pData_);
+ }
+ if (rhs.pMakerNote_) {
+ pMakerNote_ = rhs.pMakerNote_->clone().release();
+ pMakerNote_->updateBase(pData_);
+ }
+ }
+
+ ExifData::~ExifData()
+ {
+ delete pTiffHeader_;
+ delete pIfd0_;
+ delete pExifIfd_;
+ delete pIopIfd_;
+ delete pGpsIfd_;
+ delete pIfd1_;
+ delete pMakerNote_;
+ delete[] pData_;
+ }
+
+ ExifData& ExifData::operator=(const ExifData& rhs)
+ {
+ if (this == &rhs) return *this;
+
+ exifMetadata_ = rhs.exifMetadata_;
+
+ size_ = 0;
+ delete[] pData_;
+ pData_ = new byte[rhs.size_];
+ size_ = rhs.size_;
+ memcpy(pData_, rhs.pData_, rhs.size_);
+
+ delete pTiffHeader_;
+ pTiffHeader_ = 0;
+ if (rhs.pTiffHeader_) {
+ pTiffHeader_ = new TiffHeader(*rhs.pTiffHeader_);
+ }
+ delete pIfd0_;
+ pIfd0_ = 0;
+ if (rhs.pIfd0_) {
+ pIfd0_ = new Ifd(*rhs.pIfd0_);
+ pIfd0_->updateBase(pData_);
+ }
+ delete pExifIfd_;
+ pExifIfd_ = 0;
+ if (rhs.pExifIfd_) {
+ pExifIfd_ = new Ifd(*rhs.pExifIfd_);
+ pExifIfd_->updateBase(pData_);
+ }
+ delete pIopIfd_;
+ pIopIfd_ = 0;
+ if (rhs.pIopIfd_) {
+ pIopIfd_ = new Ifd(*rhs.pIopIfd_);
+ pIopIfd_->updateBase(pData_);
+ }
+ delete pGpsIfd_;
+ pGpsIfd_ = 0;
+ if (rhs.pGpsIfd_) {
+ pGpsIfd_ = new Ifd(*rhs.pGpsIfd_);
+ pGpsIfd_->updateBase(pData_);
+ }
+ delete pIfd1_;
+ pIfd1_ = 0;
+ if (rhs.pIfd1_) {
+ pIfd1_ = new Ifd(*rhs.pIfd1_);
+ pIfd1_->updateBase(pData_);
+ }
+ delete pMakerNote_;
+ pMakerNote_ = 0;
+ if (rhs.pMakerNote_) {
+ pMakerNote_ = rhs.pMakerNote_->clone().release();
+ pMakerNote_->updateBase(pData_);
+ }
+
+ compatible_ = rhs.compatible_;
+ return *this;
+ }
+
+ Exifdatum& ExifData::operator[](const std::string& key)
+ {
+ ExifKey exifKey(key);
+ iterator pos = findKey(exifKey);
+ if (pos == end()) {
+ add(Exifdatum(exifKey));
+ pos = findKey(exifKey);
+ }
+ return *pos;
+ }
+
+ int ExifData::load(const byte* buf, long len)
+ {
+ // Copy the data buffer
+ delete[] pData_;
+ pData_ = new byte[len];
+ memcpy(pData_, buf, len);
+ size_ = len;
+
+ // Read the TIFF header
+ delete pTiffHeader_;
+ pTiffHeader_ = new TiffHeader;
+ assert(pTiffHeader_ != 0);
+ int rc = pTiffHeader_->read(pData_);
+ if (rc) return rc;
+
+ // Read IFD0
+ delete pIfd0_;
+ pIfd0_ = new Ifd(ifd0Id, 0, false);
+ assert(pIfd0_ != 0);
+ rc = pIfd0_->read(pData_ + pTiffHeader_->offset(),
+ size_ - pTiffHeader_->offset(),
+ byteOrder(),
+ pTiffHeader_->offset());
+ if (rc) return rc;
+
+ delete pExifIfd_;
+ pExifIfd_ = new Ifd(exifIfdId, 0, false);
+ assert(pExifIfd_ != 0);
+ // Find and read ExifIFD sub-IFD of IFD0
+ rc = pIfd0_->readSubIfd(*pExifIfd_, pData_, size_, byteOrder(),
0x8769);
+ if (rc) return rc;
+ // Find MakerNote in ExifIFD, create a MakerNote class
+ Ifd::iterator pos = pExifIfd_->findTag(0x927c);
+ Ifd::iterator make = pIfd0_->findTag(0x010f);
+ Ifd::iterator model = pIfd0_->findTag(0x0110);
+ if ( pos != pExifIfd_->end()
+ && make != pIfd0_->end() && model != pIfd0_->end()) {
+ // Todo: The conversion to string assumes that there is a \0 at
the end
+ // Todo: How to avoid the cast (is that a MSVC thing?)
+ pMakerNote_ = MakerNoteFactory::create(
+ reinterpret_cast<const char*>(make->data()),
+ reinterpret_cast<const char*>(model->data()),
+ false,
+ pos->data(),
+ pos->size(),
+ byteOrder(),
+ pExifIfd_->offset() + pos->offset()).release();
+ }
+ // Read the MakerNote
+ if (pMakerNote_) {
+ rc = pMakerNote_->read(pos->data(),
+ pos->size(),
+ byteOrder(),
+ pExifIfd_->offset() + pos->offset());
+ if (rc) {
+ // Todo: How to handle debug output like this
+ std::cerr << "Warning: Failed to read Makernote, rc = "
+ << rc << "\n";
+ delete pMakerNote_;
+ pMakerNote_ = 0;
+ }
+ }
+ // If we successfully parsed the MakerNote, delete the raw MakerNote,
+ // the parsed MakerNote is the primary MakerNote from now on
+ if (pMakerNote_) {
+ pExifIfd_->erase(pos);
+ }
+
+ delete pIopIfd_;
+ pIopIfd_ = new Ifd(iopIfdId, 0, false);
+ assert(pIopIfd_ != 0);
+ // Find and read Interoperability IFD in ExifIFD
+ rc = pExifIfd_->readSubIfd(*pIopIfd_, pData_, size_, byteOrder(),
0xa005);
+ if (rc) return rc;
+
+ delete pGpsIfd_;
+ pGpsIfd_ = new Ifd(gpsIfdId, 0, false);
+ assert(pGpsIfd_ != 0);
+ // Find and read GPSInfo sub-IFD in IFD0
+ rc = pIfd0_->readSubIfd(*pGpsIfd_, pData_, size_, byteOrder(), 0x8825);
+ if (rc) return rc;
+
+ delete pIfd1_;
+ pIfd1_ = new Ifd(ifd1Id, 0, false);
+ assert(pIfd1_ != 0);
+ // Read IFD1
+ if (pIfd0_->next()) {
+ rc = pIfd1_->read(pData_ + pIfd0_->next(),
+ size_ - pIfd0_->next(),
+ byteOrder(),
+ pIfd0_->next());
+ if (rc) return rc;
+ }
+ // Find and delete ExifIFD sub-IFD of IFD1
+ pos = pIfd1_->findTag(0x8769);
+ if (pos != pIfd1_->end()) {
+ pIfd1_->erase(pos);
+ rc = 7;
+ }
+ // Find and delete GPSInfo sub-IFD in IFD1
+ pos = pIfd1_->findTag(0x8825);
+ if (pos != pIfd1_->end()) {
+ pIfd1_->erase(pos);
+ rc = 7;
+ }
+ // Copy all entries from the IFDs and the MakerNote to the metadata
+ exifMetadata_.clear();
+ add(pIfd0_->begin(), pIfd0_->end(), byteOrder());
+ add(pExifIfd_->begin(), pExifIfd_->end(), byteOrder());
+ if (pMakerNote_) {
+ add(pMakerNote_->begin(), pMakerNote_->end(),
+ (pMakerNote_->byteOrder() == invalidByteOrder ?
+ byteOrder() : pMakerNote_->byteOrder()));
+ }
+ add(pIopIfd_->begin(), pIopIfd_->end(), byteOrder());
+ add(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder());
+ add(pIfd1_->begin(), pIfd1_->end(), byteOrder());
+ // Read the thumbnail (but don't worry whether it was successful or
not)
+ readThumbnail();
+
+ return rc;
+ } // ExifData::load
+
+
+ DataBuf ExifData::copy()
+ {
+ DataBuf buf;
+ // If we can update the internal IFDs and the underlying data buffer
+ // from the metadata without changing the data size, then it is enough
+ // to copy the data buffer.
+ if (compatible_ && updateEntries()) {
+#ifdef DEBUG_MAKERNOTE
+ std::cerr << "->>>>>> using non-intrusive writing <<<<<<-\n";
+#endif
+ buf.alloc(size_);
+ memcpy(buf.pData_, pData_, size_);
+ }
+ // Else we have to do it the hard way...
+ else {
+#ifdef DEBUG_MAKERNOTE
+ std::cerr << "->>>>>> writing from metadata <<<<<<-\n";
+#endif
+ buf = copyFromMetadata();
+ }
+ return buf;
+ }
+
+ DataBuf ExifData::copyFromMetadata()
+ {
+ // Build IFD0
+ Ifd ifd0(ifd0Id);
+ addToIfd(ifd0, begin(), end(), byteOrder());
+
+ // Build Exif IFD from metadata
+ Ifd exifIfd(exifIfdId);
+ addToIfd(exifIfd, begin(), end(), byteOrder());
+ MakerNote::AutoPtr makerNote;
+ if (pMakerNote_) {
+ // Build MakerNote from metadata
+ makerNote = pMakerNote_->create();
+ addToMakerNote(makerNote.get(),
+ begin(), end(),
+ (pMakerNote_->byteOrder() == invalidByteOrder ?
+ byteOrder() : pMakerNote_->byteOrder()));
+ // Create a placeholder MakerNote entry of the correct size and
+ // add it to the Exif IFD (because we don't know the offset yet)
+ Entry e;
+ e.setIfdId(exifIfd.ifdId());
+ e.setTag(0x927c);
+ DataBuf tmpBuf(makerNote->size());
+ memset(tmpBuf.pData_, 0x0, tmpBuf.size_);
+ e.setValue(undefined, tmpBuf.size_, tmpBuf.pData_, tmpBuf.size_);
+ exifIfd.erase(0x927c);
+ exifIfd.add(e);
+ }
+
+ // Build Interoperability IFD from metadata
+ Ifd iopIfd(iopIfdId);
+ addToIfd(iopIfd, begin(), end(), byteOrder());
+
+ // Build GPSInfo IFD from metadata
+ Ifd gpsIfd(gpsIfdId);
+ addToIfd(gpsIfd, begin(), end(), byteOrder());
+
+ // build IFD1 from metadata
+ Ifd ifd1(ifd1Id);
+ addToIfd(ifd1, begin(), end(), byteOrder());
+ // Set a temporary dummy offset in IFD0
+ if (ifd1.size() > 0) {
+ ifd0.setNext(1, byteOrder());
+ }
+
+ // Compute the new IFD offsets
+ int exifIdx = ifd0.erase(0x8769);
+ int gpsIdx = ifd0.erase(0x8825);
+ int iopIdx = exifIfd.erase(0xa005);
+
+ TiffHeader tiffHeader(byteOrder());
+ long ifd0Offset = tiffHeader.size();
+ bool addOffsetTag = false;
+ long exifIfdOffset = ifd0Offset + ifd0.size() + ifd0.dataSize();
+ if (exifIfd.size() > 0 || iopIfd.size() > 0) {
+ exifIfdOffset += 12;
+ addOffsetTag = true;
+ }
+ if (gpsIfd.size() > 0) {
+ exifIfdOffset += 12;
+ addOffsetTag = true;
+ }
+ if (ifd0.size() == 0 && addOffsetTag) {
+ exifIfdOffset += 6;
+ }
+ addOffsetTag = false;
+ long iopIfdOffset = exifIfdOffset + exifIfd.size() +
exifIfd.dataSize();
+ if (iopIfd.size() > 0) {
+ iopIfdOffset += 12;
+ addOffsetTag = true;
+ }
+ if (exifIfd.size() == 0 && addOffsetTag) {
+ iopIfdOffset += 6;
+ }
+ long gpsIfdOffset = iopIfdOffset + iopIfd.size() + iopIfd.dataSize();
+ long ifd1Offset = gpsIfdOffset + gpsIfd.size() + gpsIfd.dataSize();
+
+ // Set the offset to IFD1 in IFD0
+ if (ifd1.size() > 0) {
+ ifd0.setNext(ifd1Offset, byteOrder());
+ }
+
+ // Set the offset to the Exif IFD in IFD0
+ if (exifIfd.size() > 0 || iopIfd.size() > 0) {
+ setOffsetTag(ifd0, exifIdx, 0x8769, exifIfdOffset, byteOrder());
+ }
+ // Set the offset to the GPSInfo IFD in IFD0
+ if (gpsIfd.size() > 0) {
+ setOffsetTag(ifd0, gpsIdx, 0x8825, gpsIfdOffset, byteOrder());
+ }
+ // Set the offset to the Interoperability IFD in Exif IFD
+ if (iopIfd.size() > 0) {
+ setOffsetTag(exifIfd, iopIdx, 0xa005, iopIfdOffset, byteOrder());
+ }
+
+ // Allocate a data buffer big enough for all metadata
+ long size = tiffHeader.size();
+ size += ifd0.size() + ifd0.dataSize();
+ size += exifIfd.size() + exifIfd.dataSize();
+ size += iopIfd.size() + iopIfd.dataSize();
+ size += gpsIfd.size() + gpsIfd.dataSize();
+ size += ifd1.size() + ifd1.dataSize();
+ DataBuf buf(size);
+
+ // Copy the TIFF header, all IFDs, MakerNote and thumbnail to the
buffer
+ size = tiffHeader.copy(buf.pData_);
+ ifd0.sortByTag();
+ size += ifd0.copy(buf.pData_ + ifd0Offset, byteOrder(), ifd0Offset);
+ exifIfd.sortByTag();
+ size += exifIfd.copy(buf.pData_ + exifIfdOffset, byteOrder(),
exifIfdOffset);
+ if (makerNote.get() != 0) {
+ // Copy the MakerNote over the placeholder data
+ Entries::iterator mn = exifIfd.findTag(0x927c);
+ // Do _not_ sort the makernote; vendors (at least Canon), don't
seem
+ // to bother about this TIFF standard requirement, so writing the
+ // makernote as is might result in fewer deviations from the
original
+ makerNote->copy(buf.pData_ + exifIfdOffset + mn->offset(),
+ byteOrder(),
+ exifIfdOffset + mn->offset());
+ }
+ iopIfd.sortByTag();
+ size += iopIfd.copy(buf.pData_ + iopIfdOffset, byteOrder(),
iopIfdOffset);
+ gpsIfd.sortByTag();
+ size += gpsIfd.copy(buf.pData_ + gpsIfdOffset, byteOrder(),
gpsIfdOffset);
+ ifd1.sortByTag();
+ size += ifd1.copy(buf.pData_ + ifd1Offset, byteOrder(), ifd1Offset);
+ assert(size == buf.size_);
+ return buf;
+ } // ExifData::copyFromMetadata
+
+ void ExifData::add(Entries::const_iterator begin,
+ Entries::const_iterator end,
+ ByteOrder byteOrder)
+ {
+ Entries::const_iterator i = begin;
+ for (; i != end; ++i) {
+ add(Exifdatum(*i, byteOrder));
+ }
+ }
+
+ void ExifData::add(const ExifKey& key, const Value* pValue)
+ {
+ add(Exifdatum(key, pValue));
+ }
+
+ void ExifData::add(const Exifdatum& exifdatum)
+ {
+ if (ExifTags::isMakerIfd(exifdatum.ifdId())) {
+ if (pMakerNote_ == 0) {
+ pMakerNote_ =
MakerNoteFactory::create(exifdatum.ifdId()).release();
+ }
+ if (pMakerNote_ == 0) throw Error(23, exifdatum.ifdId());
+ }
+ // allow duplicates
+ exifMetadata_.push_back(exifdatum);
+ }
+
+ ExifData::const_iterator ExifData::findKey(const ExifKey& key) const
+ {
+ return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
+ FindMetadatumByKey(key.key()));
+ }
+
+ ExifData::iterator ExifData::findKey(const ExifKey& key)
+ {
+ return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
+ FindMetadatumByKey(key.key()));
+ }
+
+ ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const
+ {
+ return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
+ FindMetadatumByIfdIdIdx(ifdId, idx));
+ }
+
+ ExifData::iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx)
+ {
+ return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
+ FindMetadatumByIfdIdIdx(ifdId, idx));
+ }
+
+ void ExifData::sortByKey()
+ {
+ std::sort(exifMetadata_.begin(), exifMetadata_.end(),
cmpMetadataByKey);
+ }
+
+ void ExifData::sortByTag()
+ {
+ std::sort(exifMetadata_.begin(), exifMetadata_.end(),
cmpMetadataByTag);
+ }
+
+ ExifData::iterator ExifData::erase(ExifData::iterator pos)
+ {
+ return exifMetadata_.erase(pos);
+ }
+
+ void ExifData::setJpegThumbnail(const byte* buf, long size)
+ {
+ (*this)["Exif.Thumbnail.Compression"] = uint16_t(6);
+ Exifdatum& format = (*this)["Exif.Thumbnail.JPEGInterchangeFormat"];
+ format = uint32_t(0);
+ format.setDataArea(buf, size);
+ (*this)["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size);
+ }
+
+ void ExifData::setJpegThumbnail(const byte* buf, long size,
+ URational xres, URational yres, uint16_t
unit)
+ {
+ setJpegThumbnail(buf, size);
+ (*this)["Exif.Thumbnail.XResolution"] = xres;
+ (*this)["Exif.Thumbnail.YResolution"] = yres;
+ (*this)["Exif.Thumbnail.ResolutionUnit"] = unit;
+ }
+
+ void ExifData::setJpegThumbnail(const std::string& path)
+ {
+ DataBuf thumb = readFile(path); // may throw
+ setJpegThumbnail(thumb.pData_, thumb.size_);
+ }
+
+ void ExifData::setJpegThumbnail(const std::string& path,
+ URational xres, URational yres, uint16_t
unit)
+ {
+ DataBuf thumb = readFile(path); // may throw
+ setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit);
+ }
+
+ long ExifData::eraseThumbnail()
+ {
+ // First, determine if the thumbnail is at the end of the Exif data
+ bool stp = stdThumbPosition();
+ // Delete all Exif.Thumbnail.* (IFD1) metadata
+ ExifMetadata::iterator i = begin();
+ while (i != end()) {
+ if (i->ifdId() == ifd1Id) {
+ i = erase(i);
+ }
+ else {
+ ++i;
+ }
+ }
+ long delta = 0;
+ if (stp) {
+ delta = size_;
+ if (size_ > 0 && pIfd0_ && pIfd0_->next() > 0) {
+ // Truncate IFD1 and thumbnail data from the data buffer
+ size_ = pIfd0_->next();
+ pIfd0_->setNext(0, byteOrder());
+ if (pIfd1_) pIfd1_->clear();
+ }
+ delta -= size_;
+ }
+ else {
+ // We will have to write the hard way and re-arrange the data
+ compatible_ = false;
+ if (pIfd1_) delta = pIfd1_->size() + pIfd1_->dataSize();
+ }
+ return delta;
+ } // ExifData::eraseThumbnail
+
+ bool ExifData::stdThumbPosition() const
+ {
+ if ( pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0
+ || pGpsIfd_ == 0 || pIfd1_ == 0) return true;
+
+ // Todo: There is still an invalid assumption here: The data of an IFD
+ // can be stored in multiple non-contiguous blocks. In this case,
+ // dataOffset + dataSize does not point to the end of the IFD
data.
+ // in particular, this is potentially the case for the remaining
Exif
+ // data in the presence of a known Makernote.
+ bool rc = true;
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get()) {
+ long maxOffset;
+ maxOffset = std::max(pIfd0_->offset(), pIfd0_->dataOffset());
+ maxOffset = std::max(maxOffset, pExifIfd_->offset());
+ maxOffset = std::max(maxOffset, pExifIfd_->dataOffset()
+ + pExifIfd_->dataSize());
+ if (pMakerNote_) {
+ maxOffset = std::max(maxOffset, pMakerNote_->offset()
+ + pMakerNote_->size());
+ }
+ maxOffset = std::max(maxOffset, pIopIfd_->offset());
+ maxOffset = std::max(maxOffset, pIopIfd_->dataOffset()
+ + pIopIfd_->dataSize());
+ maxOffset = std::max(maxOffset, pGpsIfd_->offset());
+ maxOffset = std::max(maxOffset, pGpsIfd_->dataOffset()
+ + pGpsIfd_->dataSize());
+
+ if ( maxOffset > pIfd1_->offset()
+ || maxOffset > pIfd1_->dataOffset() && pIfd1_->dataOffset() >
0)
+ rc = false;
+ /*
+ Todo: Removed condition from the above if(). Should be
re-added...
+ || maxOffset > pThumbnail_->offset()
+ */
+ }
+ return rc;
+ } // ExifData::stdThumbPosition
+
+ ByteOrder ExifData::byteOrder() const
+ {
+ if (pTiffHeader_) return pTiffHeader_->byteOrder();
+ return littleEndian;
+ }
+
+ int ExifData::writeThumbnail(const std::string& path) const
+ {
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get() == 0) return 8;
+
+ std::string name = path + thumbnail->extension();
+ FileIo file(name);
+ if (file.open("wb") != 0) {
+ throw Error(10, name, "wb", strError());
+ }
+
+ DataBuf buf(thumbnail->copy(*this));
+ if (file.write(buf.pData_, buf.size_) != buf.size_) {
+ throw Error(2, name, strError(), "FileIo::write");
+ }
+
+ return 0;
+ } // ExifData::writeThumbnail
+
+ DataBuf ExifData::copyThumbnail() const
+ {
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get() == 0) return DataBuf();
+ return thumbnail->copy(*this);
+ }
+
+ const char* ExifData::thumbnailFormat() const
+ {
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get() == 0) return "";
+ return thumbnail->format();
+ }
+
+ const char* ExifData::thumbnailExtension() const
+ {
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get() == 0) return "";
+ return thumbnail->extension();
+ }
+
+ Thumbnail::AutoPtr ExifData::getThumbnail() const
+ {
+ Thumbnail::AutoPtr thumbnail;
+ const_iterator pos = findKey(ExifKey("Exif.Thumbnail.Compression"));
+ if (pos != end()) {
+ long compression = pos->toLong();
+ if (compression == 6) {
+ thumbnail = Thumbnail::AutoPtr(new JpegThumbnail);
+ }
+ else {
+ thumbnail = Thumbnail::AutoPtr(new TiffThumbnail);
+ }
+ }
+ return thumbnail;
+
+ } // ExifData::getThumbnail
+
+ int ExifData::readThumbnail()
+ {
+ int rc = -1;
+ Thumbnail::AutoPtr thumbnail = getThumbnail();
+ if (thumbnail.get() != 0) {
+ rc = thumbnail->setDataArea(*this, pIfd1_, pData_, size_);
+ }
+ return rc;
+
+ } // ExifData::readThumbnail
+
+ bool ExifData::updateEntries()
+ {
+ if ( pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0
+ || pGpsIfd_ == 0 || pIfd1_ == 0) return false;
+ if (!this->compatible()) return false;
+
+ bool compatible = true;
+ compatible &= updateRange(pIfd0_->begin(), pIfd0_->end(), byteOrder());
+ compatible &= updateRange(pExifIfd_->begin(), pExifIfd_->end(),
byteOrder());
+ if (pMakerNote_) {
+ compatible &= updateRange(pMakerNote_->begin(),
+ pMakerNote_->end(),
+ (pMakerNote_->byteOrder() ==
invalidByteOrder ?
+ byteOrder() :
pMakerNote_->byteOrder()));
+ }
+ compatible &= updateRange(pIopIfd_->begin(), pIopIfd_->end(),
byteOrder());
+ compatible &= updateRange(pGpsIfd_->begin(), pGpsIfd_->end(),
byteOrder());
+ compatible &= updateRange(pIfd1_->begin(), pIfd1_->end(), byteOrder());
+
+ return compatible;
+ } // ExifData::updateEntries
+
+ bool ExifData::updateRange(const Entries::iterator& begin,
+ const Entries::iterator& end,
+ ByteOrder byteOrder)
+ {
+ bool compatible = true;
+ for (Entries::iterator entry = begin; entry != end; ++entry) {
+ // find the corresponding Exifdatum
+ const_iterator md = findIfdIdIdx(entry->ifdId(), entry->idx());
+ if (md == this->end()) {
+ // corresponding Exifdatum was deleted: this is not (yet) a
+ // supported non-intrusive write operation.
+ compatible = false;
+ continue;
+ }
+ if (entry->count() == 0 && md->count() == 0) {
+ // Special case: don't do anything if both the entry and
+ // Exifdatum have no data. This is to preserve the original
+ // data in the offset field of an IFD entry with count 0,
+ // if the Exifdatum was not changed.
+ }
+ else if ( entry->size() < md->size()
+ || entry->sizeDataArea() < md->sizeDataArea()) {
+ compatible = false;
+ continue;
+ }
+ else {
+ // Hack: Set the entry's value only if there is no data area.
+ // This ensures that the original offsets are not overwritten
+ // with relative offsets from the Exifdatum (which require
+ // conversion to offsets relative to the start of the TIFF
+ // header and that is currently only done in intrusive write
+ // mode). On the other hand, it is thus now not possible to
+ // change the offsets of an entry with a data area in
+ // non-intrusive mode. This can be considered a bug.
+ // Todo: Fix me!
+ if (md->sizeDataArea() == 0) {
+ DataBuf buf(md->size());
+ md->copy(buf.pData_, byteOrder);
+ entry->setValue(static_cast<uint16_t>(md->typeId()),
+ md->count(),
+ buf.pData_, md->size());
+ }
+ // Always set the data area
+ DataBuf dataArea(md->dataArea());
+ entry->setDataArea(dataArea.pData_, dataArea.size_);
+ }
+ }
+ return compatible;
+ } // ExifData::updateRange
+
+ bool ExifData::compatible() const
+ {
+ bool compatible = true;
+ // For each Exifdatum, check if it is compatible with the corresponding
+ // IFD or MakerNote entry
+ for (const_iterator md = begin(); md != this->end(); ++md) {
+ std::pair<bool, Entries::const_iterator> rc;
+ rc = findEntry(md->ifdId(), md->idx());
+ // Make sure that we have an entry
+ if (!rc.first) {
+ compatible = false;
+ break;
+ }
+ // Make sure that the size of the Exifdatum fits the available size
+ // of the entry
+ if ( md->size() > rc.second->size()
+ || md->sizeDataArea() > rc.second->sizeDataArea()) {
+ compatible = false;
+ break;
+ }
+ }
+ return compatible;
+ } // ExifData::compatible
+
+ std::pair<bool, Entries::const_iterator>
+ ExifData::findEntry(IfdId ifdId, int idx) const
+ {
+ Entries::const_iterator entry;
+ std::pair<bool, Entries::const_iterator> rc(false, entry);
+
+ if (ExifTags::isMakerIfd(ifdId) && pMakerNote_) {
+ entry = pMakerNote_->findIdx(idx);
+ if (entry != pMakerNote_->end()) {
+ rc.first = true;
+ rc.second = entry;
+ }
+ return rc;
+ }
+ const Ifd* ifd = getIfd(ifdId);
+ if (ifd && isExifIfd(ifdId)) {
+ entry = ifd->findIdx(idx);
+ if (entry != ifd->end()) {
+ rc.first = true;
+ rc.second = entry;
+ }
+ }
+ return rc;
+ } // ExifData::findEntry
+
+ const Ifd* ExifData::getIfd(IfdId ifdId) const
+ {
+ const Ifd* ifd = 0;
+ switch (ifdId) {
+ case ifd0Id:
+ ifd = pIfd0_;
+ break;
+ case exifIfdId:
+ ifd = pExifIfd_;
+ break;
+ case iopIfdId:
+ ifd = pIopIfd_;
+ break;
+ case gpsIfdId:
+ ifd = pGpsIfd_;
+ break;
+ case ifd1Id:
+ ifd = pIfd1_;
+ break;
+ default:
+ ifd = 0;
+ break;
+ }
+ return ifd;
+ } // ExifData::getIfd
+
+ //
*************************************************************************
+ // free functions
+
+ void addToIfd(Ifd& ifd,
+ ExifMetadata::const_iterator begin,
+ ExifMetadata::const_iterator end,
+ ByteOrder byteOrder)
+ {
+ for (ExifMetadata::const_iterator i = begin; i != end; ++i) {
+ // add only metadata with matching IFD id
+ if (i->ifdId() == ifd.ifdId()) {
+ addToIfd(ifd, *i, byteOrder);
+ }
+ }
+ } // addToIfd
+
+ void addToIfd(Ifd& ifd, const Exifdatum& md, ByteOrder byteOrder)
+ {
+ assert(ifd.alloc());
+
+ Entry e;
+ e.setIfdId(md.ifdId());
+ e.setIdx(md.idx());
+ e.setTag(md.tag());
+ e.setOffset(0); // will be calculated when the IFD is written
+
+ DataBuf buf(md.size());
+ md.copy(buf.pData_, byteOrder);
+ e.setValue(static_cast<uint16_t>(md.typeId()), md.count(),
+ buf.pData_, buf.size_);
+
+ DataBuf dataArea(md.dataArea());
+ e.setDataArea(dataArea.pData_, dataArea.size_);
+
+ ifd.add(e);
+ } // addToIfd
+
+ void addToMakerNote(MakerNote* makerNote,
+ ExifMetadata::const_iterator begin,
+ ExifMetadata::const_iterator end,
+ ByteOrder byteOrder)
+ {
+ for (ExifMetadata::const_iterator i = begin; i != end; ++i) {
+ if (ExifTags::isMakerIfd(i->ifdId())) {
+ addToMakerNote(makerNote, *i, byteOrder);
+ }
+ }
+ } // addToMakerNote
+
+ void addToMakerNote(MakerNote* makerNote,
+ const Exifdatum& md,
+ ByteOrder byteOrder)
+ {
+ Entry e;
+ e.setIfdId(md.ifdId());
+ e.setIdx(md.idx());
+ e.setTag(md.tag());
+ e.setOffset(0); // will be calculated when the makernote is written
+
+ DataBuf buf(md.size());
+ md.copy(buf.pData_, byteOrder);
+ e.setValue(static_cast<uint16_t>(md.typeId()), md.count(),
+ buf.pData_, md.size());
+
+ DataBuf dataArea(md.dataArea());
+ e.setDataArea(dataArea.pData_, dataArea.size_);
+
+ makerNote->add(e);
+ } // addToMakerNote
+
+ std::ostream& operator<<(std::ostream& os, const Exifdatum& md)
+ {
+ return ExifTags::printTag(os, md.tag(), md.ifdId(), md.value());
+ }
+} // namespace Exiv2
+
+//
*****************************************************************************
+// local definitions
+namespace {
+
+ void setOffsetTag(Exiv2::Ifd& ifd,
+ int idx,
+ uint16_t tag,
+ uint32_t offset,
+ Exiv2::ByteOrder byteOrder)
+ {
+ Exiv2::Ifd::iterator pos = ifd.findTag(tag);
+ if (pos == ifd.end()) {
+ Exiv2::Entry e(ifd.alloc());
+ e.setIfdId(ifd.ifdId());
+ e.setIdx(idx);
+ e.setTag(tag);
+ e.setOffset(0); // will be calculated when the IFD is written
+ ifd.add(e);
+ pos = ifd.findTag(tag);
+ }
+ pos->setValue(offset, byteOrder);
+ }
+
+ Exiv2::DataBuf readFile(const std::string& path)
+ {
+ Exiv2::FileIo file(path);
+ if (file.open("rb") != 0) {
+ throw Exiv2::Error(10, path, "rb", Exiv2::strError());
+ }
+ struct stat st;
+ if (0 != stat(path.c_str(), &st)) {
+ throw Exiv2::Error(2, path, Exiv2::strError(), "::stat");
+ }
+ Exiv2::DataBuf buf(st.st_size);
+ long len = file.read(buf.pData_, buf.size_);
+ if (len != buf.size_) {
+ throw Exiv2::Error(2, path, Exiv2::strError(), "FileIo::read");
+ }
+ return buf;
+ }
+
+}
Added: Extractor/src/plugins/exiv2/exif.hpp
===================================================================
--- Extractor/src/plugins/exiv2/exif.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exif.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,909 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file exif.hpp
+ @brief Encoding and decoding of Exif data
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created
+ */
+#ifndef EXIF_HPP_
+#define EXIF_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "metadatum.hpp"
+#include "types.hpp"
+#include "error.hpp"
+#include "value.hpp"
+#include "ifd.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+/*!
+ @brief Provides classes and functions to encode and decode Exif and Iptc
data.
+ This namespace corresponds to the <b>libexiv2</b> library.
+
+ */
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class ExifData;
+ class MakerNote;
+ class TiffHeader;
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Information related to one Exif tag. An Exif metadatum consists of
+ an ExifKey and a Value and provides methods to manipulate these.
+ */
+ class Exifdatum : public Metadatum {
+ friend std::ostream& operator<<(std::ostream&, const Exifdatum&);
+ template<typename T> friend Exifdatum& setValue(Exifdatum&, const T&);
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor for new tags created by an application. The
+ %Exifdatum is created from a \em key / value pair. %Exifdatum
copies
+ (clones) the \em 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 an %Exifdatum value.
+ @throw Error if the key cannot be parsed and converted.
+ */
+ explicit Exifdatum(const ExifKey& key, const Value* pValue =0);
+ //! Constructor to build an %Exifdatum from an IFD entry.
+ Exifdatum(const Entry& e, ByteOrder byteOrder);
+ //! Copy constructor
+ Exifdatum(const Exifdatum& rhs);
+ //! Destructor
+ virtual ~Exifdatum();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator
+ Exifdatum& operator=(const Exifdatum& rhs);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to UShortValue.
+ */
+ Exifdatum& operator=(const uint16_t& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to ULongValue.
+ */
+ Exifdatum& operator=(const uint32_t& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to URationalValue.
+ */
+ Exifdatum& operator=(const URational& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to ShortValue.
+ */
+ Exifdatum& operator=(const int16_t& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to LongValue.
+ */
+ Exifdatum& operator=(const int32_t& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum. The type of the new Value
+ is set to RationalValue.
+ */
+ Exifdatum& operator=(const Rational& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum.
+ Calls setValue(const std::string&).
+ */
+ Exifdatum& operator=(const std::string& value);
+ /*!
+ @brief Assign \em value to the %Exifdatum.
+ Calls setValue(const Value*).
+ */
+ Exifdatum& operator=(const Value& value);
+ /*!
+ @brief Set the value. This method copies (clones) the value pointed
+ to by \em pValue.
+ */
+ void setValue(const Value* pValue);
+ /*!
+ @brief Set the value to the string \em value. Uses Value::read(const
+ std::string&). If the %Exifdatum does not have a Value yet,
+ then a %Value of the correct type for this %Exifdatum is
+ created. An AsciiValue is created for unknown tags.
+ */
+ void setValue(const std::string& value);
+ /*!
+ @brief Set the value from an IFD entry.
+ */
+ void setValue(const Entry& e, ByteOrder byteOrder);
+ /*!
+ @brief Set the data area by copying (cloning) the buffer pointed to
+ by \em buf.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to set such
+ a data area.
+
+ @param buf Pointer to the source data area
+ @param len Size of the data area
+ @return Return -1 if the %Exifdatum does not have a value yet or the
+ value has no data area, else 0.
+ */
+ int setDataArea(const byte* buf, long len)
+ { return value_.get() == 0 ? -1 : value_->setDataArea(buf, len); }
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Return the key of the %Exifdatum.
+ std::string key() const
+ { return key_.get() == 0 ? "" : key_->key(); }
+ //! Return the name of the group (the second part of the key)
+ std::string groupName() const
+ { return key_.get() == 0 ? "" : key_->groupName(); }
+ //! Return the name of the tag (which is also the third part of the
key)
+ std::string tagName() const
+ { return key_.get() == 0 ? "" : key_->tagName(); }
+ //! Return the tag
+ uint16_t tag() const
+ { return key_.get() == 0 ? 0xffff : key_->tag(); }
+ //! Return the IFD id
+ IfdId ifdId() const
+ { return key_.get() == 0 ? ifdIdNotSet : key_->ifdId(); }
+ //! Return the name of the IFD
+ const char* ifdName() const
+ { return key_.get() == 0 ? "" : key_->ifdName(); }
+ //! Return the related image item (deprecated)
+ std::string ifdItem() const
+ { return key_.get() == 0 ? "" : key_->ifdItem(); }
+ //! Return the index (unique id of this key within the original IFD)
+ int idx() const
+ { return key_.get() == 0 ? 0 : key_->idx(); }
+ /*!
+ @brief Write value to a data buffer and return the number
+ of bytes written.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return Number of characters written.
+ */
+ long copy(byte* buf, ByteOrder byteOrder) const
+ { return value_.get() == 0 ? 0 : value_->copy(buf, byteOrder); }
+ //! Return the type id of the value
+ TypeId typeId() const
+ { return value_.get() == 0 ? invalidTypeId : value_->typeId(); }
+ //! Return the name of the type
+ 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()); }
+ //! Return the number of components in the value
+ long count() const
+ { return value_.get() == 0 ? 0 : value_->count(); }
+ //! Return the size of the value in bytes
+ long size() const
+ { return value_.get() == 0 ? 0 : value_->size(); }
+ //! Return the value as a string.
+ std::string toString() const
+ { return value_.get() == 0 ? "" : value_->toString(); }
+ /*!
+ @brief Return the <EM>n</EM>-th component of the value converted to
+ long. The return value is -1 if the value of the Exifdatum is
+ not set and the behaviour of the method is undefined if there
+ is no n-th component.
+ */
+ long toLong(long n =0) const
+ { return value_.get() == 0 ? -1 : value_->toLong(n); }
+ /*!
+ @brief Return the <EM>n</EM>-th component of the value converted to
+ float. The return value is -1 if the value of the Exifdatum
is
+ not set and the behaviour of the method is undefined if there
+ is no n-th component.
+ */
+ float toFloat(long n =0) const
+ { return value_.get() == 0 ? -1 : value_->toFloat(n); }
+ /*!
+ @brief Return the <EM>n</EM>-th component of the value converted to
+ Rational. The return value is -1/1 if the value of the
+ Exifdatum is not set and the behaviour of the method is
+ undefined if there is no n-th component.
+ */
+ Rational toRational(long n =0) const
+ { return value_.get() == 0 ? Rational(-1, 1) :
value_->toRational(n); }
+ /*!
+ @brief Return an auto-pointer to a copy (clone) of the value. The
+ caller owns this copy and the auto-pointer ensures that it
will
+ be deleted.
+
+ This method is provided for users who need full control over the
+ value. A caller may, e.g., downcast the pointer to the appropriate
+ subclass of Value to make use of the interface of the subclass to set
+ or modify its contents.
+
+ @return An auto-pointer to a copy (clone) of the value, 0 if the
value
+ is not set.
+ */
+ Value::AutoPtr getValue() const
+ { return value_.get() == 0 ? Value::AutoPtr(0) : value_->clone(); }
+ /*!
+ @brief Return a constant reference to the value.
+
+ This method is provided mostly for convenient and versatile output of
+ the value which can (to some extent) be formatted through standard
+ stream manipulators. Do not attempt to write to the value through
+ this reference.
+
+ <b>Example:</b> <br>
+ @code
+ ExifData::const_iterator i = exifData.findKey(key);
+ if (i != exifData.end()) {
+ std::cout << i->key() << " " << std::hex << i->value() << "\n";
+ }
+ @endcode
+
+ @return A constant reference to the value.
+ @throw Error if the value is not set.
+ */
+ const Value& value() const
+ { if (value_.get() != 0) return *value_; throw Error(8); }
+ //! Return the size of the data area.
+ long sizeDataArea() const
+ { return value_.get() == 0 ? 0 : value_->sizeDataArea(); }
+ /*!
+ @brief Return a copy of the data area of the value. The caller owns
+ this copy and %DataBuf ensures that it will be deleted.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to access
+ such a data area.
+
+ @return A %DataBuf containing a copy of the data area or an empty
+ %DataBuf if the value does not have a data area assigned or
the
+ value is not set.
+ */
+ DataBuf dataArea() const
+ { return value_.get() == 0 ? DataBuf(0, 0) : value_->dataArea(); }
+
+ //@}
+
+ private:
+ // DATA
+ ExifKey::AutoPtr key_; //!< Key
+ Value::AutoPtr value_; //!< Value
+
+ }; // class Exifdatum
+
+ /*!
+ @brief Output operator for Exifdatum types, prints the interpreted
+ tag value.
+ */
+ std::ostream& operator<<(std::ostream& os, const Exifdatum& md);
+
+ /*!
+ @brief Set the value of \em exifDatum to \em value. If the object already
+ has a value, it is replaced. Otherwise a new ValueType\<T\> value
+ is created and set to \em value.
+
+ This is a helper function, called from Exifdatum members. It is meant to
+ be used with T = (u)int16_t, (u)int32_t or (U)Rational. Do not use
directly.
+ */
+ template<typename T>
+ Exifdatum& setValue(Exifdatum& exifDatum, const T& value);
+
+ /*!
+ @brief Exif %Thumbnail image. This abstract base class provides the
+ interface for the thumbnail image that is optionally embedded in
+ the Exif data. This class is used internally by ExifData, it is
+ probably not useful for a client as a standalone class. Instead,
+ use an instance of ExifData to access the Exif thumbnail image.
+ */
+ class Thumbnail {
+ public:
+ //! Shortcut for a %Thumbnail auto pointer.
+ typedef std::auto_ptr<Thumbnail> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Virtual destructor
+ virtual ~Thumbnail() {}
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Set the image data as data area of the appropriate Exif
+ metadatum. Read the thumbnail image data from data buffer
+ \em buf. Return 0 if successful.
+
+ @param exifData Exif data corresponding to the data buffer.
+ @param pIfd1 Corresponding raw IFD1.
+ @param buf Data buffer containing the thumbnail data. The buffer must
+ start with the TIFF header.
+ @param len Number of bytes in the data buffer.
+ @return 0 if successful;<BR>
+ 1 in case of inconsistent thumbnail Exif data; or<BR>
+ 2 if the data area is outside of the data buffer
+ */
+ virtual int setDataArea(ExifData& exifData,
+ Ifd* pIfd1,
+ const byte* buf,
+ long len) const =0;
+ /*!
+ @brief Return the thumbnail image in a %DataBuf. The caller owns the
+ data buffer and %DataBuf ensures that it will be deleted.
+ */
+ virtual DataBuf copy(const ExifData& exifData) const =0;
+ /*!
+ @brief Return a short string for the format of the thumbnail
+ ("TIFF", "JPEG").
+ */
+ virtual const char* format() const =0;
+ /*!
+ @brief Return the file extension for the format of the thumbnail
+ (".tif", ".jpg").
+ */
+ virtual const char* extension() const =0;
+ //@}
+
+ protected:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Assignment operator. Protected so that it can only be used
+ by subclasses but not directly.
+ */
+ Thumbnail& operator=(const Thumbnail& rhs);
+ //@}
+
+ }; // class Thumbnail
+
+ //! Exif thumbnail image in TIFF format
+ class TiffThumbnail : public Thumbnail {
+ public:
+ //! Shortcut for a %TiffThumbnail auto pointer.
+ typedef std::auto_ptr<TiffThumbnail> AutoPtr;
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ TiffThumbnail& operator=(const TiffThumbnail& rhs) { return *this; }
+ //@}
+
+ //! @name Accessors
+ //@{
+ int setDataArea(ExifData& exifData,
+ Ifd* pIfd1,
+ const byte* buf,
+ long len) const;
+ DataBuf copy(const ExifData& exifData) const;
+ const char* format() const;
+ const char* extension() const;
+ //@}
+
+ }; // class TiffThumbnail
+
+ //! Exif thumbnail image in JPEG format
+ class JpegThumbnail : public Thumbnail {
+ public:
+ //! Shortcut for a %JpegThumbnail auto pointer.
+ typedef std::auto_ptr<JpegThumbnail> AutoPtr;
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ JpegThumbnail& operator=(const JpegThumbnail& rhs) { return *this; }
+ //@}
+
+ //! @name Accessors
+ //@{
+ int setDataArea(ExifData& exifData,
+ Ifd* pIfd1,
+ const byte* buf,
+ long len) const;
+ DataBuf copy(const ExifData& exifData) const;
+ const char* format() const;
+ const char* extension() const;
+ //@}
+
+ }; // class JpegThumbnail
+
+ //! Container type to hold all metadata
+ typedef std::vector<Exifdatum> ExifMetadata;
+
+ //! Unary predicate that matches a Exifdatum with a given ifd id and idx
+ class FindMetadatumByIfdIdIdx {
+ public:
+ //! Constructor, initializes the object with the ifd id and idx to
look for
+ FindMetadatumByIfdIdIdx(IfdId ifdId, int idx)
+ : ifdId_(ifdId), idx_(idx) {}
+ /*!
+ @brief Returns true if the ifd id and idx of the argument
+ \em exifdatum is equal to that of the object.
+ */
+ bool operator()(const Exifdatum& exifdatum) const
+ { return ifdId_ == exifdatum.ifdId() && idx_ == exifdatum.idx(); }
+
+ private:
+ IfdId ifdId_;
+ int idx_;
+
+ }; // class FindMetadatumByIfdIdIdx
+
+ /*!
+ @brief A container for Exif data. This is a top-level class of the
%Exiv2
+ library. The container holds Exifdatum objects.
+
+ Provide high-level access to the Exif data of an image:
+ - read Exif information from JPEG files
+ - access metadata through keys and standard C++ iterators
+ - add, modify and delete metadata
+ - write Exif data to JPEG files
+ - extract Exif metadata to files, insert from these files
+ - extract and delete Exif thumbnail (JPEG and TIFF thumbnails)
+ */
+ class ExifData {
+ public:
+ //! ExifMetadata iterator type
+ typedef ExifMetadata::iterator iterator;
+ //! ExifMetadata const iterator type
+ typedef ExifMetadata::const_iterator const_iterator;
+
+ //! @name Creators
+ //@{
+ //! Default constructor
+ ExifData();
+ //! Copy constructor (Todo: copy image data also)
+ ExifData(const ExifData& rhs);
+ //! Destructor
+ ~ExifData();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator (Todo: assign image data also)
+ ExifData& operator=(const ExifData& rhs);
+ /*!
+ @brief Load the Exif data from a byte buffer. The data buffer
+ must start with the TIFF header.
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @return 0 if successful.
+ */
+ int load(const byte* buf, long len);
+ /*!
+ @brief Write the Exif data to a data buffer, which is returned. The
+ caller owns this copy and %DataBuf ensures that it will be
+ deleted. The copied data starts with the TIFF header.
+
+ Tries to update the original data buffer and write it back with
+ minimal changes, in a 'non-intrusive' fashion, if possible. In this
+ case, tag data that ExifData does not understand stand a good chance
+ to remain valid. (In particular, if the Exif data contains a
+ Makernote in IFD format, the offsets in its IFD will remain valid.)
+ <BR>
+ If 'non-intrusive' writing is not possible, the Exif data will be
+ re-built from scratch, in which case the absolute position of the
+ metadata entries within the data buffer may (and in most cases will)
+ be different from their original position. Furthermore, in this case,
+ the Exif data is updated with the metadata from the actual thumbnail
+ image (overriding existing metadata).
+
+ @return A %DataBuf containing the Exif data.
+ */
+ DataBuf copy();
+ /*!
+ @brief Returns a reference to the %Exifdatum that is associated with
a
+ particular \em key. If %ExifData does not already contain such
+ an %Exifdatum, operator[] adds object \em Exifdatum(key).
+
+ @note Since operator[] might insert a new element, it can't be a
const
+ member function.
+ */
+ Exifdatum& operator[](const std::string& key);
+ /*!
+ @brief Add all (IFD) entries in the range from iterator position
begin
+ to iterator position end to the Exif metadata. No duplicate
+ checks are performed, i.e., it is possible to add multiple
+ metadata with the same key.
+ */
+ void add(Entries::const_iterator begin,
+ Entries::const_iterator end,
+ ByteOrder byteOrder);
+ /*!
+ @brief Add an Exifdatum from the supplied key and value pair. This
+ method copies (clones) key and value. No duplicate checks are
+ performed, i.e., it is possible to add multiple metadata with
+ the same key.
+ */
+ void add(const ExifKey& key, const Value* pValue);
+ /*!
+ @brief Add a copy of the \em exifdatum to the Exif metadata. No
+ duplicate checks are performed, i.e., it is possible to add
+ multiple metadata with the same key.
+
+ @throw Error if the makernote cannot be created
+ */
+ void add(const Exifdatum& exifdatum);
+ /*!
+ @brief Delete the Exifdatum at iterator position \em pos, return the
+ position of the next exifdatum. Note that iterators into
+ the metadata, including \em pos, are potentially invalidated
+ by this call.
+ */
+ iterator erase(iterator pos);
+ /*!
+ @brief Delete all Exifdatum instances resulting in an empty
container.
+ Note that this also removes thumbnails.
+ */
+ void clear() { eraseThumbnail(); exifMetadata_.clear(); }
+ //! Sort metadata by key
+ void sortByKey();
+ //! Sort metadata by tag
+ void sortByTag();
+ //! Begin of the metadata
+ iterator begin() { return exifMetadata_.begin(); }
+ //! End of the metadata
+ iterator end() { return exifMetadata_.end(); }
+ /*!
+ @brief Find a Exifdatum with the given \em key, return an iterator to
+ it. If multiple metadata with the same key exist, it is
+ undefined which of the matching metadata is found.
+ */
+ iterator findKey(const ExifKey& key);
+ /*!
+ @brief Find the Exifdatum with the given \em ifdId and \em idx,
+ return an iterator to it.
+
+ This method can be used to uniquely identify an exifdatum that was
+ created from an IFD or from the makernote (with idx greater than
+ 0). Metadata created by an application (not read from an IFD or a
+ makernote) all have their idx field set to 0, i.e., they cannot be
+ uniquely identified with this method. If multiple metadata with the
+ same key exist, it is undefined which of the matching metadata is
+ found.
+ */
+ iterator findIfdIdIdx(IfdId ifdId, int idx);
+ /*!
+ @brief Set the Exif thumbnail to the Jpeg image \em path. Set
+ XResolution, YResolution and ResolutionUnit to \em xres,
+ \em yres and \em unit, respectively.
+
+ This results in the minimal thumbnail tags being set for a Jpeg
+ thumbnail, as mandated by the Exif standard.
+
+ @throw Error if reading the file fails.
+
+ @note No checks on the file format or size are performed.
+ @note Additional existing Exif thumbnail tags are not modified.
+ @note The Jpeg image inserted as thumbnail image should not
+ itself contain Exif data (or other metadata), as existing
+ applications may have problems with that. (The preview
+ application that comes with OS X for one.) - David Harvey.
+ */
+ void setJpegThumbnail(const std::string& path,
+ URational xres, URational yres, uint16_t unit);
+ /*!
+ @brief Set the Exif thumbnail to the Jpeg image pointed to by \em
buf,
+ and size \em size. Set XResolution, YResolution and
+ ResolutionUnit to \em xres, \em yres and \em unit,
respectively.
+
+ This results in the minimal thumbnail tags being set for a Jpeg
+ thumbnail, as mandated by the Exif standard.
+
+ @throw Error if reading the file fails.
+
+ @note No checks on the image format or size are performed.
+ @note Additional existing Exif thumbnail tags are not modified.
+ @note The Jpeg image inserted as thumbnail image should not
+ itself contain Exif data (or other metadata), as existing
+ applications may have problems with that. (The preview
+ application that comes with OS X for one.) - David Harvey.
+ */
+ void setJpegThumbnail(const byte* buf, long size,
+ URational xres, URational yres, uint16_t unit);
+ /*!
+ @brief Set the Exif thumbnail to the Jpeg image \em path.
+
+ This sets only the Compression, JPEGInterchangeFormat and
+ JPEGInterchangeFormatLength tags, which is not all the thumbnail
+ Exif information mandatory according to the Exif standard. (But it's
+ enough to work with the thumbnail.)
+
+ @throw Error if reading the file fails.
+
+ @note No checks on the file format or size are performed.
+ @note Additional existing Exif thumbnail tags are not modified.
+ */
+ void setJpegThumbnail(const std::string& path);
+ /*!
+ @brief Set the Exif thumbnail to the Jpeg image pointed to by \em
buf,
+ and size \em size.
+
+ This sets only the Compression, JPEGInterchangeFormat and
+ JPEGInterchangeFormatLength tags, which is not all the thumbnail
+ Exif information mandatory according to the Exif standard. (But it's
+ enough to work with the thumbnail.)
+
+ @note No checks on the image format or size are performed.
+ @note Additional existing Exif thumbnail tags are not modified.
+ */
+ void setJpegThumbnail(const byte* buf, long size);
+ /*!
+ @brief Delete the thumbnail from the Exif data. Removes all
+ Exif.%Thumbnail.*, i.e., IFD1 metadata.
+
+ @return The number of bytes of thumbnail data erased from the
original
+ Exif data. Note that the original image size may differ from
+ the size of the image after deleting the thumbnail by more
+ than this number. This is the case if the Exif data contains
+ extra bytes (often at the end of the Exif block) or gaps and
+ the thumbnail is not located at the end of the Exif block so
+ that non-intrusive writing of a truncated Exif block is not
+ possible. Instead it is in this case necessary to write the
+ Exif data, without the thumbnail, from the metadata and all
+ extra bytes and gaps are lost, resulting in a smaller image.
+ */
+ long eraseThumbnail();
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Begin of the metadata
+ const_iterator begin() const { return exifMetadata_.begin(); }
+ //! End of the metadata
+ const_iterator end() const { return exifMetadata_.end(); }
+ /*!
+ @brief Find an exifdatum with the given \em 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 ExifKey& key) const;
+ /*!
+ @brief Find the exifdatum with the given \em ifdId and \em idx,
+ return an iterator to it.
+
+ This method can be used to uniquely identify a Exifdatum that was
+ created from an IFD or from the makernote (with idx greater than
+ 0). Metadata created by an application (not read from an IFD or a
+ makernote) all have their idx field set to 0, i.e., they cannot be
+ uniquely identified with this method. If multiple metadata with the
+ same key exist, it is undefined which of the matching metadata is
+ found.
+ */
+ const_iterator findIfdIdIdx(IfdId ifdId, int idx) const;
+ //! Return true if there is no Exif metadata
+ bool empty() const { return count() == 0; }
+ //! Get the number of metadata entries
+ long count() const { return static_cast<long>(exifMetadata_.size()); }
+ /*!
+ @brief Returns the byte order. Default is little endian.
+ */
+ ByteOrder byteOrder() const;
+ /*!
+ @brief Write the thumbnail image to a file. A filename extension
+ is appended to \em path according to the image type of the
+ thumbnail, so \em path should not include an extension.
+ This will overwrite an existing file of the same name.
+
+ @param path Path of the filename without image type extension
+
+ @throw Error if writing to the file fails.
+
+ @return 0 if successful;<BR>
+ 8 if the Exif data does not contain a thumbnail.
+ */
+ int writeThumbnail(const std::string& path) const;
+ /*!
+ @brief Return the thumbnail image in a %DataBuf. The caller owns the
+ data buffer and %DataBuf ensures that it will be deleted.
+ */
+ DataBuf copyThumbnail() const;
+ /*!
+ @brief Return a short string describing the format of the Exif
+ thumbnail ("TIFF", "JPEG").
+ */
+ const char* thumbnailFormat() const;
+ /*!
+ @brief Return the file extension for the Exif thumbnail depending
+ on the format (".tif", ".jpg").
+ */
+ const char* thumbnailExtension() const;
+ /*!
+ @brief Return a thumbnail object of the correct type, corresponding
to
+ the current Exif data. Caller owns this object and the auto
+ pointer ensures that it will be deleted.
+ */
+ Thumbnail::AutoPtr getThumbnail() const;
+ //@}
+
+ private:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read the thumbnail from the data buffer. Assigns the thumbnail
+ data area with the appropriate Exif tags. Return 0 if
successful,
+ i.e., if there is a thumbnail.
+ */
+ int readThumbnail();
+ /*!
+ @brief Check if the metadata changed and update the internal IFDs and
+ the MakerNote if the changes are compatible with the existing
+ data (non-intrusive write support).
+
+ @return True if only compatible changes were detected in the metadata
+ and the internal IFDs and MakerNote (and thus the data
buffer)
+ were updated successfully. Return false, if non-intrusive
+ writing is not possible. The internal IFDs and the MakerNote
+ (and thus the data buffer) may or may not be modified in this
+ case.
+ */
+ bool updateEntries();
+ /*!
+ @brief Update the metadata for a range of entries. Called by
+ updateEntries() for each of the internal IFDs and the
MakerNote
+ (if any).
+ */
+ bool updateRange(const Entries::iterator& begin,
+ const Entries::iterator& end,
+ ByteOrder byteOrder);
+ /*!
+ @brief Write the Exif data to a data buffer the hard way, return the
+ data buffer. The caller owns this data buffer and %DataBuf
+ ensures that it will be deleted.
+
+ Rebuilds the Exif data from scratch, using the TIFF header, metadata
+ container and thumbnail. In particular, the internal IFDs and the
+ original data buffer are not used. Furthermore, this method updates
+ the Exif data with the metadata from the actual thumbnail image
+ (overriding existing metadata).
+
+ @return A %DataBuf containing the Exif data.
+ */
+ DataBuf copyFromMetadata();
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Check if the metadata is compatible with the internal IFDs for
+ non-intrusive writing. Return true if compatible, false if
not.
+
+ @note This function does not detect deleted metadata as incompatible,
+ although the deletion of metadata is not (yet) a supported
+ non-intrusive write operation.
+ */
+ bool compatible() const;
+ /*!
+ @brief Find the IFD or makernote entry corresponding to ifd id and
idx.
+
+ @return A pair of which the first part determines if a match was
found
+ and, if true, the second contains an iterator to the entry.
+ */
+ std::pair<bool, Entries::const_iterator>
+ findEntry(IfdId ifdId, int idx) const;
+ //! Return a pointer to the internal IFD identified by its IFD id
+ const Ifd* getIfd(IfdId ifdId) const;
+ /*!
+ @brief Check if IFD1, the IFD1 data and thumbnail data are located
at
+ the end of the Exif data. Return true, if they are or if there
+ is no thumbnail at all, else return false.
+ */
+ bool stdThumbPosition() const;
+ //@}
+
+ // DATA
+ ExifMetadata exifMetadata_;
+
+ // The pointers below are used only if Exif data is read from a
+ // raw data buffer
+ TiffHeader* pTiffHeader_; //! Pointer to the TIFF header
+ Ifd* pIfd0_; //! Pointer to Ifd0
+ Ifd* pExifIfd_; //! Pointer to ExifIfd
+ Ifd* pIopIfd_; //! Pointer to IopIfd
+ Ifd* pGpsIfd_; //! Pointer to GpsIfd
+ Ifd* pIfd1_; //! Pointer to Ifd1
+ MakerNote* pMakerNote_; //! Pointer to the MakerNote, if any
+
+ long size_; //!< Size of the Exif raw data in bytes
+ byte* pData_; //!< Exif raw data buffer
+
+ /*!
+ Can be set to false to indicate that non-intrusive writing is not
+ possible. If it is true (the default), then the compatibility checks
+ will be performed to determine which writing method to use.
+ */
+ bool compatible_;
+
+ }; // class ExifData
+
+//
*****************************************************************************
+// template, inline and free functions
+
+ template<typename T>
+ Exifdatum& setValue(Exifdatum& exifDatum, const T& value)
+ {
+ std::auto_ptr<ValueType<T> > v
+ = std::auto_ptr<ValueType<T> >(new ValueType<T>);
+ v->value_.push_back(value);
+ exifDatum.value_ = v;
+ return exifDatum;
+ }
+ /*!
+ @brief Add all metadata in the range from iterator position begin to
+ iterator position end, which have an IFD id matching that of the
+ IFD to the list of directory entries of ifd. No duplicate checks
+ are performed, i.e., it is possible to add multiple metadata with
+ the same key to an IFD.
+ */
+ void addToIfd(Ifd& ifd,
+ ExifMetadata::const_iterator begin,
+ ExifMetadata::const_iterator end,
+ ByteOrder byteOrder);
+ /*!
+ @brief Add the Exifdatum to the IFD. No duplicate checks are performed,
+ i.e., it is possible to add multiple metadata with the same key to
+ an IFD.
+ */
+ void addToIfd(Ifd& ifd, const Exifdatum& exifdatum, ByteOrder byteOrder);
+ /*!
+ @brief Add all metadata in the range from iterator position begin to
+ iterator position end with IFD id 'makerIfd' to the list of
+ makernote entries of the object pointed to be makerNote. No
+ duplicate checks are performed, i.e., it is possible to add
+ multiple metadata with the same key to a makernote.
+ */
+ void addToMakerNote(MakerNote* makerNote,
+ ExifMetadata::const_iterator begin,
+ ExifMetadata::const_iterator end,
+ ByteOrder byteOrder);
+ /*!
+ @brief Add the Exifdatum to makerNote, encoded in byte order byteOrder.
+ No duplicate checks are performed, i.e., it is possible to add
+ multiple metadata with the same key to a makernote.
+ */
+ void addToMakerNote(MakerNote* makerNote,
+ const Exifdatum& exifdatum,
+ ByteOrder byteOrder);
+
+} // namespace Exiv2
+
+#endif // #ifndef EXIF_HPP_
Added: Extractor/src/plugins/exiv2/exifcomment.cpp
===================================================================
--- Extractor/src/plugins/exiv2/exifcomment.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exifcomment.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,68 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ Abstract : Sample program showing how to set the Exif comment of an image,
+ Exif.Photo.UserComment
+
+ File: exifcomment.cpp
+ Version : $Rev: 560 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History : 10-May-04, ahu: created
+ 16-Jan-05, ahu: updated using CommentValue and operator trickery
+ */
+//
*****************************************************************************
+// included header files
+#include "image.hpp"
+#include "exif.hpp"
+#include <iostream>
+#include <iomanip>
+#include <cstring>
+#include <cassert>
+
+//
*****************************************************************************
+// Main
+int main(int argc, char* const argv[])
+try {
+
+ if (argc != 2) {
+ std::cout << "Usage: " << argv[0] << " file\n";
+ return 1;
+ }
+
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
+ assert (image.get() != 0);
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+
+ /*
+ Exiv2 uses a CommentValue for Exif user comments. The format of the
+ comment string includes an optional charset specification at the
beginning:
+
+ [charset=["]Ascii|Jis|Unicode|Undefined["] ]comment
+
+ Undefined is used as a default if the comment doesn't start with a
charset
+ definition.
+
+ Following are a few examples of valid comments. The last one is written
to
+ the file.
+ */
+ exifData["Exif.Photo.UserComment"]
+ = "charset=\"Unicode\" An Unicode Exif comment added with Exiv2";
+ exifData["Exif.Photo.UserComment"]
+ = "charset=\"Undefined\" An undefined Exif comment added with Exiv2";
+ exifData["Exif.Photo.UserComment"]
+ = "Another undefined Exif comment added with Exiv2";
+ exifData["Exif.Photo.UserComment"]
+ = "charset=Ascii An ASCII Exif comment added with Exiv2";
+
+ std::cout << "Writing user comment '"
+ << exifData["Exif.Photo.UserComment"]
+ << "' back to the image\n";
+
+ image->writeMetadata();
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return -1;
+}
Added: Extractor/src/plugins/exiv2/exifprint.cpp
===================================================================
--- Extractor/src/plugins/exiv2/exifprint.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exifprint.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,49 @@
+// ***************************************************************** -*- C++
-*-
+// exifprint.cpp, $Rev: 578 $
+// Sample program to print the Exif metadata of an image
+
+#include "image.hpp"
+#include "exif.hpp"
+#include <iostream>
+#include <iomanip>
+#include <cassert>
+
+int main(int argc, char* const argv[])
+try {
+
+ if (argc != 2) {
+ std::cout << "Usage: " << argv[0] << " file\n";
+ return 1;
+ }
+
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
+ assert(image.get() != 0);
+ image->readMetadata();
+
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::string error(argv[1]);
+ error += ": No Exif data found in the file";
+ throw Exiv2::Error(1, error);
+ }
+ Exiv2::ExifData::const_iterator end = exifData.end();
+ for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
+ std::cout << std::setw(44) << std::setfill(' ') << std::left
+ << i->key() << " "
+ << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << i->tag() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << i->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << i->count() << " "
+ << std::dec << i->value()
+ << "\n";
+ }
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return -1;
+}
Added: Extractor/src/plugins/exiv2/exiv2.cpp
===================================================================
--- Extractor/src/plugins/exiv2/exiv2.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exiv2.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,804 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ Abstract: Command line program to display and manipulate image %Exif data
+
+ File: exiv2.cpp
+ Version: $Rev: 575 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 10-Dec-03, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: exiv2.cpp 575 2005-06-04 07:32:20Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "exiv2.hpp"
+#include "actions.hpp"
+#include "utils.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <cstring>
+#include <cassert>
+
+//
*****************************************************************************
+// local declarations
+namespace {
+
+ //! List of all command identifiers and corresponding strings
+ static const CmdIdAndString cmdIdAndString[] = {
+ { add, "add" },
+ { set, "set" },
+ { del, "del" },
+ { invalidCmdId, "invalidCmd" } // End of list marker
+ };
+
+ // Return a command Id for a command string
+ CmdId commandId(const std::string& cmdString);
+
+ // Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value
+ // in seconds if successful, else returns false.
+ bool parseTime(const std::string& ts, long& time);
+
+ /*!
+ @brief Parse the oparg string into a bitmap of common targets.
+ @param optarg Option arguments
+ @param action Action being processed
+ @return A bitmap of common targets or -1 in case of a parse error
+ */
+ int parseCommonTargets(const std::string& optarg,
+ const std::string& action);
+
+ /*!
+ @brief Parse metadata modification commands from multiple files
+ @param modifyCmds Reference to a structure to store the parsed commands
+ @param cmdFiles Container with the file names
+ */
+ bool parseCmdFiles(ModifyCmds& modifyCmds,
+ const Params::CmdFiles& cmdFiles);
+
+ /*!
+ @brief Parse metadata modification commands from a container of commands
+ @param modifyCmds Reference to a structure to store the parsed commands
+ @param cmdLines Container with the commands
+ */
+ bool parseCmdLines(ModifyCmds& modifyCmds,
+ const Params::CmdLines& cmdLines);
+
+ /*!
+ @brief Parse one line of the command file
+ @param modifyCmd Reference to a command structure to store the parsed
+ command
+ @param line Input line
+ @param num Line number (used for error output)
+ */
+ bool parseLine(ModifyCmd& modifyCmd,
+ const std::string& line, int num);
+
+}
+
+//
*****************************************************************************
+// Main
+int main(int argc, char* const argv[])
+{
+ // Handle command line arguments
+ Params& params = Params::instance();
+ if (params.getopt(argc, argv)) {
+ params.usage();
+ return 1;
+ }
+ if (params.help_) {
+ params.help();
+ return 0;
+ }
+ if (params.version_) {
+ params.version();
+ return 0;
+ }
+
+ // Create the required action class
+ Action::TaskFactory& taskFactory = Action::TaskFactory::instance();
+ Action::Task::AutoPtr task
+ = taskFactory.create(Action::TaskType(params.action_));
+ assert(task.get());
+
+ // Process all files
+ int n = 1;
+ int s = static_cast<int>(params.files_.size());
+ int w = s > 9 ? s > 99 ? 3 : 2 : 1;
+ Params::Files::const_iterator e = params.files_.end();
+ for (Params::Files::const_iterator i = params.files_.begin(); i != e; ++i)
{
+ if (params.verbose_) {
+ std::cout << "File " << std::setw(w) << n++ << "/" << s << ": "
+ << *i << std::endl;
+ }
+ task->run(*i);
+ }
+ return 0;
+} // main
+
+//
*****************************************************************************
+// class Params
+Params* Params::instance_ = 0;
+
+Params& Params::instance()
+{
+ if (0 == instance_) {
+ instance_ = new Params;
+ }
+ return *instance_;
+}
+
+void Params::version(std::ostream& os) const
+{
+ os << EXV_PACKAGE_STRING << ", "
+ << "Copyright (C) 2004, 2005 Andreas Huggel.\n\n"
+ << "This is free software; see the source for copying conditions. "
+ << "There is NO \nwarranty; not even for MERCHANTABILITY or FITNESS FOR
"
+ << "A PARTICULAR PURPOSE.\n";
+}
+
+void Params::usage(std::ostream& os) const
+{
+ os << "Usage: " << progname()
+ << " [ options ] [ action ] file ...\n\n"
+ << "Manipulate the Exif metadata of images.\n";
+}
+
+void Params::help(std::ostream& os) const
+{
+ usage(os);
+ os << "\nActions:\n"
+ << " ad | adjust Adjust Exif timestamps by the given time. This\n"
+ << " action requires the option -a time.\n"
+ << " pr | print Print image metadata.\n"
+ << " rm | delete Delete image metadata from the files.\n"
+ << " in | insert Insert metadata from corresponding *.exv files.\n"
+ << " ex | extract Extract metadata to *.exv and thumbnail image
files.\n"
+ << " mv | rename Rename files according to the Exif create
timestamp.\n"
+ << " The filename format can be set with -r format.\n"
+ << " mo | modify Apply commands to modify (add, set, delete) the
Exif\n"
+ << " and Iptc metadata of image files. Requires option
-m or -M\n"
+ << "\nOptions:\n"
+ << " -h Display this help and exit.\n"
+ << " -V Show the program version and exit.\n"
+ << " -v Be verbose during the program run.\n"
+ << " -f Do not prompt before overwriting existing files
(force).\n"
+ << " -F Do not prompt before renaming existing files (Force).\n"
+ << " -a time Time adjustment in the format [-]HH[:MM[:SS]]. This
option\n"
+ << " is only used with the `adjust' action.\n"
+ << " -p mode Print mode for the `print' action. Possible modes are:\n"
+ << " s : print a summary of the Exif metadata (the
default)\n"
+ << " t : interpreted (translated) Exif data\n"
+ << " v : plain Exif data values\n"
+ << " h : hexdump of the Exif data\n"
+ << " i : Iptc data values\n"
+ << " c : Jpeg comment\n"
+ << " -d tgt Delete target(s) for the `delete' action. Possible
targets are:\n"
+ << " a : all supported metadata (the default)\n"
+ << " e : Exif section\n"
+ << " t : Exif thumbnail only\n"
+ << " i : Iptc data\n"
+ << " c : Jpeg comment\n"
+ << " -i tgt Insert target(s) for the `insert' action. Possible
targets are\n"
+ << " the same as those for the -d option. Only Jpeg
thumbnails can\n"
+ << " be inserted, they need to be named <file>-thumb.jpg\n"
+ << " -e tgt Extract target(s) for the `extract' action. Possible
targets\n"
+ << " are the same as those for the -d option.\n"
+ << " -r fmt Filename format for the `rename' action. The format
string\n"
+ << " follows strftime(3). Default filename format is "
+ << format_ << ".\n"
+ << " -m file Command file for the modify action. The format for
commands is\n"
+ << " set|add|del <key> [[<type>] <value>].\n"
+ << " -M cmd Command line for the modify action. The format for the\n"
+ << " commands is the same as that of the lines of a command
file.\n"
+ << " -l dir Location (directory) for files to be inserted or
extracted.\n\n";
+} // Params::help
+
+int Params::option(int opt, const std::string& optarg, int optopt)
+{
+ int rc = 0;
+ switch (opt) {
+ case 'h': help_ = true; break;
+ case 'V': version_ = true; break;
+ case 'v': verbose_ = true; break;
+ case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break;
+ case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break;
+ case 'r': rc = evalRename(optarg); break;
+ case 'a': rc = evalAdjust(optarg); break;
+ case 'p': rc = evalPrint(optarg); break;
+ case 'd': rc = evalDelete(optarg); break;
+ case 'e': rc = evalExtract(optarg); break;
+ case 'i': rc = evalInsert(optarg); break;
+ case 'm': rc = evalModify(opt, optarg); break;
+ case 'M': rc = evalModify(opt, optarg); break;
+ case 'l': directory_ = optarg; break;
+ case ':':
+ std::cerr << progname() << ": Option -" << static_cast<char>(optopt)
+ << " requires an argument\n";
+ rc = 1;
+ break;
+ case '?':
+ std::cerr << progname() << ": Unrecognized option -"
+ << static_cast<char>(optopt) << "\n";
+ rc = 1;
+ break;
+ default:
+ std::cerr << progname()
+ << ": getopt returned unexpected character code "
+ << std::hex << opt << "\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::option
+
+int Params::evalRename(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::rename;
+ format_ = optarg;
+ break;
+ case Action::rename:
+ std::cerr << progname()
+ << ": Ignoring surplus option -r \"" << optarg << "\"\n";
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -r is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalRename
+
+int Params::evalAdjust(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::adjust;
+ adjust_ = parseTime(optarg, adjustment_);
+ if (!adjust_) {
+ std::cerr << progname() << ": Error parsing -a option argument `"
+ << optarg << "'\n";
+ rc = 1;
+ }
+ break;
+ case Action::adjust:
+ std::cerr << progname()
+ << ": Ignoring surplus option -a " << optarg << "\n";
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -a is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalAdjust
+
+int Params::evalPrint(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::print;
+ switch (optarg[0]) {
+ case 's': printMode_ = pmSummary; break;
+ case 't': printMode_ = pmInterpreted; break;
+ case 'v': printMode_ = pmValues; break;
+ case 'h': printMode_ = pmHexdump; break;
+ case 'i': printMode_ = pmIptc; break;
+ case 'c': printMode_ = pmComment; break;
+ default:
+ std::cerr << progname() << ": Unrecognized print mode `"
+ << optarg << "'\n";
+ rc = 1;
+ break;
+ }
+ break;
+ case Action::print:
+ std::cerr << progname()
+ << ": Ignoring surplus option -p" << optarg << "\n";
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -p is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalPrint
+
+int Params::evalDelete(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::erase;
+ target_ = 0;
+ // fallthrough
+ case Action::erase:
+ rc = parseCommonTargets(optarg, "erase");
+ if (rc > 0) {
+ target_ |= rc;
+ rc = 0;
+ }
+ else {
+ rc = 1;
+ }
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -d is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalDelete
+
+int Params::evalExtract(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::extract;
+ target_ = 0;
+ // fallthrough
+ case Action::extract:
+ rc = parseCommonTargets(optarg, "extract");
+ if (rc > 0) {
+ target_ |= rc;
+ rc = 0;
+ }
+ else {
+ rc = 1;
+ }
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -e is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalExtract
+
+int Params::evalInsert(const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::insert;
+ target_ = 0;
+ // fallthrough
+ case Action::insert:
+ rc = parseCommonTargets(optarg, "insert");
+ if (rc > 0) {
+ target_ |= rc;
+ rc = 0;
+ }
+ else {
+ rc = 1;
+ }
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -i is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalInsert
+
+int Params::evalModify(int opt, const std::string& optarg)
+{
+ int rc = 0;
+ switch (action_) {
+ case Action::none:
+ action_ = Action::modify;
+ // fallthrough
+ case Action::modify:
+ if (opt == 'm') cmdFiles_.push_back(optarg); // parse the files later
+ if (opt == 'M') cmdLines_.push_back(optarg); // parse the commands
later
+ break;
+ default:
+ std::cerr << progname()
+ << ": Option -" << (char)opt
+ << " is not compatible with a previous option\n";
+ rc = 1;
+ break;
+ }
+ return rc;
+} // Params::evalModify
+
+int Params::nonoption(const std::string& argv)
+{
+ int rc = 0;
+ bool action = false;
+ if (first_) {
+ // The first non-option argument must be the action
+ first_ = false;
+ if (argv == "ad" || argv == "adjust") {
+ if (action_ != Action::none && action_ != Action::adjust) {
+ std::cerr << progname() << ": Action adjust is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::adjust;
+ }
+ if (argv == "pr" || argv == "print") {
+ if (action_ != Action::none && action_ != Action::print) {
+ std::cerr << progname() << ": Action print is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::print;
+ }
+ if (argv == "rm" || argv == "delete") {
+ if (action_ != Action::none && action_ != Action::erase) {
+ std::cerr << progname() << ": Action delete is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::erase;
+ }
+ if (argv == "ex" || argv == "extract") {
+ if (action_ != Action::none && action_ != Action::extract) {
+ std::cerr << progname() << ": Action extract is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::extract;
+ }
+ if (argv == "in" || argv == "insert") {
+ if (action_ != Action::none && action_ != Action::insert) {
+ std::cerr << progname() << ": Action insert is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::insert;
+ }
+ if (argv == "mv" || argv == "rename") {
+ if (action_ != Action::none && action_ != Action::rename) {
+ std::cerr << progname() << ": Action rename is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::rename;
+ }
+ if (argv == "mo" || argv == "modify") {
+ if (action_ != Action::none && action_ != Action::modify) {
+ std::cerr << progname() << ": Action modify is not "
+ << "compatible with the given options\n";
+ rc = 1;
+ }
+ action = true;
+ action_ = Action::modify;
+ }
+ if (action_ == Action::none) {
+ // if everything else fails, assume print as the default action
+ action_ = Action::print;
+ }
+ }
+ if (!action) {
+ files_.push_back(argv);
+ }
+ return rc;
+} // Params::nonoption
+
+int Params::getopt(int argc, char* const argv[])
+{
+ int rc = Util::Getopt::getopt(argc, argv, optstring_);
+ // Further consistency checks
+ if (help_ || version_) return 0;
+ if (action_ == Action::none) {
+ // This shouldn't happen since print is taken as default action
+ std::cerr << progname() << ": An action must be specified\n";
+ rc = 1;
+ }
+ if (action_ == Action::adjust && !adjust_) {
+ std::cerr << progname()
+ << ": Adjust action requires option -a time\n";
+ rc = 1;
+ }
+ if (action_ == Action::modify && cmdFiles_.empty() && cmdLines_.empty()) {
+ std::cerr << progname()
+ << ": Modify action requires at least one -m or -M option\n";
+ rc = 1;
+ }
+ if (0 == files_.size()) {
+ std::cerr << progname() << ": At least one file is required\n";
+ rc = 1;
+ }
+ if (rc == 0 && action_ == Action::modify) {
+ // Parse command files
+ if (!parseCmdFiles(modifyCmds_, cmdFiles_)) {
+ std::cerr << progname() << ": Error parsing -m option
arguments\n";
+ rc = 1;
+ }
+ }
+ if (rc ==0 && action_ == Action::modify) {
+ // Parse command lines
+ if (!parseCmdLines(modifyCmds_, cmdLines_)) {
+ std::cerr << progname() << ": Error parsing -M option arguments\n";
+ rc = 1;
+ }
+ }
+ if (!directory_.empty() && !(action_ == Action::insert || action_ ==
Action::extract)) {
+ std::cerr << progname() << ": -l option can only be used with extract
or insert actions\n";
+ rc = 1;
+ }
+ return rc;
+} // Params::getopt
+
+//
*****************************************************************************
+// local implementations
+namespace {
+
+ bool parseTime(const std::string& ts, long& time)
+ {
+ std::string hstr, mstr, sstr;
+ char *cts = new char[ts.length() + 1];
+ strcpy(cts, ts.c_str());
+ char *tmp = ::strtok(cts, ":");
+ if (tmp) hstr = tmp;
+ tmp = ::strtok(0, ":");
+ if (tmp) mstr = tmp;
+ tmp = ::strtok(0, ":");
+ if (tmp) sstr = tmp;
+ delete[] cts;
+
+ int sign = 1;
+ long hh(0), mm(0), ss(0);
+ // [-]HH part
+ if (!Util::strtol(hstr.c_str(), hh)) return false;
+ if (hh < 0) {
+ sign = -1;
+ hh *= -1;
+ }
+ // check for the -0 special case
+ if (hh == 0 && hstr.find('-') != std::string::npos) sign = -1;
+ // MM part, if there is one
+ if (mstr != "") {
+ if (!Util::strtol(mstr.c_str(), mm)) return false;
+ if (mm > 59) return false;
+ if (mm < 0) return false;
+ }
+ // SS part, if there is one
+ if (sstr != "") {
+ if (!Util::strtol(sstr.c_str(), ss)) return false;
+ if (ss > 59) return false;
+ if (ss < 0) return false;
+ }
+
+ time = sign * (hh * 3600 + mm * 60 + ss);
+ return true;
+ } // parseTime
+
+ int parseCommonTargets(const std::string& optarg,
+ const std::string& action)
+ {
+ int rc = 0;
+ int target = 0;
+ for (size_t i = 0; rc == 0 && i < optarg.size(); ++i) {
+ switch (optarg[i]) {
+ case 'e': target |= Params::ctExif; break;
+ case 'i': target |= Params::ctIptc; break;
+ case 'c': target |= Params::ctComment; break;
+ case 't': target |= Params::ctThumb; break;
+ case 'a': target |= Params::ctExif
+ | Params::ctIptc
+ | Params::ctComment; break;
+ default:
+ std::cerr << Params::instance().progname() << ": Unrecognized
"
+ << action << " target `" << optarg[i] << "'\n";
+ rc = -1;
+ break;
+ }
+ }
+ return rc ? rc : target;
+ } // parseCommonTargets
+
+ bool parseCmdFiles(ModifyCmds& modifyCmds,
+ const Params::CmdFiles& cmdFiles)
+ {
+ Params::CmdFiles::const_iterator end = cmdFiles.end();
+ Params::CmdFiles::const_iterator filename = cmdFiles.begin();
+ for ( ; filename != end; ++filename) {
+ try {
+ std::ifstream file(filename->c_str());
+ if (!file) {
+ std::cerr << *filename
+ << ": Failed to open command file for reading\n";
+ return false;
+ }
+ int num = 0;
+ std::string line;
+ while (std::getline(file, line)) {
+ ModifyCmd modifyCmd;
+ if (parseLine(modifyCmd, line, ++num)) {
+ modifyCmds.push_back(modifyCmd);
+ }
+ }
+ }
+ catch (const Exiv2::AnyError& error) {
+ std::cerr << *filename << ", line " << error << "\n";
+ return false;
+ }
+ }
+ return true;
+ } // parseCmdFile
+
+ bool parseCmdLines(ModifyCmds& modifyCmds,
+ const Params::CmdLines& cmdLines)
+ {
+ try {
+ int num = 0;
+ Params::CmdLines::const_iterator end = cmdLines.end();
+ Params::CmdLines::const_iterator line = cmdLines.begin();
+ for ( ; line != end; ++line) {
+ ModifyCmd modifyCmd;
+ if (parseLine(modifyCmd, *line, ++num)) {
+ modifyCmds.push_back(modifyCmd);
+ }
+ }
+ return true;
+ }
+ catch (const Exiv2::AnyError& error) {
+ std::cerr << "-M option " << error << "\n";
+ return false;
+ }
+ } // parseCmdLines
+
+ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num)
+ {
+ const std::string delim = " \t";
+
+ // Skip empty lines and comments
+ std::string::size_type cmdStart = line.find_first_not_of(delim);
+ if (cmdStart == std::string::npos || line[cmdStart] == '#') return
false;
+
+ // Get command and key
+ std::string::size_type cmdEnd = line.find_first_of(delim, cmdStart+1);
+ std::string::size_type keyStart = line.find_first_not_of(delim,
cmdEnd+1);
+ std::string::size_type keyEnd = line.find_first_of(delim, keyStart+1);
+ if ( cmdStart == std::string::npos
+ || cmdEnd == std::string::npos
+ || keyStart == std::string::npos) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Invalid command line");
+ }
+
+ std::string cmd(line.substr(cmdStart, cmdEnd-cmdStart));
+ CmdId cmdId = commandId(cmd);
+ if (cmdId == invalidCmdId) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Invalid command `" + cmd + "'");
+ }
+
+ Exiv2::TypeId defaultType = Exiv2::invalidTypeId;
+ std::string key(line.substr(keyStart, keyEnd-keyStart));
+ MetadataId metadataId = invalidMetadataId;
+ try {
+ Exiv2::IptcKey iptcKey(key);
+ metadataId = iptc;
+ defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(),
+ iptcKey.record());
+ }
+ catch (const Exiv2::AnyError&) {}
+ if (metadataId == invalidMetadataId) {
+ try {
+ Exiv2::ExifKey exifKey(key);
+ metadataId = exif;
+ defaultType = Exiv2::ExifTags::tagType(exifKey.tag(),
+ exifKey.ifdId());
+ }
+ catch (const Exiv2::AnyError&) {}
+ }
+ if (metadataId == invalidMetadataId) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Invalid key `" + key + "'");
+ }
+
+ std::string value;
+ Exiv2::TypeId type = defaultType;
+ bool explicitType = false;
+ if (cmdId != del) {
+ // Get type and value
+ std::string::size_type typeStart
+ = line.find_first_not_of(delim, keyEnd+1);
+ std::string::size_type typeEnd
+ = line.find_first_of(delim, typeStart+1);
+ std::string::size_type valStart = typeStart;
+ std::string::size_type valEnd = line.find_last_not_of(delim);
+
+ if ( keyEnd == std::string::npos
+ || typeStart == std::string::npos
+ || valStart == std::string::npos) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Invalid command line ");
+ }
+
+ if (typeEnd != std::string::npos) {
+ std::string typeStr(line.substr(typeStart, typeEnd-typeStart));
+ Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr);
+ if (tmpType != Exiv2::invalidTypeId) {
+ valStart = line.find_first_not_of(delim, typeEnd+1);
+ if (valStart == std::string::npos) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Invalid command line ");
+ }
+ type = tmpType;
+ explicitType = true;
+ }
+ }
+
+ value = line.substr(valStart, valEnd+1-valStart);
+ std::string::size_type last = value.length()-1;
+ if ( (value[0] == '"' || value[last] == '"')
+ && value[0] != value[last]) {
+ throw Exiv2::Error(1, Exiv2::toString(num)
+ + ": Unbalanced quotes");
+ }
+ if (value[0] == '"') {
+ value = value.substr(1, value.length()-2);
+ }
+ }
+
+ modifyCmd.cmdId_ = cmdId;
+ modifyCmd.key_ = key;
+ modifyCmd.metadataId_ = metadataId;
+ modifyCmd.typeId_ = type;
+ modifyCmd.explicitType_ = explicitType;
+ modifyCmd.value_ = value;
+
+ return true;
+ } // parseLine
+
+ CmdId commandId(const std::string& cmdString)
+ {
+ int i = 0;
+ for (; cmdIdAndString[i].cmdId_ != invalidCmdId
+ && cmdIdAndString[i].cmdString_ != cmdString; ++i) {}
+ return cmdIdAndString[i].cmdId_;
+ }
+
+}
Added: Extractor/src/plugins/exiv2/exiv2.hpp
===================================================================
--- Extractor/src/plugins/exiv2/exiv2.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/exiv2.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,217 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file exiv2.hpp
+ @brief Defines class Params, used for the command line handling of exiv2
+ @version $Rev: 567 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 08-Dec-03, ahu: created
+ */
+#ifndef EXIV2_HPP_
+#define EXIV2_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "utils.hpp"
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <iostream>
+
+//
*****************************************************************************
+// class definitions
+
+//! Command identifiers
+enum CmdId { invalidCmdId, add, set, del };
+//! Metadata identifiers
+enum MetadataId { invalidMetadataId, iptc, exif };
+//! Structure for one parsed modification command
+struct ModifyCmd {
+ //! C'tor
+ ModifyCmd() :
+ cmdId_(invalidCmdId), metadataId_(invalidMetadataId),
+ typeId_(Exiv2::invalidTypeId), explicitType_(false) {}
+ CmdId cmdId_; //!< Command identifier
+ std::string key_; //!< Exiv2 key string
+ MetadataId metadataId_; //!< Metadata identifier
+ Exiv2::TypeId typeId_; //!< Exiv2 type identifier
+ //! Flag to indicate if the type was explicitely specified (true)
+ bool explicitType_;
+ std::string value_; //!< Data
+};
+//! Container for modification commands
+typedef std::vector<ModifyCmd> ModifyCmds;
+//! Structure to link command identifiers to strings
+struct CmdIdAndString {
+ CmdId cmdId_; //!< Commands identifier
+ std::string cmdString_; //!< Command string
+};
+
+/*!
+ @brief Implements the command line handling for the program.
+
+ Derives from Util::Getopt to use the command line argument parsing
+ functionalty provided there. This class is implemented as a Singleton,
+ i.e., there is only one global instance of it, which can be accessed
+ from everywhere.
+
+ <b>Usage example:</b> <br>
+ @code
+ #include "params.h"
+
+ int main(int argc, char* const argv[])
+ {
+ Params& params = Params::instance();
+ if (params.getopt(argc, argv)) {
+ params.usage();
+ return 1;
+ }
+ if (params.help_) {
+ params.help();
+ return 0;
+ }
+ if (params.version_) {
+ params.version();
+ return 0;
+ }
+
+ // do something useful here...
+
+ return 0;
+ }
+ @endcode
+ */
+class Params : public Util::Getopt {
+private:
+ std::string optstring_;
+
+public:
+ //! Container for command files
+ typedef std::vector<std::string> CmdFiles;
+ //! Container for commands from the command line
+ typedef std::vector<std::string> CmdLines;
+ //! Container to store filenames.
+ typedef std::vector<std::string> Files;
+
+ /*!
+ @brief Controls all access to the global Params instance.
+ @return Reference to the global Params instance.
+ */
+ static Params& instance();
+
+ //! Enumerates print modes
+ enum PrintMode { pmSummary, pmInterpreted, pmValues, pmHexdump, pmIptc,
+ pmComment };
+ //! Enumerates common targets, bitmap
+ enum CommonTarget { ctExif = 1, ctIptc = 2, ctComment = 4, ctThumb = 8 };
+ //! Enumerates the policies to handle existing files in rename action
+ enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy };
+
+ bool help_; //!< Help option flag.
+ bool version_; //!< Version option flag.
+ bool verbose_; //!< Verbose (talkative) option flag.
+ bool force_; //!< Force overwrites flag.
+ FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename
exists.
+ bool adjust_; //!< Adjustment flag.
+ PrintMode printMode_; //!< Print mode.
+ //! %Action (integer rather than TaskType to avoid dependency).
+ int action_;
+ int target_; //!< What common target to process.
+
+ long adjustment_; //!< Adjustment in seconds.
+ std::string format_; //!< Filename format (-r option arg).
+ CmdFiles cmdFiles_; //!< Names of the modification command
files
+ CmdLines cmdLines_; //!< Commands from the command line
+ ModifyCmds modifyCmds_; //!< Parsed modification commands
+ std::string directory_; //!< Location for files to
extract/insert
+ Files files_; //!< List of non-option arguments.
+
+private:
+ /*!
+ @brief Default constructor. Note that optstring_ is initialized here.
+ The c'tor is private to force instantiation through instance().
+ */
+ Params() : optstring_(":hVvfFa:r:p:d:e:i:m:M:l:"),
+ help_(false),
+ version_(false),
+ verbose_(false),
+ force_(false),
+ fileExistsPolicy_(askPolicy),
+ adjust_(false),
+ printMode_(pmSummary),
+ action_(0),
+ target_(ctExif|ctIptc|ctComment),
+ adjustment_(0),
+ format_("%Y%m%d_%H%M%S"),
+ first_(true) {}
+
+ //! Prevent copy-construction: not implemented.
+ Params(const Params& rhs);
+
+ //! @name Helpers
+ //@{
+ int evalRename(const std::string& optarg);
+ int evalAdjust(const std::string& optarg);
+ int evalPrint(const std::string& optarg);
+ int evalDelete(const std::string& optarg);
+ int evalExtract(const std::string& optarg);
+ int evalInsert(const std::string& optarg);
+ int evalModify(int opt, const std::string& optarg);
+ //@}
+
+ //! Pointer to the global Params object.
+ static Params* instance_;
+
+ bool first_;
+
+public:
+ /*!
+ @brief Call Getopt::getopt() with optstring, to inititate command line
+ argument parsing, perform consistency checks after all command
line
+ arguments are parsed.
+
+ @param argc Argument count as passed to main() on program invocation.
+ @param argv Argument array as passed to main() on program invocation.
+
+ @return 0 if successful, >0 in case of errors.
+ */
+ int getopt(int argc, char* const argv[]);
+
+ //! Handle options and their arguments.
+ virtual int option(int opt, const std::string& optarg, int optopt);
+
+ //! Handle non-option parameters.
+ virtual int nonoption(const std::string& argv);
+
+ //! Print a minimal usage note to an output stream.
+ void usage(std::ostream& os =std::cout) const;
+
+ //! Print further usage explanations to an output stream.
+ void help(std::ostream& os =std::cout) const;
+
+ //! Print version information to an output stream.
+ void version(std::ostream& os =std::cout) const;
+}; // class Params
+
+#endif // #ifndef EXIV2_HPP_
Copied: Extractor/src/plugins/exiv2/exiv2extractor.cc (from rev 1226,
Extractor/src/plugins/exiv2extractor.cc)
Added: Extractor/src/plugins/exiv2/fujimn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/fujimn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/fujimn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,278 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: fujimn.cpp
+ Version: $Rev: 569 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 18-Feb-04, ahu: created
+ 07-Mar-04, ahu: isolated as a separate component
+ Credits: Fujifilm MakerNote implemented according to the specification
+ in "Appendix 4: Makernote of Fujifilm" of the document
+ "Exif file format" by TsuruZoh Tachibanaya
+
<http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html>
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: fujimn.cpp 569 2005-05-28 05:48:43Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "fujimn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ FujiMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("FUJIFILM", "*",
createFujiMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ fujiIfdId, MakerNote::AutoPtr(new FujiMakerNote));
+
+ ExifTags::registerMakerTagInfo(fujiIfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Fujifilm MakerNote Tag Info
+ const TagInfo FujiMakerNote::tagInfo_[] = {
+ TagInfo(0x0000, "Version", "Fujifilm Makernote version", fujiIfdId,
makerTags, undefined, printValue),
+ TagInfo(0x1000, "Quality", "Image quality setting", fujiIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x1001, "Sharpness", "Sharpness setting", fujiIfdId,
makerTags, unsignedShort, print0x1001),
+ TagInfo(0x1002, "WhiteBalance", "White balance setting", fujiIfdId,
makerTags, unsignedShort, print0x1002),
+ TagInfo(0x1003, "Color", "Chroma saturation setting", fujiIfdId,
makerTags, unsignedShort, print0x1003),
+ TagInfo(0x1004, "Tone", "Contrast setting", fujiIfdId, makerTags,
unsignedShort, print0x1004),
+ TagInfo(0x1010, "FlashMode", "Flash firing mode setting", fujiIfdId,
makerTags, unsignedShort, print0x1010),
+ TagInfo(0x1011, "FlashStrength", "Flash firing strength compensation
setting", fujiIfdId, makerTags, signedRational, printValue),
+ TagInfo(0x1020, "Macro", "Macro mode setting", fujiIfdId, makerTags,
unsignedShort, printOffOn),
+ TagInfo(0x1021, "FocusMode", "Focusing mode setting", fujiIfdId,
makerTags, unsignedShort, print0x1021),
+ TagInfo(0x1022, "0x1022", "Unknown", fujiIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1030, "SlowSync", "Slow synchro mode setting", fujiIfdId,
makerTags, unsignedShort, printOffOn),
+ TagInfo(0x1031, "PictureMode", "Picture mode setting", fujiIfdId,
makerTags, unsignedShort, print0x1031),
+ TagInfo(0x1032, "0x1032", "Unknown", fujiIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1100, "Continuous", "Continuous shooting or auto bracketing
setting", fujiIfdId, makerTags, unsignedShort, printOffOn),
+ TagInfo(0x1101, "0x1101", "Unknown", fujiIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1200, "0x1200", "Unknown", fujiIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1300, "BlurWarning", "Blur warning status", fujiIfdId,
makerTags, unsignedShort, printOffOn),
+ TagInfo(0x1301, "FocusWarning", "Auto Focus warning status",
fujiIfdId, makerTags, unsignedShort, printOffOn),
+ TagInfo(0x1302, "AeWarning", "Auto Exposure warning status",
fujiIfdId, makerTags, unsignedShort, printOffOn),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownFujiMakerNoteTag)", "Unknown FujiMakerNote
tag", fujiIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ FujiMakerNote::FujiMakerNote(bool alloc)
+ : IfdMakerNote(fujiIfdId, alloc)
+ {
+ byteOrder_ = littleEndian;
+ absOffset_ = false;
+ byte buf[] = {
+ 'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00
+ };
+ readHeader(buf, 12, byteOrder_);
+ }
+
+ FujiMakerNote::FujiMakerNote(const FujiMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int FujiMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 12) return 1;
+
+ header_.alloc(12);
+ memcpy(header_.pData_, buf, header_.size_);
+ // Read the offset relative to the start of the makernote from the
header
+ // Note: we ignore the byteOrder paramter
+ adjOffset_ = getUShort(header_.pData_ + 8, byteOrder_);
+ return 0;
+ }
+
+ int FujiMakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the FUJIFILM prefix
+ if ( header_.size_ < 12
+ || std::string(reinterpret_cast<char*>(header_.pData_), 8)
+ != std::string("FUJIFILM", 8)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ FujiMakerNote::AutoPtr FujiMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ FujiMakerNote* FujiMakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote = AutoPtr(new FujiMakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ FujiMakerNote::AutoPtr FujiMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ FujiMakerNote* FujiMakerNote::clone_() const
+ {
+ return new FujiMakerNote(*this);
+ }
+
+ std::ostream& FujiMakerNote::printOffOn(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Off"; break;
+ case 1: os << "On"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1001(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 1: // fallthrough
+ case 2: os << "Soft"; break;
+ case 3: os << "Normal"; break;
+ case 4: // fallthrough
+ case 5: os << "Hard"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1002(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Auto"; break;
+ case 256: os << "Daylight"; break;
+ case 512: os << "Cloudy"; break;
+ case 768: os << "Fluorescent (daylight)"; break;
+ case 769: os << "Fluorescent (warm white)"; break;
+ case 770: os << "Fluorescent (cool white)"; break;
+ case 1024: os << "Incandescent"; break;
+ case 3480: os << "Custom"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1003(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Standard"; break;
+ case 256: os << "High"; break;
+ case 512: os << "Original"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1004(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Standard"; break;
+ case 256: os << "Hard"; break;
+ case 512: os << "Original"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1010(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Auto"; break;
+ case 1: os << "On"; break;
+ case 2: os << "Off"; break;
+ case 3: os << "Red-eye"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1021(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Manual"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& FujiMakerNote::print0x1031(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toLong()) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Portrait"; break;
+ case 2: os << "Landscape"; break;
+ case 4: os << "Sports"; break;
+ case 5: os << "Night"; break;
+ case 6: os << "Program"; break;
+ case 256: os << "Aperture priority"; break;
+ case 512: os << "Shutter priority"; break;
+ case 768: os << "Manual"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createFujiMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new FujiMakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/fujimn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/fujimn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/fujimn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,162 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file fujimn.hpp
+ @brief Fujifilm MakerNote implemented according to the specification
+ in Appendix 4: Makernote of Fujifilm of the document
+ <a
href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html">
+ Exif file format</a> by TsuruZoh Tachibanaya
+ @version $Rev: 569 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 11-Feb-04, ahu: created
+ */
+#ifndef FUJIMN_HPP_
+#define FUJIMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createFujiMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Fujifilm cameras
+ class FujiMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %FujiMakerNote auto pointer.
+ typedef std::auto_ptr<FujiMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ FujiMakerNote(bool alloc =true);
+ //! Copy constructor
+ FujiMakerNote(const FujiMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~FujiMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Fujifilm %MakerNote tags
+ //@{
+ //! Print Off or On status
+ static std::ostream& printOffOn(std::ostream& os, const Value& value);
+ //! Print sharpness
+ static std::ostream& print0x1001(std::ostream& os, const Value& value);
+ //! Print white balance
+ static std::ostream& print0x1002(std::ostream& os, const Value& value);
+ //! Print color
+ static std::ostream& print0x1003(std::ostream& os, const Value& value);
+ //! Print tone
+ static std::ostream& print0x1004(std::ostream& os, const Value& value);
+ //! Print flash mode
+ static std::ostream& print0x1010(std::ostream& os, const Value& value);
+ //! Print focus mode
+ static std::ostream& print0x1021(std::ostream& os, const Value& value);
+ //! Print picture mode
+ static std::ostream& print0x1031(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ FujiMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ FujiMakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class FujiMakerNote
+
+ static FujiMakerNote::RegisterMn registerFujiMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef FUJIMN_HPP_
Added: Extractor/src/plugins/exiv2/futils.cpp
===================================================================
--- Extractor/src/plugins/exiv2/futils.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/futils.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,78 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: utils.cpp
+ Version: $Rev: 560 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 08-Dec-03, ahu: created
+ 02-Apr-05, ahu: moved to Exiv2 namespace
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: futils.cpp 560 2005-04-17 11:51:32Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "futils.hpp"
+
+// + standard includes
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _MSC_VER
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // for stat()
+#endif
+
+#include <cerrno>
+#include <cstring>
+#include <sstream>
+
+namespace Exiv2 {
+
+//
*****************************************************************************
+// free functions
+
+ bool fileExists(const std::string& path, bool ct)
+ {
+ struct stat buf;
+ int ret = stat(path.c_str(), &buf);
+ if (0 != ret) return false;
+ if (ct && !S_ISREG(buf.st_mode)) return false;
+ return true;
+ } // fileExists
+
+ std::string strError()
+ {
+ int error = errno;
+ std::ostringstream os;
+ os << strerror(error) << " (" << error << ")";
+ return os.str();
+ } // strError
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/futils.hpp
===================================================================
--- Extractor/src/plugins/exiv2/futils.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/futils.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,66 @@
+// ********************************************************* -*- C++ -*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file futils.hpp
+ @brief Basic file utility functions required by Exiv2
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 12-Dec-03, ahu: created<BR>
+ 02-Apr-05, ahu: moved to Exiv2 namespace
+ */
+#ifndef FUTILS_HPP_
+#define FUTILS_HPP_
+
+// *********************************************************************
+// included header files
+// + standard includes
+#include <string>
+
+// *********************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+// *********************************************************************
+// free functions
+
+ /*!
+ @brief Test if a file exists.
+
+ @param path Name of file to verify.
+ @param ct Flag to check if <i>path</i> is a regular file.
+ @return true if <i>path</i> exists and, if <i>ct</i> is set,
+ is a regular file, else false.
+
+ @note The function calls <b>stat()</b> test for <i>path</i>
+ and its type, see stat(2). <b>errno</b> is left unchanged
+ in case of an error.
+ */
+ bool fileExists(const std::string& path, bool ct =false);
+ /*!
+ @brief Return a system error message and the error code (errno).
+ See %strerror(3).
+ */
+ std::string strError();
+
+} // namespace Exiv2
+
+#endif // #ifndef FUTILS_HPP_
Added: Extractor/src/plugins/exiv2/ifd.cpp
===================================================================
--- Extractor/src/plugins/exiv2/ifd.cpp 2005-07-03 19:32:53 UTC (rev 1227)
+++ Extractor/src/plugins/exiv2/ifd.cpp 2005-07-03 19:43:52 UTC (rev 1228)
@@ -0,0 +1,719 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: ifd.cpp
+ Version: $Rev: 562 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: ifd.cpp 562 2005-04-20 18:16:29Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "ifd.hpp"
+#include "types.hpp"
+#include "error.hpp"
+#include "tags.hpp" // for ExifTags::ifdName
+
+// + standard includes
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <cstring>
+#include <cassert>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Entry::Entry(bool alloc)
+ : alloc_(alloc), ifdId_(ifdIdNotSet), idx_(0),
+ tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0),
+ sizeDataArea_(0), pDataArea_(0)
+ {
+ }
+
+ Entry::~Entry()
+ {
+ if (alloc_) {
+ delete[] pData_;
+ delete[] pDataArea_;
+ }
+ }
+
+ Entry::Entry(const Entry& rhs)
+ : alloc_(rhs.alloc_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
+ tag_(rhs.tag_), type_(rhs.type_),
+ count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_),
pData_(0),
+ sizeDataArea_(rhs.sizeDataArea_), pDataArea_(0)
+ {
+ if (alloc_) {
+ if (rhs.pData_) {
+ pData_ = new byte[rhs.size()];
+ memcpy(pData_, rhs.pData_, rhs.size());
+ }
+ if (rhs.pDataArea_) {
+ pDataArea_ = new byte[rhs.sizeDataArea()];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
+ }
+ }
+ else {
+ pData_ = rhs.pData_;
+ pDataArea_ = rhs.pDataArea_;
+ }
+ }
+
+ Entry& Entry::operator=(const Entry& rhs)
+ {
+ if (this == &rhs) return *this;
+ alloc_ = rhs.alloc_;
+ ifdId_ = rhs.ifdId_;
+ idx_ = rhs.idx_;
+ tag_ = rhs.tag_;
+ type_ = rhs.type_;
+ count_ = rhs.count_;
+ offset_ = rhs.offset_;
+ size_ = rhs.size_;
+ sizeDataArea_ = rhs.sizeDataArea_;
+ if (alloc_) {
+ delete[] pData_;
+ pData_ = 0;
+ if (rhs.pData_) {
+ pData_ = new byte[rhs.size()];
+ memcpy(pData_, rhs.pData_, rhs.size());
+ }
+ delete[] pDataArea_;
+ pDataArea_ = 0;
+ if (rhs.pDataArea_) {
+ pDataArea_ = new byte[rhs.sizeDataArea()];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
+ }
+ }
+ else {
+ pData_ = rhs.pData_;
+ pDataArea_ = rhs.pDataArea_;
+ }
+ return *this;
+ } // Entry::operator=
+
+ void Entry::setValue(uint32_t data, ByteOrder byteOrder)
+ {
+ if (pData_ == 0 || size_ < 4) {
+ assert(alloc_);
+ size_ = 4;
+ delete[] pData_;
+ pData_ = new byte[size_];
+ }
+ ul2Data(pData_, data, byteOrder);
+ // do not change size_
+ type_ = unsignedLong;
+ count_ = 1;
+ }
+
+ void Entry::setValue(uint16_t type, uint32_t count, const byte* buf, long
len)
+ {
+ long dataSize = count * TypeInfo::typeSize(TypeId(type));
+ // No minimum size requirement, but make sure the buffer can hold the
data
+ if (len < dataSize) throw Error(24, tag(), dataSize, len);
+ if (alloc_) {
+ delete[] pData_;
+ pData_ = new byte[len];
+ memset(pData_, 0x0, len);
+ memcpy(pData_, buf, dataSize);
+ size_ = len;
+ }
+ else {
+ if (size_ == 0) {
+ // Set the data pointer of a virgin entry
+ pData_ = const_cast<byte*>(buf);
+ size_ = len;
+ }
+ else {
+ // Overwrite existing data if it fits into the buffer
+ if (size_ < dataSize) throw Error(24, tag(), dataSize, size_);
+ memset(pData_, 0x0, size_);
+ memcpy(pData_, buf, dataSize);
+ // do not change size_
+ }
+ }
+ type_ = type;
+ count_ = count;
+ } // Entry::setValue
+
+ void Entry::setDataArea(const byte* buf, long len)
+ {
+ if (alloc_) {
+ delete[] pDataArea_;
+ pDataArea_ = new byte[len];
+ memcpy(pDataArea_, buf, len);
+ sizeDataArea_ = len;
+ }
+ else {
+ if (sizeDataArea_ == 0) {
+ // Set the data area pointer of a virgin entry
+ pDataArea_ = const_cast<byte*>(buf);
+ sizeDataArea_ = len;
+ }
+ else {
+ // Overwrite existing data if it fits into the buffer
+ if (sizeDataArea_ < len) {
+ throw Error(25, tag(), sizeDataArea_, len);
+ }
+ memset(pDataArea_, 0x0, sizeDataArea_);
+ memcpy(pDataArea_, buf, len);
+ // do not change sizeDataArea_
+ }
+ }
+ } // Entry::setDataArea
+
+ void Entry::setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder)
+ {
+ for (uint32_t i = 0; i < count(); ++i) {
+ byte* buf = pData_ + i * typeSize();
+ switch(TypeId(type())) {
+ case unsignedShort: {
+ uint16_t d = getUShort(buf, byteOrder);
+ if (d + offset > 0xffff) throw Error(26);
+ us2Data(buf, d + static_cast<uint16_t>(offset), byteOrder);
+ break;
+ }
+ case unsignedLong: {
+ ul2Data(buf, getULong(buf, byteOrder) + offset, byteOrder);
+ break;
+ }
+ case unsignedRational: {
+ URational d = getURational(buf, byteOrder);
+ d.first = d.first + offset * d.second;
+ ur2Data(buf, d, byteOrder);
+ break;
+ }
+ case signedShort: {
+ int16_t d = getShort(buf, byteOrder);
+ if (d + static_cast<int32_t>(offset) > 0xffff) throw Error(26);
+ s2Data(buf, d + static_cast<int16_t>(offset), byteOrder);
+ break;
+ }
+ case signedLong: {
+ int32_t d = getLong(buf, byteOrder);
+ l2Data(buf, d + static_cast<int32_t>(offset), byteOrder);
+ break;
+ }
+ case signedRational: {
+ Rational d = getRational(buf, byteOrder);
+ d.first = d.first + static_cast<int32_t>(offset) * d.second;
+ r2Data(buf, d, byteOrder);
+ break;
+ }
+ default:
+ throw Error(27);
+ break;
+ }
+ }
+ } // Entry::setDataAreaOffsets
+
+ void Entry::updateBase(byte* pOldBase, byte* pNewBase)
+ {
+ if (!alloc_) {
+ if (pDataArea_) {
+ pDataArea_ = pDataArea_ - pOldBase + pNewBase;
+ }
+ if (pData_) {
+ pData_ = pData_ - pOldBase + pNewBase;
+ }
+ }
+ } // Entry::updateBase
+
+ const byte* Entry::component(uint32_t n) const
+ {
+ if (n >= count()) return 0;
+ return data() + n * typeSize();
+ } // Entry::component
+
+ Ifd::Ifd(IfdId ifdId)
+ : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(0),
+ dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
+ {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+
+ Ifd::Ifd(IfdId ifdId, long offset)
+ : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(offset),
+ dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
+ {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+
+ Ifd::Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext)
+ : alloc_(alloc), ifdId_(ifdId), pBase_(0), offset_(offset),
+ dataOffset_(0), hasNext_(hasNext), pNext_(0), next_(0)
+ {
+ if (alloc_ && hasNext_) {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ }
+ }
+
+ Ifd::~Ifd()
+ {
+ // do not delete pBase_
+ if (alloc_ && hasNext_) delete[] pNext_;
+ }
+
+ Ifd::Ifd(const Ifd& rhs)
+ : alloc_(rhs.alloc_), entries_(rhs.entries_), ifdId_(rhs.ifdId_),
+ pBase_(rhs.pBase_), offset_(rhs.offset_),
dataOffset_(rhs.dataOffset_),
+ hasNext_(rhs.hasNext_), pNext_(rhs.pNext_), next_(rhs.next_)
+ {
+ if (alloc_ && hasNext_) {
+ pNext_ = new byte[4];
+ memset(pNext_, 0x0, 4);
+ if (rhs.pNext_) memcpy(pNext_, rhs.pNext_, 4);
+ }
+ }
+
+ int Ifd::read(const byte* buf, long len, ByteOrder byteOrder, long offset)
+ {
+ // Todo: This is a hack to work around bug #424 - fix it properly!
+ if (ifdId_ == olympusIfdId) len = 65535;
+
+ int rc = 0;
+ long o = 0;
+ Ifd::PreEntries preEntries;
+
+ if (len < 2) rc = 6;
+ if (rc == 0) {
+ offset_ = offset;
+ int n = getUShort(buf, byteOrder);
+ o = 2;
+
+ for (int i = 0; i < n; ++i) {
+ if (len < o + 12) {
+ // Todo: How to handle debug output like this
+ std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
+ << " entry " << i
+ << " lies outside of the IFD memory buffer.\n";
+ rc = 6;
+ break;
+ }
+ Ifd::PreEntry pe;
+ pe.tag_ = getUShort(buf + o, byteOrder);
+ pe.type_ = getUShort(buf + o + 2, byteOrder);
+ pe.count_ = getULong(buf + o + 4, byteOrder);
+ pe.size_ = pe.count_ * TypeInfo::typeSize(TypeId(pe.type_));
+ pe.offsetLoc_ = o + 8;
+ pe.offset_ = pe.size_ > 4 ? getLong(buf + o + 8, byteOrder) :
0;
+ preEntries.push_back(pe);
+ o += 12;
+ }
+ }
+ if (rc == 0 && hasNext_) {
+ if (len < o + 4) {
+ // Todo: How to handle debug output like this
+ std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
+ << " memory of the pointer to the next IFD"
+ << " lies outside of the IFD memory buffer.\n";
+ rc = 6;
+ }
+ else {
+ if (alloc_) {
+ memcpy(pNext_, buf + o, 4);
+ }
+ else {
+ pNext_ = const_cast<byte*>(buf + o);
+ }
+ next_ = getULong(buf + o, byteOrder);
+ }
+ }
+ // Set the offset of the first data entry outside of the IFD.
+ // At the same time we guess the offset of the IFD, if it was not
+ // given. The guess is based on the assumption that the smallest offset
+ // points to a data buffer directly following the IFD. Subsequently all
+ // offsets of IFD entries will need to be recalculated.
+ if (rc == 0 && preEntries.size() > 0) {
+ // Find the entry with the smallest offset
+ Ifd::PreEntries::const_iterator i = std::min_element(
+ preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset);
+ // Only do something if there is at least one entry with data
+ // outside the IFD directory itself.
+ if (i->size_ > 4) {
+ if (offset_ == 0) {
+ // Set the 'guessed' IFD offset
+ offset_ = i->offset_
+ - (2 + 12 * static_cast<long>(preEntries.size())
+ + (hasNext_ ? 4 : 0));
+ }
+ // Set the offset of the first data entry outside of the IFD
+ if (i->offset_ - offset_ >= len) {
+ // Todo: How to handle debug output like this
+ std::cerr << "Error: Offset of the 1st data entry of "
+ << ExifTags::ifdName(ifdId_)
+ << " is out of bounds:\n"
+ << " Offset = 0x" << std::setw(8)
+ << std::setfill('0') << std::hex
+ << i->offset_ - offset_
+ << ", exceeds buffer size by "
+ << std::dec << i->offset_ - len
+ << " Bytes\n";
+ rc = 6;
+ }
+ else {
+ dataOffset_ = i->offset_;
+ }
+ }
+ }
+ // Convert the pre-IFD entries to the actual entries, assign the data
+ // to each IFD entry and calculate relative offsets, relative to the
+ // start of the IFD
+ if (rc == 0) {
+ entries_.clear();
+ int idx = 0;
+ const Ifd::PreEntries::iterator begin = preEntries.begin();
+ const Ifd::PreEntries::iterator end = preEntries.end();
+ for (Ifd::PreEntries::iterator i = begin; i != end; ++i) {
+ Entry e(alloc_);
+ e.setIfdId(ifdId_);
+ e.setIdx(++idx);
+ e.setTag(i->tag_);
+ long tmpOffset =
+ i->size_ > 4 ? i->offset_ - offset_ : i->offsetLoc_;
+ if (tmpOffset + i->size_ > len) {
+ // Todo: How to handle debug output like this
+ std::cerr << "Warning: Upper boundary of data for "
+ << ExifTags::ifdName(ifdId_)
+ << " entry " << static_cast<int>(i - begin)
+ << " is out of bounds:\n"
+ << " Offset = 0x" << std::setw(8)
+ << std::setfill('0') << std::hex
+ << tmpOffset
+ << ", size = " << std::dec << i->size_
+ << ", exceeds buffer size by "
+ << tmpOffset + i->size_ - len
+ << " Bytes; Truncating the data.\n";
+ // Truncate the entry
+ i->size_ = 0;
+ i->count_ = 0;
+ tmpOffset = i->offsetLoc_;
+ }
+ // Set the offset to the data, relative to start of IFD
+ e.setOffset(tmpOffset);
+ // Set the size to at least for bytes to accomodate offset-data
+ e.setValue(i->type_, i->count_, buf + e.offset(),
+ std::max(long(4), i->size_));
+ this->add(e);
+ }
+ }
+ if (!alloc_) pBase_ = const_cast<byte*>(buf) - offset_;
+ if (rc) this->clear();
+
+ return rc;
+ } // Ifd::read
+
+ Ifd::const_iterator Ifd::findIdx(int idx) const
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByIdx(idx));
+ }
+
+ Ifd::iterator Ifd::findIdx(int idx)
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByIdx(idx));
+ }
+
+ Ifd::const_iterator Ifd::findTag(uint16_t tag) const
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByTag(tag));
+ }
+
+ Ifd::iterator Ifd::findTag(uint16_t tag)
+ {
+ return std::find_if(entries_.begin(), entries_.end(),
+ FindEntryByTag(tag));
+ }
+
+ void Ifd::sortByTag()
+ {
+ std::sort(entries_.begin(), entries_.end(), cmpEntriesByTag);
+ }
+
+ int Ifd::readSubIfd(
+ Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag
+ ) const
+ {
+ int rc = 0;
+ const_iterator pos = findTag(tag);
+ if (pos != entries_.end()) {
+ long offset = getULong(pos->data(), byteOrder);
+ if (len < offset) {
+ rc = 6;
+ }
+ else {
+ rc = dest.read(buf + offset, len - offset, byteOrder, offset);
+ }
+ }
+ return rc;
+ } // Ifd::readSubIfd
+
+ long Ifd::copy(byte* buf, ByteOrder byteOrder, long offset)
+ {
+ if (entries_.size() == 0 && next_ == 0) return 0;
+ if (offset != 0) offset_ = offset;
+
+ // Add the number of entries to the data buffer
+ us2Data(buf, static_cast<uint16_t>(entries_.size()), byteOrder);
+ long o = 2;
+
+ // Add all directory entries to the data buffer
+ long dataSize = 0;
+ long dataAreaSize = 0;
+ long totalDataSize = 0;
+ const iterator b = entries_.begin();
+ const iterator e = entries_.end();
+ iterator i;
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ totalDataSize += i->size();
+ }
+ }
+ for (i = b; i != e; ++i) {
+ us2Data(buf + o, i->tag(), byteOrder);
+ us2Data(buf + o + 2, i->type(), byteOrder);
+ ul2Data(buf + o + 4, i->count(), byteOrder);
+ if (i->sizeDataArea() > 0) {
+ long dataAreaOffset =
offset_+size()+totalDataSize+dataAreaSize;
+ i->setDataAreaOffsets(dataAreaOffset, byteOrder);
+ dataAreaSize += i->sizeDataArea();
+ }
+ if (i->size() > 4) {
+ // Set the offset of the entry, data immediately follows the
IFD
+ i->setOffset(size() + dataSize);
+ l2Data(buf + o + 8, offset_ + i->offset(), byteOrder);
+ dataSize += i->size();
+ }
+ else {
+ // Copy data into the offset field
+ memset(buf + o + 8, 0x0, 4);
+ memcpy(buf + o + 8, i->data(), i->size());
+ }
+ o += 12;
+ }
+
+ if (hasNext_) {
+ // Add the offset to the next IFD to the data buffer
+ if (pNext_) {
+ memcpy(buf + o, pNext_, 4);
+ }
+ else {
+ memset(buf + o, 0x0, 4);
+ }
+ o += 4;
+ }
+
+ // Add the data of all IFD entries to the data buffer
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ memcpy(buf + o, i->data(), i->size());
+ o += i->size();
+ }
+ }
+
+ // Add all data areas to the data buffer
+ for (i = b; i != e; ++i) {
+ if (i->sizeDataArea() > 0) {
+ memcpy(buf + o, i->dataArea(), i->sizeDataArea());
+ o += i->sizeDataArea();
+ }
+ }
+
+ return o;
+ } // Ifd::copy
+
+ void Ifd::clear()
+ {
+ entries_.clear();
+ offset_ = 0;
+ dataOffset_ = 0;
+ if (hasNext_) {
+ if (alloc_) {
+ memset(pNext_, 0x0, 4);
+ }
+ else {
+ pBase_ = 0;
+ pNext_ = 0;
+ }
+ next_ = 0;
+ }
+ } // Ifd::clear
+
+ void Ifd::setNext(uint32_t next, ByteOrder byteOrder)
+ {
+ if (hasNext_) {
+ assert(pNext_);
+ ul2Data(pNext_, next, byteOrder);
+ next_ = next;
+ }
+ }
+
+ void Ifd::add(const Entry& entry)
+ {
+ assert(alloc_ == entry.alloc());
+ assert(ifdId_ == entry.ifdId());
+ // allow duplicates
+ entries_.push_back(entry);
+ }
+
+ int Ifd::erase(uint16_t tag)
+ {
+ int idx = 0;
+ iterator pos = findTag(tag);
+ if (pos != end()) {
+ idx = pos->idx();
+ erase(pos);
+ }
+ return idx;
+ }
+
+ Ifd::iterator Ifd::erase(iterator pos)
+ {
+ return entries_.erase(pos);
+ }
+
+ byte* Ifd::updateBase(byte* pNewBase)
+ {
+ byte *pOld = 0;
+ if (!alloc_) {
+ iterator end = this->end();
+ for (iterator pos = begin(); pos != end; ++pos) {
+ pos->updateBase(pBase_, pNewBase);
+ }
+ if (hasNext_) {
+ pNext_ = pNext_ - pBase_ + pNewBase;
+ }
+ pOld = pBase_;
+ pBase_ = pNewBase;
+ }
+ return pOld;
+ }
+
+ long Ifd::size() const
+ {
+ if (entries_.size() == 0 && next_ == 0) return 0;
+ return static_cast<long>(2 + 12 * entries_.size() + (hasNext_ ? 4 :
0));
+ }
+
+ long Ifd::dataSize() const
+ {
+ long dataSize = 0;
+ const_iterator end = this->end();
+ for (const_iterator i = begin(); i != end; ++i) {
+ if (i->size() > 4) dataSize += i->size();
+ dataSize += i->sizeDataArea();
+ }
+ return dataSize;
+ }
+
+ void Ifd::print(std::ostream& os, const std::string& prefix) const
+ {
+ if (entries_.size() == 0) return;
+ // Print a header
+ os << prefix << "IFD Offset: 0x"
+ << std::setw(8) << std::setfill('0') << std::hex << std::right
+ << offset_
+ << ", IFD Entries: "
+ << std::setfill(' ') << std::dec << std::right
+ << static_cast<unsigned int>(entries_.size()) << "\n"
+ << prefix << "Entry Tag Format (Bytes each) Number
Offset\n"
+ << prefix << "----- ------ --------------------- ------
-----------\n";
+ // Print IFD entries
+ const const_iterator b = entries_.begin();
+ const const_iterator e = entries_.end();
+ const_iterator i = b;
+ for (; i != e; ++i) {
+ std::ostringstream offset;
+ if (i->size() > 4) {
+ offset << " 0x" << std::setw(8) << std::setfill('0')
+ << std::hex << std::right << i->offset();
+ }
+ else {
+ const byte* data = i->data();
+ for (int k = 0; k < i->size(); ++k) {
+ offset << std::setw(2) << std::setfill('0') << std::hex
+ << (int)data[k] << " ";
+ }
+ }
+ os << prefix << std::setw(5) << std::setfill(' ') << std::dec
+ << std::right << static_cast<int>(i - b)
+ << " 0x" << std::setw(4) << std::setfill('0') << std::hex
+ << std::right << i->tag()
+ << " " << std::setw(17) << std::setfill(' ')
+ << std::left << i->typeName()
+ << " (" << std::dec << i->typeSize() << ")"
+ << " " << std::setw(6) << std::setfill(' ') << std::dec
+ << std::right << i->count()
+ << " " << offset.str()
+ << "\n";
+ }
+ if (hasNext_) {
+ os << prefix << "Next IFD: 0x"
+ << std::setw(8) << std::setfill('0') << std::hex
+ << std::right << next() << "\n";
+ }
+ // Print data of IFD entries
+ for (i = b; i != e; ++i) {
+ if (i->size() > 4) {
+ os << "Data of entry " << static_cast<int>(i - b) << ":\n";
+ hexdump(os, i->data(), i->size(), offset_ + i->offset());
+ }
+ }
+
+ } // Ifd::print
+
+ //
*************************************************************************
+ // free functions
+
+ bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.tag() < rhs.tag();
+ }
+
+ bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry&
rhs)
+ {
+ // We need to ignore entries with size <= 4, so by definition,
+ // entries with size <= 4 are greater than those with size > 4
+ // when compared by their offset.
+ if (lhs.size_ <= 4) {
+ return false; // lhs is greater by definition, or they are equal
+ }
+ if (rhs.size_ <= 4) {
+ return true; // rhs is greater by definition (they cannot be equal)
+ }
+ return lhs.offset_ < rhs.offset_;
+ } // cmpPreEntriesByOffset
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/ifd.hpp
===================================================================
--- Extractor/src/plugins/exiv2/ifd.hpp 2005-07-03 19:32:53 UTC (rev 1227)
+++ Extractor/src/plugins/exiv2/ifd.hpp 2005-07-03 19:43:52 UTC (rev 1228)
@@ -0,0 +1,601 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file ifd.hpp
+ @brief Encoding and decoding of IFD (%Image File Directory) data
+ @version $Rev: 562 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created<BR>
+ 11-Feb-04, ahu: isolated as a component
+ */
+#ifndef IFD_HPP_
+#define IFD_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Ifd;
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Data structure for one IFD directory entry. See the description of
+ class Ifd for an explanation of the supported modes for memory
+ allocation.
+ */
+ class Entry {
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Default constructor. The entry allocates memory for its
+ data if alloc is true (the default), otherwise it remembers
+ just the pointers into a read and writeable data buffer which
+ it doesn't allocate or delete.
+ */
+ explicit Entry(bool alloc =true);
+ //! Destructor
+ ~Entry();
+ //! Copy constructor
+ Entry(const Entry& rhs);
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator
+ Entry& operator=(const Entry& rhs);
+ //! Set the tag
+ void setTag(uint16_t tag) { tag_ = tag; }
+ //! Set the IFD id
+ void setIfdId(IfdId ifdId) { ifdId_ = ifdId; }
+ //! Set the index (unique id of an entry within one IFD)
+ void setIdx(int idx) { idx_ = idx; }
+ //! Set the offset. The offset is relative to the start of the IFD.
+ void setOffset(long offset) { offset_ = offset; }
+ /*!
+ @brief Set the value of the entry to a single unsigned long
component,
+ i.e., set the type of the entry to unsigned long, number of
+ components to one and the value according to the data
provided.
+
+ The size of the data buffer is set to at least four bytes, but is
left
+ unchanged if it can accomodate the pointer. This method can be used
+ to set the value of a tag which contains a pointer (offset) to a
+ location in the Exif data (like e.g., ExifTag, 0x8769 in IFD0, which
+ contains a pointer to the Exif IFD).
+ <BR>This method cannot be used to set the value of a newly created
+ %Entry in non-alloc mode.
+
+ @note This method is now deprecated, use data area related methods
+ instead.
+ */
+ void setValue(uint32_t data, ByteOrder byteOrder);
+ /*!
+ @brief Set type, count, the data buffer and its size.
+
+ Copies the provided buffer when called in memory allocation mode.
+ <BR>In non-alloc mode, use this method to initialise the data of a
+ newly created %Entry. In this case, only the pointer to the buffer
is
+ copied, i.e., the buffer must remain valid throughout the life of the
+ %Entry. Subsequent calls in non-alloc mode will overwrite the data
+ pointed to by this pointer with the data provided, i.e., the buffer
+ provided in subsequent calls can be deleted after the call.
+ <BR>In either memory allocation mode, the data buffer provided must
be
+ large enough to hold count components of type. The size of the
buffer
+ will be as indicated in the size argument. I.e., it is possible to
+ allocate (set) a data buffer larger than required to hold count
+ components of the given type.
+
+ @param type The type of the data.
+ @param count Number of components in the buffer.
+ @param data Pointer to the data buffer.
+ @param size Size of the desired data buffer in bytes.
+ @throw Error if no memory allocation is allowed
+ and the size of the data buffer is larger than the existing
+ data buffer of the entry or if size is not large enough to
hold
+ count components of the given type.
+ */
+ void setValue(uint16_t type, uint32_t count, const byte* data, long
size);
+ /*!
+ @brief Set the data area. Memory management as for
+ setValue(uint16_t, uint32_t, const byte*, long)
+
+ For certain tags the regular value of an IFD entry is an offset to a
+ data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
+ (Exif.Image.ExifTag) or tag 0x0201 in IFD1
+ (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
+ to a data area containing the Exif IFD. That of JPEGInterchangeFormat
+ contains the JPEG thumbnail image.
+ This method sets the data area of a tag in accordance with the memory
+ allocation mode.
+
+ @param buf Pointer to the data area.
+ @param len Size of the data area.
+
+ @throw Error in non-alloc mode, if there already is a dataarea but
the
+ size of the existing dataarea is not large enough for the
+ new buffer.
+ */
+ void setDataArea(const byte* buf, long len);
+ /*!
+ @brief Set the offset(s) to the data area of an entry.
+
+ Add @em offset to each data component of the entry. This is used by
+ Ifd::copy to convert the data components of an entry containing
+ offsets relative to the data area to become offsets from the start of
+ the TIFF header. Usually, entries with a data area have exactly one
+ unsigned long data component, which is 0.
+
+ @param offset Offset
+ @param byteOrder Byte order
+
+ @throw Error if the offset is out of range for the data type of the
+ tag or the data type is not supported.
+ */
+ void setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder);
+ /*!
+ @brief Update the base pointer of the Entry from \em pOldBase
+ to \em pNewBase.
+
+ Allows to re-locate the underlying data buffer to a new location
+ \em pNewBase. This method only has an effect in non-alloc mode.
+
+ @param pOldBase Base pointer of the old data buffer
+ @param pNewBase Base pointer of the new data buffer
+ */
+ void updateBase(byte* pOldBase, byte* pNewBase);
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Return the tag
+ uint16_t tag() const { return tag_; }
+ //! Return the type id.
+ uint16_t type() const { return type_; }
+ //! Return the name of the type
+ const char* typeName() const
+ { return TypeInfo::typeName(TypeId(type_)); }
+ //! Return the size in bytes of one element of this type
+ long typeSize() const
+ { return TypeInfo::typeSize(TypeId(type_)); }
+ //! Return the IFD id
+ IfdId ifdId() const { return ifdId_; }
+ //! Return the index (unique id >0 of an entry within an IFD, 0 if not
set)
+ int idx() const { return idx_; }
+ //! Return the number of components in the value
+ uint32_t count() const { return count_; }
+ /*!
+ @brief Return the size of the data buffer in bytes.
+ @note There is no minimum size for the data buffer, except that it
+ must be large enough to hold the data.
+ */
+ long size() const { return size_; }
+ //! Return the offset from the start of the IFD to the data of the
entry
+ long offset() const { return offset_; }
+ /*!
+ @brief Return a pointer to the data buffer. Do not attempt to write
+ to this pointer.
+ */
+ const byte* data() const { return pData_; }
+ /*!
+ @brief Return a pointer to the n-th component, 0 if there is no
+ n-th component. Do not attempt to write to this pointer.
+ */
+ const byte* component(uint32_t n) const;
+ //! Get the memory allocation mode
+ bool alloc() const { return alloc_; }
+ //! Return the size of the data area.
+ long sizeDataArea() const { return sizeDataArea_; }
+ /*!
+ @brief Return a pointer to the data area. Do not attempt to write to
+ this pointer.
+
+ For certain tags the regular value of an IFD entry is an offset to a
+ data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
+ (Exif.Image.ExifTag) or tag 0x0201 in IFD1
+ (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
+ to a data area containing the Exif IFD. That of JPEGInterchangeFormat
+ contains the JPEG thumbnail image.
+ Use this method to access (read-only) the data area of a tag. Use
+ setDataArea() to write to the data area.
+
+ @return Return a pointer to the data area.
+ */
+ const byte* dataArea() const { return pDataArea_; }
+ //@}
+
+ private:
+ // DATA
+ /*!
+ True: Requires memory allocation and deallocation,<BR>
+ False: No memory management needed.
+ */
+ bool alloc_;
+ //! Redundant IFD id (it is also at the IFD)
+ IfdId ifdId_;
+ //! Unique id of an entry within an IFD (0 if not set)
+ int idx_;
+ //! Tag
+ uint16_t tag_;
+ //! Type
+ uint16_t type_;
+ //! Number of components
+ uint32_t count_;
+ //! Offset from the start of the IFD to the data
+ long offset_;
+ /*!
+ Size of the data buffer holding the value in bytes, there is
+ no minimum size.
+ */
+ long size_;
+ //! Pointer to the data buffer
+ byte* pData_;
+ //! Size of the data area
+ long sizeDataArea_;
+ //! Pointer to the data area
+ byte* pDataArea_;
+
+ }; // class Entry
+
+ //! Container type to hold all IFD directory entries
+ typedef std::vector<Entry> Entries;
+
+ //! Unary predicate that matches an Entry with a given index
+ class FindEntryByIdx {
+ public:
+ //! Constructor, initializes the object with the index to look for
+ FindEntryByIdx(int idx) : idx_(idx) {}
+ /*!
+ @brief Returns true if the idx of the argument entry is equal
+ to that of the object.
+ */
+ bool operator()(const Entry& entry) const
+ { return idx_ == entry.idx(); }
+
+ private:
+ int idx_;
+
+ }; // class FindEntryByIdx
+
+ //! Unary predicate that matches an Entry with a given tag
+ class FindEntryByTag {
+ public:
+ //! Constructor, initializes the object with the tag to look for
+ FindEntryByTag(uint16_t tag) : tag_(tag) {}
+ /*!
+ @brief Returns true if the tag of the argument entry is equal
+ to that of the object.
+ */
+ bool operator()(const Entry& entry) const
+ { return tag_ == entry.tag(); }
+
+ private:
+ uint16_t tag_;
+
+ }; // class FindEntryByTag
+
+ /*!
+ @brief Models an IFD (%Image File Directory)
+
+ This class models an IFD as described in the TIFF 6.0 specification.
+
+ An instance of class %Ifd can operate in two modes, one that allocates
and
+ deallocates the memory required to store data, and one that doesn't
+ perform such memory management.
+ <BR>An external data buffer (not managed by %Ifd) is needed for an
instance
+ of %Ifd which operates in no memory management mode. The %Ifd will
+ maintain only pointers into this buffer.
+ <BR> The mode without memory management is used to make "non-intrusive
+ write support" possible. This allows writing to Exif data of an image
+ without changing the data layout of the Exif data, to maximize chances
+ that tag data, which the Exif reader may not understand (e.g., the
+ Makernote) remains valid. A "non-intrusive write operation" is the
+ modification of tag data without increasing the data size.
+
+ @note Use the mode with memory management (the default) if you are
unsure
+ or if these memory management considerations are of no concern to
you.
+
+ @note The two different modes imply completely different copy and
+ assignment behaviours, with the first resulting in entirely
separate
+ classes and the second mode resulting in multiple classes using one
+ and the same data buffer.
+ */
+ class Ifd {
+ //! @name Not implemented
+ //@{
+ //! Assignment not allowed (memory management mode alloc_ is const)
+ Ifd& operator=(const Ifd& rhs);
+ //@}
+
+ public:
+ //! %Entries const iterator type
+ typedef Entries::const_iterator const_iterator;
+ //! %Entries iterator type
+ typedef Entries::iterator iterator;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to set the IFD identifier. Memory
management
+ is enabled, offset is set to 0. Serves as default constructor.
+ */
+ explicit Ifd(IfdId ifdId =ifdIdNotSet);
+ /*!
+ @brief Constructor. Allows to set the IFD identifier and the offset
of
+ the IFD from the start of TIFF header. Memory management is
+ enabled.
+ */
+ Ifd(IfdId ifdId, long offset);
+ /*!
+ @brief Constructor. Allows to set the IFD identifier, offset of the
+ IFD from the start of TIFF header, choose whether or not
+ memory management is required for the Entries, and decide
+ whether this IFD has a next pointer.
+ */
+ Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext =true);
+ //! Copy constructor
+ Ifd(const Ifd& rhs);
+ //! Destructor
+ ~Ifd();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read a complete IFD and its data from a data buffer
+
+ @param buf Pointer to the data to decode. The buffer must start with
the
+ IFD data (unlike the readSubIfd() method).
+ @param len Number of bytes in the data buffer
+ @param byteOrder Applicable byte order (little or big endian).
+ @param offset (Optional) offset of the IFD from the start of the TIFF
+ header, if known. If not given, the offset will be guessed
+ using the assumption that the smallest offset of all IFD
+ directory entries points to a data buffer immediately follwing
+ the IFD.
+
+ @return 0 if successful;<BR>
+ 6 if the data buffer is too small, e.g., if an offset points
+ beyond the provided buffer. The IFD is cleared in this
+ case.
+ */
+ int read(const byte* buf, long len, ByteOrder byteOrder, long offset
=0);
+ /*!
+ @brief Copy the IFD to a data array, update the offsets of the IFD
and
+ all its entries, return the number of bytes written.
+
+ First the number of IFD entries is written (2 bytes), followed
+ by all directory entries: tag (2), type (2), number of data
+ components (4) and offset to the data or the data, if it
+ occupies not more than four bytes (4). The directory entries
+ are followed by the offset of the next IFD (4). All these
+ fields are encoded according to the byte order argument. Data
+ that doesn't fit into the offset fields follows immediately
+ after the IFD entries. The offsets in the IFD are set to
+ correctly point to the data fields, using the offset parameter
+ or the offset of the IFD.
+
+ @param buf Pointer to the data buffer. The user must ensure that the
+ buffer has enough memory. Otherwise the call results in
+ undefined behaviour.
+ @param byteOrder Applicable byte order (little or big endian).
+ @param offset Target offset from the start of the TIFF header of the
+ data array. The IFD offsets will be adjusted as necessary. If
+ not given, then it is assumed that the IFD will remain at its
+ original position, i.e., the offset of the IFD will be used.
+ @return Returns the number of characters written.
+ */
+ long copy(byte* buf, ByteOrder byteOrder, long offset =0);
+ /*!
+ @brief Reset the IFD. Delete all IFD entries from the class and put
+ the object in a state where it can accept completely new
+ entries.
+ */
+ void clear();
+ /*!
+ @brief Set the offset of the next IFD. Byte order is needed to update
+ the underlying data buffer in non-alloc mode. This method only
+ has an effect if the IFD was instantiated with hasNext = true.
+ */
+ void setNext(uint32_t next, ByteOrder byteOrder);
+ /*!
+ @brief Add the entry to the IFD. No duplicate-check is performed,
+ i.e., it is possible to add multiple entries with the same
tag.
+ The memory allocation mode of the entry to be added must match
+ that of the IFD and the IFD ids of the IFD and entry must
+ match.
+ */
+ void add(const Entry& entry);
+ /*!
+ @brief Delete the directory entry with the given tag. Return the
index
+ of the deleted entry or 0 if no entry with tag was found.
+ */
+ int erase(uint16_t tag);
+ /*!
+ @brief Delete the directory entry at iterator position pos, return
the
+ position of the next entry. Note that iterators into the
+ directory, including pos, are potentially invalidated by this
+ call.
+ */
+ iterator erase(iterator pos);
+ //! Sort the IFD entries by tag
+ void sortByTag();
+ //! The first entry
+ iterator begin() { return entries_.begin(); }
+ //! End of the entries
+ iterator end() { return entries_.end(); }
+ //! Find an IFD entry by idx, return an iterator into the entries list
+ iterator findIdx(int idx);
+ //! Find an IFD entry by tag, return an iterator into the entries list
+ iterator findTag(uint16_t tag);
+ /*!
+ @brief Update the base pointer of the Ifd and all entries to \em
pNewBase.
+
+ Allows to re-locate the underlying data buffer to a new location
+ \em pNewBase. This method only has an effect in non-alloc mode.
+
+ @param pNewBase Pointer to the new data buffer
+
+ @return Old base pointer or 0 if called in alloc mode
+ */
+ byte* updateBase(byte* pNewBase);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Read a sub-IFD from the location pointed to by the directory
entry
+ with the given tag.
+
+ @param dest References the destination IFD.
+ @param buf The data buffer to read from. The buffer must contain all
Exif
+ data starting from the TIFF header (unlike the read()
method).
+ @param len Number of bytes in the data buffer
+ @param byteOrder Applicable byte order (little or big endian).
+ @param tag Tag to look for.
+
+ @return 0 if successful;<BR>
+ 6 if reading the sub-IFD failed (see read() above) or
+ the location pointed to by the directory entry with the
+ given tag is outside of the data buffer.
+
+ @note It is not considered an error if the tag cannot be found in
the
+ IFD. 0 is returned and no action is taken in this case.
+ */
+ int readSubIfd(
+ Ifd& dest, const byte* buf, long len, ByteOrder byteOrder,
uint16_t tag
+ ) const;
+ //! Get the memory allocation mode, see the Ifd class description for
details
+ bool alloc() const { return alloc_; }
+ //! The first entry
+ const_iterator begin() const { return entries_.begin(); }
+ //! End of the entries
+ const_iterator end() const { return entries_.end(); }
+ //! Find an IFD entry by idx, return a const iterator into the entries
list
+ const_iterator findIdx(int idx) const;
+ //! Find an IFD entry by tag, return a const iterator into the entries
list
+ const_iterator findTag(uint16_t tag) const;
+ //! Get the IfdId of the IFD
+ IfdId ifdId() const { return ifdId_; }
+ //! Get the offset of the IFD from the start of the TIFF header
+ long offset() const { return offset_; }
+ /*!
+ @brief Get the offset of the first data entry outside of the IFD from
+ the start of the TIFF header, return 0 if there is none. The
+ data offset is determined when the IFD is read.
+ */
+ long dataOffset() const { return dataOffset_; }
+ //! Get the offset to the next IFD from the start of the TIFF header
+ uint32_t next() const { return next_; }
+ //! Get the number of directory entries in the IFD
+ long count() const { return static_cast<long>(entries_.size()); }
+ //! Get the size of this IFD in bytes (IFD only, without data)
+ long size() const;
+ /*!
+ @brief Return the total size of the data of this IFD in bytes; sums
+ the size of all directory entries where size is greater than
+ four plus the size of all data areas, i.e., all data that
+ requires memory outside the IFD directory entries is counted.
+ */
+ long dataSize() const;
+ /*!
+ @brief Print the IFD in human readable format to the given stream;
+ begin each line with prefix.
+ */
+ void print(std::ostream& os, const std::string& prefix ="") const;
+ //@}
+
+ private:
+ //! Helper structure to build IFD entries
+ struct PreEntry {
+ uint16_t tag_;
+ uint16_t type_;
+ uint32_t count_;
+ long size_;
+ long offsetLoc_;
+ long offset_;
+ };
+
+ //! cmpPreEntriesByOffset needs to know about PreEntry, that's all.
+ friend bool cmpPreEntriesByOffset(const PreEntry&, const PreEntry&);
+
+ //! Container for 'pre-entries'
+ typedef std::vector<PreEntry> PreEntries;
+
+ // DATA
+ /*!
+ True: requires memory allocation and deallocation,
+ False: no memory management needed.
+ */
+ const bool alloc_;
+ //! IFD entries
+ Entries entries_;
+ //! IFD Id
+ IfdId ifdId_;
+ //! Pointer to IFD from the start of the TIFF header
+ byte* pBase_;
+ //! Offset of the IFD from the start of the TIFF header
+ long offset_;
+ //! Offset of the first data entry outside of the IFD directory
+ long dataOffset_;
+ //! Indicates whether the IFD has a next pointer
+ bool hasNext_;
+ //! Pointer to the offset of next IFD from the start of the TIFF header
+ byte* pNext_;
+ //! The offset of the next IFD as data value (always in sync with
*pNext_)
+ uint32_t next_;
+
+ }; // class Ifd
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Compare two IFD entries by tag. Return true if the tag of entry
+ lhs is less than that of rhs.
+ */
+ bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs);
+
+ /*!
+ @brief Compare two 'pre-IFD entries' by offset, taking care of special
+ cases where one or both of the entries don't have an offset.
+ Return true if the offset of entry lhs is less than that of rhs,
+ else false. By definition, entries without an offset are greater
+ than those with an offset.
+ */
+ bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry&
rhs);
+
+} // namespace Exiv2
+
+#endif // #ifndef IFD_HPP_
Added: Extractor/src/plugins/exiv2/image.cpp
===================================================================
--- Extractor/src/plugins/exiv2/image.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/image.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,223 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: image.cpp
+ Version: $Rev: 563 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ Brad Schick (brad) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ 19-Jul-04, brad: revamped to be more flexible and support Iptc
+ 15-Jan-05, brad: inside-out design changes
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: image.cpp 563 2005-04-21 07:21:53Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "image.hpp"
+#include "error.hpp"
+#include "futils.hpp"
+
+// Ensure registration with factory
+#include "jpgimage.hpp"
+
+// + standard includes
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <cstdio> // for rename, remove
+#include <cassert>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _MSC_VER
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // stat
+#endif
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ ImageFactory::Registry* ImageFactory::registry_ = 0;
+
+ void ImageFactory::init()
+ {
+ if (0 == registry_) {
+ registry_ = new Registry;
+ }
+ }
+
+ void ImageFactory::registerImage(Image::Type type,
+ NewInstanceFct newInst, IsThisTypeFct isType)
+ {
+ init();
+ assert (newInst && isType);
+ (*registry_)[type] = ImageFcts(newInst, isType);
+ }
+
+ Image::Type ImageFactory::getType(const std::string& path)
+ {
+ FileIo fileIo(path);
+ return getType(fileIo);
+ }
+
+ Image::Type ImageFactory::getType(const byte* data, long size)
+ {
+ MemIo memIo(data, size);
+ return getType(memIo);
+ }
+
+ Image::Type ImageFactory::getType(BasicIo& io)
+ {
+ if (io.open() != 0) return Image::none;
+ IoCloser closer(io);
+ Image::Type type = Image::none;
+ Registry::const_iterator b = registry_->begin();
+ Registry::const_iterator e = registry_->end();
+ for (Registry::const_iterator i = b; i != e; ++i)
+ {
+ if (i->second.isThisType(io, false)) {
+ type = i->first;
+ break;
+ }
+ }
+ return type;
+ } // ImageFactory::getType
+
+ Image::AutoPtr ImageFactory::open(const std::string& path)
+ {
+ BasicIo::AutoPtr io(new FileIo(path));
+ Image::AutoPtr image = open(io); // may throw
+ if (image.get() == 0) throw Error(11, path);
+ return image;
+ }
+
+ Image::AutoPtr ImageFactory::open(const byte* data, long size)
+ {
+ BasicIo::AutoPtr io(new MemIo(data, size));
+ Image::AutoPtr image = open(io); // may throw
+ if (image.get() == 0) throw Error(12);
+ return image;
+ }
+
+ Image::AutoPtr ImageFactory::open(BasicIo::AutoPtr io)
+ {
+ if (io->open() != 0) {
+ throw Error(9, io->path(), strError());
+ }
+ Image::AutoPtr image;
+ Registry::const_iterator b = registry_->begin();
+ Registry::const_iterator e = registry_->end();
+ for (Registry::const_iterator i = b; i != e; ++i) {
+ if (i->second.isThisType(*io, false)) {
+ image = i->second.newInstance(io, false);
+ break;
+ }
+ }
+ return image;
+ } // ImageFactory::open
+
+ Image::AutoPtr ImageFactory::create(Image::Type type,
+ const std::string& path)
+ {
+ std::auto_ptr<FileIo> fileIo(new FileIo(path));
+ // Create or overwrite the file, then close it
+ if (fileIo->open("w+b") != 0) {
+ throw Error(10, path, "w+b", strError());
+ }
+ fileIo->close();
+ BasicIo::AutoPtr io(fileIo);
+ Image::AutoPtr image = create(type, io);
+ if (image.get() == 0) throw Error(13, type);
+ return image;
+ }
+
+ Image::AutoPtr ImageFactory::create(Image::Type type)
+ {
+ BasicIo::AutoPtr io(new MemIo);
+ Image::AutoPtr image = create(type, io);
+ if (image.get() == 0) throw Error(13, type);
+ return image;
+ }
+
+ Image::AutoPtr ImageFactory::create(Image::Type type,
+ BasicIo::AutoPtr io)
+ {
+ // BasicIo instance does not need to be open
+ Registry::const_iterator i = registry_->find(type);
+ if (i != registry_->end()) {
+ return i->second.newInstance(io, true);
+ }
+ return Image::AutoPtr();
+ } // ImageFactory::create
+
+ TiffHeader::TiffHeader(ByteOrder byteOrder)
+ : byteOrder_(byteOrder), tag_(0x002a), offset_(0x00000008)
+ {
+ }
+
+ int TiffHeader::read(const byte* buf)
+ {
+ if (buf[0] == 0x49 && buf[1] == 0x49) {
+ byteOrder_ = littleEndian;
+ }
+ else if (buf[0] == 0x4d && buf[1] == 0x4d) {
+ byteOrder_ = bigEndian;
+ }
+ else {
+ return 1;
+ }
+ tag_ = getUShort(buf+2, byteOrder_);
+ offset_ = getULong(buf+4, byteOrder_);
+ return 0;
+ }
+
+ long TiffHeader::copy(byte* buf) const
+ {
+ switch (byteOrder_) {
+ case littleEndian:
+ buf[0] = 0x49;
+ buf[1] = 0x49;
+ break;
+ case bigEndian:
+ buf[0] = 0x4d;
+ buf[1] = 0x4d;
+ break;
+ case invalidByteOrder:
+ // do nothing
+ break;
+ }
+ us2Data(buf+2, 0x002a, byteOrder_);
+ ul2Data(buf+4, 0x00000008, byteOrder_);
+ return size();
+ } // TiffHeader::copy
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/image.hpp
===================================================================
--- Extractor/src/plugins/exiv2/image.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/image.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,461 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file image.hpp
+ @brief Class JpegImage to access JPEG images
+ @version $Rev: 563 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @author Brad Schick (brad)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created<BR>
+ 11-Feb-04, ahu: isolated as a component<BR>
+ 19-Jul-04, brad: revamped to be more flexible and support Iptc
+ 15-Jan-05, brad: inside-out design changes
+ */
+#ifndef IMAGE_HPP_
+#define IMAGE_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "basicio.hpp"
+
+// + standard includes
+#include <string>
+#include <map>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class ExifData;
+ class IptcData;
+
+//
*****************************************************************************
+// class definitions
+ /*!
+ @brief Abstract base class defining the interface for an image. This is
+ the top-level interface to the Exiv2 library.
+
+ Most client apps will obtain an Image instance by calling a static
+ ImageFactory method. The Image class can then be used to to
+ read, write, and save metadata.
+ */
+ class Image {
+ public:
+ //! Supported image formats
+ enum Type { none, jpeg, exv };
+
+ //! Image auto_ptr type
+ typedef std::auto_ptr<Image> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Virtual Destructor
+ virtual ~Image() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read metadata from assigned image. Before this method
+ is called, the various metadata types (Iptc, Exif) will be empty.
+ @throw Error In case of failure.
+ */
+ virtual void readMetadata() =0;
+ /*!
+ @brief Write metadata back to the image.
+
+ All existing metadata sections in the image are either created,
+ replaced, or erased. If values for a given metadata type have been
+ assigned, a section for that metadata type will either be created or
+ replaced. If no values have been assigned to a given metadata type,
+ any exists section for that metadata type will be removed from the
+ image.
+
+ @throw Error if the operation fails
+ */
+ virtual void writeMetadata() =0;
+ /*!
+ @brief Assign new exif data. The new exif data is not written
+ to the image until the writeMetadata() method is called.
+ @param exifData An ExifData instance holding exif data to be copied
+ */
+ virtual void setExifData(const ExifData& exifData) =0;
+ /*!
+ @brief Erase any buffered Exif data. Exif data is not removed from
+ the actual image until the writeMetadata() method is called.
+ */
+ virtual void clearExifData() =0;
+ /*!
+ @brief Assign new iptc data. The new iptc data is not written
+ to the image until the writeMetadata() method is called.
+ @param iptcData An IptcData instance holding iptc data to be copied
+ */
+ virtual void setIptcData(const IptcData& iptcData) =0;
+ /*!
+ @brief Erase any buffered Iptc data. Iptc data is not removed from
+ the actual image until the writeMetadata() method is called.
+ */
+ virtual void clearIptcData() =0;
+ /*!
+ @brief Set the image comment. The new comment is not written
+ to the image until the writeMetadata() method is called.
+ @param comment String containing comment.
+ */
+ virtual void setComment(const std::string& comment) =0;
+ /*!
+ @brief Erase any buffered comment. Comment is not removed
+ from the actual image until the writeMetadata() method is called.
+ */
+ virtual void clearComment() =0;
+ /*!
+ @brief Copy all existing metadata from source Image. The data is
+ copied into internal buffers and is not written to the image
+ until the writeMetadata() method is called.
+ @param image Metadata source. All metadata types are copied.
+ */
+ virtual void setMetadata(const Image& image) =0;
+ /*!
+ @brief Erase all buffered metadata. Metadata is not removed
+ from the actual image until the writeMetadata() method is called.
+ */
+ virtual void clearMetadata() =0;
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Check if the Image instance is valid. Use after object
+ construction.
+ @return true if the Image is in a valid state.
+ */
+ virtual bool good() const =0;
+ /*!
+ @brief Returns an ExifData instance containing currently buffered
+ exif data.
+
+ The exif data may have been read from the image by
+ a previous call to readMetadata() or added directly. The exif
+ data in the returned instance will be written to the image when
+ writeMetadata() is called.
+
+ @return read only ExifData instance containing exif values
+ */
+ virtual const ExifData& exifData() const =0;
+ /*!
+ @brief Returns an ExifData instance containing currently buffered
+ exif data.
+
+ The contained exif data may have been read from the image by
+ a previous call to readMetadata() or added directly. The exif
+ data in the returned instance will be written to the image when
+ writeMetadata() is called.
+
+ @return modifiable ExifData instance containing exif values
+ */
+ virtual ExifData& exifData() =0;
+ /*!
+ @brief Returns an IptcData instance containing currently buffered
+ iptc data.
+
+ The contained iptc data may have been read from the image by
+ a previous call to readMetadata() or added directly. The iptc
+ data in the returned instance will be written to the image when
+ writeMetadata() is called.
+
+ @return modifiable IptcData instance containing iptc values
+ */
+ virtual const IptcData& iptcData() const =0;
+ /*!
+ @brief Returns an ExifData instance containing currently buffered
+ exif data.
+
+ The contained iptc data may have been read from the image by
+ a previous call to readMetadata() or added directly. The iptc
+ data in the returned instance will be written to the image when
+ writeMetadata() is called.
+
+ @return modifiable IptcData instance containing iptc values
+ */
+ virtual IptcData& iptcData() =0;
+ /*!
+ @brief Return a copy of the image comment. May be an empty string.
+ */
+ virtual std::string comment() const =0;
+ /*!
+ @brief Return a reference to the BasicIo instance being used for Io.
+
+ This refence is particularly useful to reading the results of
+ operations on a MemIo instance. For example after metadata has
+ been modified and the writeMetadata() method has been called,
+ this method can be used to get access to the modified image.
+
+ @return BasicIo instance that can be used to read or write image
+ data directly.
+ @note If the returned BasicIo is used to write to the image, the
+ Image class will not see those changes until the readMetadata()
+ method is called.
+ */
+ virtual BasicIo& io() const = 0;
+ //@}
+
+ protected:
+ //! @name Creators
+ //@{
+ //! Default Constructor
+ Image() {}
+ //@}
+
+ private:
+ // NOT Implemented
+ //! Copy constructor
+ Image(const Image& rhs);
+ //! Assignment operator
+ Image& operator=(const Image& rhs);
+
+ }; // class Image
+
+ //! Type for function pointer that creates new Image instances
+ typedef Image::AutoPtr (*NewInstanceFct)(BasicIo::AutoPtr io, bool create);
+ //! Type for function pointer that checks image types
+ typedef bool (*IsThisTypeFct)(BasicIo& iIo, bool advance);
+
+ /*!
+ @brief Returns an Image instance of the specified type.
+
+ The factory is implemented as a singleton, which can be accessed
+ through static member functions.
+ */
+ class ImageFactory {
+ public:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Register image type together with its function pointers.
+
+ The image factory creates new images by calling their associated
+ function pointer. Additional images can be added by registering
+ new type and function pointers. If called for a type that already
+ exists in the list, the corresponding functions are replaced.
+
+ @param type Image type.
+ @param newInst Function pointer for creating image instances.
+ @param isType Function pointer to test for matching image types.
+ */
+ static void registerImage(Image::Type type,
+ NewInstanceFct newInst,
+ IsThisTypeFct isType);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Create an Image subclass of the appropriate type by reading
+ the specified file. %Image type is derived from the file
+ contents.
+ @param path %Image file. The contents of the file are tested to
+ determine the image type. File extension is ignored.
+ @return An auto-pointer that owns an Image instance whose type
+ matches that of the file.
+ @throw Error If opening the file fails or it contains data of an
+ unknown image type.
+ */
+ static Image::AutoPtr open(const std::string& path);
+ /*!
+ @brief Create an Image subclass of the appropriate type by reading
+ the provided memory. %Image type is derived from the memory
+ contents.
+ @param data Pointer to a data buffer containing an image. The
contents
+ of the memory are tested to determine the image type.
+ @param size Number of bytes pointed to by \em data.
+ @return An auto-pointer that owns an Image instance whose type
+ matches that of the data buffer.
+ @throw Error If the memory contains data of an unknown image type.
+ */
+ static Image::AutoPtr open(const byte* data, long size);
+ /*!
+ @brief Create an Image subclass of the appropriate type by reading
+ the provided BasicIo instance. %Image type is derived from the
+ data provided by \em io. The passed in \em io instance is
+ (re)opened by this method.
+ @param io An auto-pointer that owns a BasicIo instance that provides
+ image data. The contents of the image data are tested to
determine
+ the type.
+ @note This method takes ownership of the passed
+ in BasicIo instance through the auto-pointer. Callers should not
+ continue to use the BasicIo instance after it is passed to this
method.
+ Use the Image::io() method to get a temporary reference.
+ @return An auto-pointer that owns an Image instance whose type
+ matches that of the \em io data. If no image type could be
+ determined, the pointer is 0.
+ @throw Error If opening the BasicIo fails
+ */
+ static Image::AutoPtr open(BasicIo::AutoPtr io);
+ /*!
+ @brief Create an Image subclass of the requested type by creating a
+ new image file. If the file already exists, it will be
overwritten.
+ @param type Type of the image to be created.
+ @param path %Image file to create. File extension is ignored.
+ @return An auto-pointer that owns an Image instance of the requested
+ type.
+ @throw Error If the image type is not supported.
+ */
+ static Image::AutoPtr create(Image::Type type, const std::string&
path);
+ /*!
+ @brief Create an Image subclass of the requested type by creating a
+ new image in memory.
+ @param type Type of the image to be created.
+ @return An auto-pointer that owns an Image instance of the requested
+ type.
+ @throw Error If the image type is not supported
+ */
+ static Image::AutoPtr create(Image::Type type);
+ /*!
+ @brief Create an Image subclass of the requested type by writing a
+ new image to a BasicIo instance. If the BasicIo instance already
+ contains data, it will be overwritten.
+ @param type Type of the image to be created.
+ @param io An auto-pointer that owns a BasicIo instance that will
+ be written to when creating a new image.
+ @note This method takes ownership of the passed in BasicIo instance
+ through the auto-pointer. Callers should not continue to use the
+ BasicIo instance after it is passed to this method. Use the
+ Image::io() method to get a temporary reference.
+ @return An auto-pointer that owns an Image instance of the requested
+ type. If the image type is not supported, the pointer is 0.
+ */
+ static Image::AutoPtr create(Image::Type type, BasicIo::AutoPtr io);
+ /*!
+ @brief Returns the image type of the provided file.
+ @param path %Image file. The contents of the file are tested to
+ determine the image type. File extension is ignored.
+ @return %Image type or Image::none if the type is not recognized.
+ */
+ static Image::Type getType(const std::string& path);
+ /*!
+ @brief Returns the image type of the provided data buffer.
+ @param data Pointer to a data buffer containing an image. The
contents
+ of the memory are tested to determine the image type.
+ @param size Number of bytes pointed to by \em data.
+ @return %Image type or Image::none if the type is not recognized.
+ */
+ static Image::Type getType(const byte* data, long size);
+ /*!
+ @brief Returns the image type of data provided by a BasicIo instance.
+ The passed in \em io instance is (re)opened by this method.
+ @param io A BasicIo instance that provides image data. The contents
+ of the image data are tested to determine the type.
+ @return %Image type or Image::none if the type is not recognized.
+ */
+ static Image::Type getType(BasicIo& io);
+ //@}
+
+
+ private:
+ //! @name Creators
+ //@{
+ //! Prevent construction other than through instance().
+ ImageFactory();
+ //! Prevent copy construction: not implemented.
+ ImageFactory(const ImageFactory& rhs);
+ //! Creates the private static instance
+ static void init();
+ //@}
+
+ //! Struct for storing image function pointers.
+ struct ImageFcts
+ {
+ NewInstanceFct newInstance;
+ IsThisTypeFct isThisType;
+ ImageFcts(NewInstanceFct newInst, IsThisTypeFct isType)
+ : newInstance(newInst), isThisType(isType) {}
+ ImageFcts() : newInstance(0), isThisType(0) {}
+ };
+
+ // DATA
+ //! Type used to store Image creation functions
+ typedef std::map<Image::Type, ImageFcts> Registry;
+ //! List of image types and corresponding creation functions.
+ static Registry* registry_;
+ }; // class ImageFactory
+
+
+ //! Helper class modelling the TIFF header structure.
+ class TiffHeader {
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Default constructor. Optionally sets the byte order
+ (default: little endian).
+ */
+ explicit TiffHeader(ByteOrder byteOrder =littleEndian);
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Read the TIFF header from a data buffer. Returns 0 if successful.
+ int read(const byte* buf);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Write a standard TIFF header into buf as a data string, return
+ number of bytes copied.
+
+ Only the byte order of the TIFF header varies, the values written for
+ offset and tag are constant, i.e., independent of the values possibly
+ read before a call to this function. The value 0x00000008 is written
+ for the offset, tag is set to 0x002a.
+
+ @param buf The data buffer to write to.
+ @return The number of bytes written.
+ */
+ long copy(byte* buf) const;
+ //! Return the size of the TIFF header in bytes.
+ long size() const { return 8; }
+ //! Return the byte order (little or big endian).
+ ByteOrder byteOrder() const { return byteOrder_; }
+ //! Return the tag value.
+ uint16_t tag() const { return tag_; }
+ /*!
+ @brief Return the offset to IFD0 from the start of the TIFF header.
+ The offset is 0x00000008 if IFD0 begins immediately after the
+ TIFF header.
+ */
+ uint32_t offset() const { return offset_; }
+ //@}
+
+ private:
+ ByteOrder byteOrder_;
+ uint16_t tag_;
+ uint32_t offset_;
+
+ }; // class TiffHeader
+
+} // namespace Exiv2
+
+#endif // #ifndef IMAGE_HPP_
Added: Extractor/src/plugins/exiv2/iptc.cpp
===================================================================
--- Extractor/src/plugins/exiv2/iptc.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/iptc.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,298 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: iptc.cpp
+ Version: $Rev: 560 $
+ Author(s): Brad Schick (brad) <address@hidden>
+ History: 31-July-04, brad: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: iptc.cpp 560 2005-04-17 11:51:32Z ahuggel $");
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// included header files
+#include "iptc.hpp"
+#include "types.hpp"
+#include "error.hpp"
+#include "value.hpp"
+#include "datasets.hpp"
+#include "jpgimage.hpp"
+
+// + standard includes
+#include <iostream>
+#include <algorithm>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Iptcdatum::Iptcdatum(const IptcKey& key,
+ const Value* pValue)
+ : key_(key.clone())
+ {
+ if (pValue) value_ = pValue->clone();
+ }
+
+ Iptcdatum::Iptcdatum(const Iptcdatum& rhs)
+ : Metadatum(rhs)
+ {
+ if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
+ if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
+ }
+
+ Iptcdatum::~Iptcdatum()
+ {
+ }
+
+ Iptcdatum& Iptcdatum::operator=(const Iptcdatum& rhs)
+ {
+ if (this == &rhs) return *this;
+ Metadatum::operator=(rhs);
+
+ key_.reset();
+ if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
+
+ value_.reset();
+ if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
+
+ return *this;
+ } // Iptcdatum::operator=
+
+ Iptcdatum& Iptcdatum::operator=(const uint16_t& value)
+ {
+ UShortValue::AutoPtr v = UShortValue::AutoPtr(new UShortValue);
+ v->value_.push_back(value);
+ value_ = v;
+ return *this;
+ }
+
+ Iptcdatum& Iptcdatum::operator=(const std::string& value)
+ {
+ setValue(value);
+ return *this;
+ }
+
+ Iptcdatum& Iptcdatum::operator=(const Value& value)
+ {
+ setValue(&value);
+ return *this;
+ }
+
+ void Iptcdatum::setValue(const Value* pValue)
+ {
+ value_.reset();
+ if (pValue) value_ = pValue->clone();
+ }
+
+ void Iptcdatum::setValue(const std::string& value)
+ {
+ if (value_.get() == 0) {
+ TypeId type = IptcDataSets::dataSetType(tag(), record());
+ value_ = Value::create(type);
+ }
+ value_->read(value);
+ }
+
+ const byte IptcData::marker_ = 0x1C; // Dataset marker
+
+ Iptcdatum& IptcData::operator[](const std::string& key)
+ {
+ IptcKey iptcKey(key);
+ iterator pos = findKey(iptcKey);
+ if (pos == end()) {
+ add(Iptcdatum(iptcKey));
+ pos = findKey(iptcKey);
+ }
+ return *pos;
+ }
+
+ int IptcData::load(const byte* buf, long len)
+ {
+ const byte* pRead = buf;
+ iptcMetadata_.clear();
+
+ int rc = 0;
+ uint16_t record = 0;
+ uint16_t dataSet = 0;
+ uint32_t sizeData = 0;
+ byte extTest = 0;
+
+ while (pRead + 3 < buf + len) {
+ if (*pRead++ != marker_) return 5;
+ record = *pRead++;
+ dataSet = *pRead++;
+
+ extTest = *pRead;
+ if (extTest & 0x80) {
+ // extended dataset
+ uint16_t sizeOfSize = (getUShort(pRead, bigEndian) & 0x7FFF);
+ if (sizeOfSize > 4) return 5;
+ pRead += 2;
+ sizeData = 0;
+ for (; sizeOfSize > 0; --sizeOfSize) {
+ sizeData |= *pRead++ << (8 *(sizeOfSize-1));
+ }
+ }
+ else {
+ // standard dataset
+ sizeData = getUShort(pRead, bigEndian);
+ pRead += 2;
+ }
+ rc = readData(dataSet, record, pRead, sizeData);
+ if( rc ) return rc;
+ pRead += sizeData;
+ }
+
+ return rc;
+ } // IptcData::read
+
+ int IptcData::readData(uint16_t dataSet, uint16_t record,
+ const byte* data, uint32_t sizeData)
+ {
+ Value::AutoPtr value;
+ TypeId type = IptcDataSets::dataSetType(dataSet, record);
+ value = Value::create(type);
+ value->read(data, sizeData, bigEndian);
+ IptcKey key(dataSet, record);
+ add(key, value.get());
+ return 0;
+ }
+
+ DataBuf IptcData::copy()
+ {
+ DataBuf buf(size());
+ byte *pWrite = buf.pData_;
+
+ const_iterator iter = iptcMetadata_.begin();
+ const_iterator end = iptcMetadata_.end();
+ for ( ; iter != end; ++iter) {
+ // marker, record Id, dataset num
+ *pWrite++ = marker_;
+ *pWrite++ = static_cast<byte>(iter->record());
+ *pWrite++ = static_cast<byte>(iter->tag());
+
+ // extended or standard dataset?
+ long dataSize = iter->size();
+ if (dataSize > 32767) {
+ // always use 4 bytes for extended length
+ uint16_t sizeOfSize = 4 | 0x8000;
+ us2Data(pWrite, sizeOfSize, bigEndian);
+ pWrite += 2;
+ ul2Data(pWrite, dataSize, bigEndian);
+ pWrite += 4;
+ }
+ else {
+ us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian);
+ pWrite += 2;
+ }
+
+ pWrite += iter->value().copy(pWrite, bigEndian);
+ }
+
+ return buf;
+ } // IptcData::updateBuffer
+
+ long IptcData::size() const
+ {
+ long newSize = 0;
+ const_iterator iter = iptcMetadata_.begin();
+ const_iterator end = iptcMetadata_.end();
+ for ( ; iter != end; ++iter) {
+ // marker, record Id, dataset num, first 2 bytes of size
+ newSize += 5;
+ long dataSize = iter->size();
+ newSize += dataSize;
+ if (dataSize > 32767) {
+ // extended dataset (we always use 4 bytes)
+ newSize += 4;
+ }
+ }
+ return newSize;
+ } // IptcData::size
+
+ int IptcData::add(const IptcKey& key, Value* value)
+ {
+ return add(Iptcdatum(key, value));
+ }
+
+ int IptcData::add(const Iptcdatum& iptcDatum)
+ {
+ if (!IptcDataSets::dataSetRepeatable(
+ iptcDatum.tag(), iptcDatum.record()) &&
+ findId(iptcDatum.tag(), iptcDatum.record()) != end()) {
+ return 6;
+ }
+ // allow duplicates
+ iptcMetadata_.push_back(iptcDatum);
+ return 0;
+ }
+
+ IptcData::const_iterator IptcData::findKey(const IptcKey& key) const
+ {
+ return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
+ FindMetadatumById(key.tag(), key.record()));
+ }
+
+ IptcData::iterator IptcData::findKey(const IptcKey& key)
+ {
+ return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
+ FindMetadatumById(key.tag(), key.record()));
+ }
+
+ IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t
record) const
+ {
+ return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
+ FindMetadatumById(dataset, record));
+ }
+
+ IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record)
+ {
+ return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
+ FindMetadatumById(dataset, record));
+ }
+
+ void IptcData::sortByKey()
+ {
+ std::sort(iptcMetadata_.begin(), iptcMetadata_.end(),
cmpMetadataByKey);
+ }
+
+ void IptcData::sortByTag()
+ {
+ std::sort(iptcMetadata_.begin(), iptcMetadata_.end(),
cmpMetadataByTag);
+ }
+
+ IptcData::iterator IptcData::erase(IptcData::iterator pos)
+ {
+ return iptcMetadata_.erase(pos);
+ }
+
+ //
*************************************************************************
+ // free functions
+ std::ostream& operator<<(std::ostream& os, const Iptcdatum& md)
+ {
+ return os << md.value();
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/iptc.hpp
===================================================================
--- Extractor/src/plugins/exiv2/iptc.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/iptc.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,416 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file iptc.hpp
+ @brief Encoding and decoding of Iptc data
+ @version $Rev: 560 $
+ @author Brad Schick (brad)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 31-Jul-04, brad: created
+ */
+#ifndef IPTC_HPP_
+#define IPTC_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "metadatum.hpp"
+#include "types.hpp"
+#include "error.hpp"
+#include "value.hpp"
+#include "datasets.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Information related to one Iptc dataset. An Iptc metadatum
consists
+ of an IptcKey and a Value and provides methods to manipulate
these.
+ */
+ class Iptcdatum : public Metadatum {
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @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().
+
+ @param key The key of the %Iptcdatum.
+ @param pValue Pointer to a %Iptcdatum value.
+ @throw Error if the key cannot be parsed and converted
+ to a tag number and record id.
+ */
+ explicit Iptcdatum(const IptcKey& key,
+ const Value* pValue =0);
+ //! Copy constructor
+ Iptcdatum(const Iptcdatum& rhs);
+ //! Destructor
+ virtual ~Iptcdatum();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator
+ Iptcdatum& operator=(const Iptcdatum& rhs);
+ /*!
+ @brief Assign \em value to the %Iptcdatum. The type of the new Value
+ is set to UShortValue.
+ */
+ Iptcdatum& operator=(const uint16_t& value);
+ /*!
+ @brief Assign \em value to the %Iptcdatum.
+ Calls setValue(const std::string&).
+ */
+ Iptcdatum& operator=(const std::string& value);
+ /*!
+ @brief Assign \em value to the %Iptcdatum.
+ Calls setValue(const Value*).
+ */
+ Iptcdatum& operator=(const Value& value);
+ /*!
+ @brief Set the Value. This method copies (clones) the %Value pointed
+ to by \em pValue.
+ */
+ void setValue(const Value* pValue);
+ /*!
+ @brief Set the value to the string \em value, using
+ Value::read(const std::string&).
+ If the %Iptcdatum does not have a Value yet, then a %Value of
+ the correct type for this %Iptcdatum is created. If that
+ fails (because of an unknown dataset), a StringValue is
+ created.
+ */
+ void setValue(const std::string& value);
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Write value to a data buffer and return the number
+ of bytes written.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return Number of characters written.
+ */
+ long copy(byte* buf, ByteOrder byteOrder) const
+ { return value_.get() == 0 ? 0 : value_->copy(buf, byteOrder); }
+ /*!
+ @brief Return the key of the Iptcdatum. The key is of the form
+ '<b>Iptc</b>.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_.get() == 0 ? "" : key_->key(); }
+ /*!
+ @brief Return the name of the record
+ @return record name
+ */
+ std::string recordName() const
+ { return key_.get() == 0 ? "" : key_->recordName(); }
+ /*!
+ @brief Return the record id
+ @return record id
+ */
+ uint16_t record() const
+ { return key_.get() == 0 ? 0 : key_->record(); }
+ /*!
+ @brief Return the name of the tag (aka dataset)
+ @return tag name
+ */
+ std::string tagName() const
+ { return key_.get() == 0 ? "" : key_->tagName(); }
+ //! Return the tag (aka dataset) number
+ uint16_t tag() const
+ { return key_.get() == 0 ? 0 : key_->tag(); }
+ //! Return the type id of the value
+ TypeId typeId() const
+ { return value_.get() == 0 ? invalidTypeId : value_->typeId(); }
+ //! Return the name of the type
+ 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()); }
+ //! Return the number of components in the value
+ long count() const { return value_.get() == 0 ? 0 : value_->count(); }
+ //! Return the size of the value in bytes
+ long size() const { return value_.get() == 0 ? 0 : value_->size(); }
+ //! Return the value as a string.
+ std::string toString() const
+ { return value_.get() == 0 ? "" : value_->toString(); }
+ /*!
+ @brief Return the n-th component of the value converted to long. The
+ return value is -1 if the value of the Iptcdatum is not set
and
+ the behaviour of the method is undefined if there is no n-th
+ component.
+ */
+ long toLong(long n =0) const
+ { return value_.get() == 0 ? -1 : value_->toLong(n); }
+ /*!
+ @brief Return the n-th component of the value converted to float.
The
+ return value is -1 if the value of the Iptcdatum is not set
and
+ the behaviour of the method is undefined if there is no n-th
+ component.
+ */
+ float toFloat(long n =0) const
+ { return value_.get() == 0 ? -1 : value_->toFloat(n); }
+ /*!
+ @brief Return the n-th component of the value converted to
+ Rational. The return value is -1/1 if the value of the
+ Iptcdatum is not set and the behaviour of the method is
+ undefined if there is no n-th component.
+ */
+ Rational toRational(long n =0) const
+ { return value_.get() == 0 ? Rational(-1, 1) :
value_->toRational(n); }
+ /*!
+ @brief Return an auto-pointer to a copy (clone) of the value. The
+ caller owns this copy and the auto-pointer ensures that it
will
+ be deleted.
+
+ This method is provided for users who need full control over the
+ value. A caller may, e.g., downcast the pointer to the appropriate
+ subclass of Value to make use of the interface of the subclass to set
+ or modify its contents.
+
+ @return An auto-pointer to a copy (clone) of the value, 0 if the
value
+ is not set.
+ */
+ Value::AutoPtr getValue() const
+ { return value_.get() == 0 ? Value::AutoPtr(0) : value_->clone(); }
+ /*!
+ @brief Return a constant reference to the value.
+
+ This method is provided mostly for convenient and versatile output of
+ the value which can (to some extent) be formatted through standard
+ stream manipulators. Do not attempt to write to the value through
+ this reference.
+
+ <b>Example:</b> <br>
+ @code
+ IptcData::const_iterator i = iptcData.findKey(key);
+ if (i != iptcData.end()) {
+ std::cout << i->key() << " " << std::hex << i->value() << "\n";
+ }
+ @endcode
+
+ @return A constant reference to the value.
+ @throw Error If the value is not set.
+ */
+ const Value& value() const
+ { if (value_.get() != 0) return *value_; throw Error(8); }
+ //@}
+
+ private:
+ // DATA
+ IptcKey::AutoPtr key_; //!< Key
+ Value::AutoPtr value_; //!< Value
+
+ }; // class Iptcdatum
+
+ /*!
+ @brief Output operator for Iptcdatum types, printing the interpreted
+ tag value.
+ */
+ std::ostream& operator<<(std::ostream& os, const Iptcdatum& md);
+
+ //! Container type to hold all metadata
+ typedef std::vector<Iptcdatum> IptcMetadata;
+
+ //! Unary predicate that matches an Iptcdatum with given record and dataset
+ class FindMetadatumById {
+ public:
+ //! Constructor, initializes the object with the record and dataset id
+ FindMetadatumById(uint16_t dataset, uint16_t record)
+ : dataset_(dataset), record_(record) {}
+ /*!
+ @brief Returns true if the record and dataset id of the argument
+ Iptcdatum is equal to that of the object.
+ */
+ bool operator()(const Iptcdatum& iptcdatum) const
+ { return dataset_ == iptcdatum.tag() && record_ ==
iptcdatum.record(); }
+
+ private:
+ uint16_t dataset_;
+ uint16_t record_;
+
+ }; // class FindMetadatumById
+
+ /*!
+ @brief A container for Iptc data. This is a top-level class of
+ the %Exiv2 library.
+
+ Provide high-level access to the Iptc data of an image:
+ - read Iptc information from JPEG files
+ - access metadata through keys and standard C++ iterators
+ - add, modify and delete metadata
+ - write Iptc data to JPEG files
+ - extract Iptc metadata to files, insert from these files
+ */
+ class IptcData {
+ public:
+ //! IptcMetadata iterator type
+ typedef IptcMetadata::iterator iterator;
+ //! IptcMetadata const iterator type
+ typedef IptcMetadata::const_iterator const_iterator;
+
+ // Use the compiler generated constructors and assignment operator
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Load the Iptc data from a byte buffer. The format must follow
+ the IPTC IIM4 standard.
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @return 0 if successful;<BR>
+ 5 if Iptc data is invalid or corrupt;<BR>
+ */
+ int load(const byte* buf, long len);
+ /*!
+ @brief Write the Iptc data to a data buffer and return the data
buffer.
+ Caller owns this buffer. The copied data follows the IPTC IIM4
+ standard.
+ @return Data buffer containing the Iptc data.
+ */
+ DataBuf copy();
+ /*!
+ @brief Returns a reference to the %Iptcdatum that is associated with
a
+ particular \em key. If %IptcData does not already contain such
+ an %Iptcdatum, operator[] adds object \em Iptcdatum(key).
+
+ @note Since operator[] might insert a new element, it can't be a
const
+ member function.
+ */
+ Iptcdatum& operator[](const std::string& key);
+ /*!
+ @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;<BR>
+ 6 if the dataset already exists and is not repeatable
+ */
+ 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.
+ @return 0 if successful;<BR>
+ 6 if the dataset already exists and is not repeatable;<BR>
+ */
+ int add(const Iptcdatum& iptcdatum);
+ /*!
+ @brief Delete the Iptcdatum at iterator position pos, return the
+ position of the next Iptcdatum. Note that iterators into
+ the metadata, including pos, are potentially invalidated
+ by this call.
+ */
+ iterator erase(iterator pos);
+ /*!
+ @brief Delete all Iptcdatum instances resulting in an empty
container.
+ */
+ void clear() { iptcMetadata_.clear(); }
+ //! Sort metadata by key
+ void sortByKey();
+ //! Sort metadata by tag (aka dataset)
+ void sortByTag();
+ //! Begin of the metadata
+ iterator begin() { return iptcMetadata_.begin(); }
+ //! End of the metadata
+ iterator end() { return iptcMetadata_.end(); }
+ /*!
+ @brief Find a Iptcdatum with the given key, return an iterator to it.
+ If multiple entries with the same key exist, it is undefined
+ which of the matching metadata is found.
+ */
+ 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
+ same Ids exists, it is undefined which of the matching
+ metadata is found.
+ */
+ iterator findId(uint16_t dataset,
+ uint16_t record = IptcDataSets::application2);
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Begin of the metadata
+ const_iterator begin() const { return iptcMetadata_.begin(); }
+ //! End of the metadata
+ const_iterator end() const { return iptcMetadata_.end(); }
+ /*!
+ @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 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
+ same Ids exist it is undefined which of the matching
+ metadata is found.
+ */
+ const_iterator findId(uint16_t dataset,
+ uint16_t record = IptcDataSets::application2)
const;
+ //! Return true if there is no Iptc metadata
+ bool empty() const { return count() == 0; }
+ //! Get the number of metadata entries
+ long count() const { return static_cast<long>(iptcMetadata_.size()); }
+ /*!
+ @brief Return the exact size of all contained Iptc metadata
+ */
+ long size() const;
+ //@}
+
+ private:
+ /*!
+ @brief Read a single dataset payload and create a new metadata entry
+ @param dataSet DataSet number
+ @param record Record Id
+ @param data Pointer to the first byte of dataset payload
+ @param sizeData Length in bytes of dataset payload
+ @return 0 if successful.
+ */
+ int readData(uint16_t dataSet, uint16_t record,
+ const byte* data, uint32_t sizeData);
+
+ // Constant data
+ static const byte marker_; // Dataset marker
+
+ // DATA
+ IptcMetadata iptcMetadata_;
+ }; // class IptcData
+
+} // namespace Exiv2
+
+#endif // #ifndef IPTC_HPP_
Added: Extractor/src/plugins/exiv2/iptceasy.cpp
===================================================================
--- Extractor/src/plugins/exiv2/iptceasy.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/iptceasy.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,49 @@
+// ***************************************************************** -*- C++
-*-
+// iptceasy.cpp, $Rev: 560 $
+// The quickest way to access, set or modify Iptc metadata.
+
+#include "iptc.hpp"
+#include "image.hpp"
+#include <iostream>
+#include <iomanip>
+#include <cassert>
+
+int main(int argc, char* const argv[])
+try {
+ if (argc != 2) {
+ std::cout << "Usage: " << argv[0] << " file\n";
+ return 1;
+ }
+ std::string file(argv[1]);
+
+ Exiv2::IptcData iptcData;
+
+ iptcData["Iptc.Application2.Headline"] = "The headline I am";
+ iptcData["Iptc.Application2.Keywords"] = "Yet another keyword";
+ iptcData["Iptc.Application2.DateCreated"] = "2004-8-3";
+ iptcData["Iptc.Application2.Urgency"] = uint16_t(1);
+ iptcData["Iptc.Envelope.ModelVersion"] = 42;
+ iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00";
+ iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23
146";
+ iptcData["Iptc.0x0009.0x0001"] = "Who am I?";
+
+ Exiv2::StringValue value;
+ value.read("very!");
+ iptcData["Iptc.Application2.Urgency"] = value;
+
+ std::cout << "Time sent: " << iptcData["Iptc.Envelope.TimeSent"] << "\n";
+
+ // Open image file
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
+ assert (image.get() != 0);
+
+ // Set Iptc data and write it to the file
+ image->setIptcData(iptcData);
+ image->writeMetadata();
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return -1;
+}
Added: Extractor/src/plugins/exiv2/iptcprint.cpp
===================================================================
--- Extractor/src/plugins/exiv2/iptcprint.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/iptcprint.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,50 @@
+// ***************************************************************** -*- C++
-*-
+// iptcprint.cpp, $Rev: 578 $
+// Sample program to print the Iptc metadata of an image
+
+#include "image.hpp"
+#include "iptc.hpp"
+#include <iostream>
+#include <iomanip>
+#include <cassert>
+
+int main(int argc, char* const argv[])
+try {
+
+ if (argc != 2) {
+ std::cout << "Usage: " << argv[0] << " file\n";
+ return 1;
+ }
+
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
+ assert (image.get() != 0);
+ image->readMetadata();
+
+ Exiv2::IptcData &iptcData = image->iptcData();
+ if (iptcData.empty()) {
+ std::string error(argv[1]);
+ error += ": No Iptc data found in the file";
+ throw Exiv2::Error(1, error);
+ }
+
+ Exiv2::IptcData::iterator end = iptcData.end();
+ for (Exiv2::IptcData::iterator md = iptcData.begin(); md != end; ++md) {
+ std::cout << std::setw(44) << std::setfill(' ') << std::left
+ << md->key() << " "
+ << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << md->tag() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md->typeName() << " "
+ << std::dec << std::setw(3)
+ << std::setfill(' ') << std::right
+ << md->count() << " "
+ << std::dec << md->value()
+ << std::endl;
+ }
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return -1;
+}
Added: Extractor/src/plugins/exiv2/jpgimage.cpp
===================================================================
--- Extractor/src/plugins/exiv2/jpgimage.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/jpgimage.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,661 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: jpgimage.cpp
+ Version: $Rev: 563 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ Brad Schick (brad) <address@hidden>
+ History: 15-Jan-05, brad: split out from image.cpp
+
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: jpgimage.cpp 563 2005-04-21 07:21:53Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "jpgimage.hpp"
+#include "error.hpp"
+#include "futils.hpp"
+
+// + standard includes
+#include <cstring>
+#include <cassert>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ // Local functions. These could be static private functions on Image
+ // subclasses but then ImageFactory needs to be made a friend.
+ /*!
+ @brief Create a new ExvImage instance and return an auto-pointer to it.
+ Caller owns the returned object and the auto-pointer ensures that
+ it will be deleted.
+ */
+ Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create);
+ //! Check if the file iIo is an EXV file
+ bool isExvType(BasicIo& iIo, bool advance);
+ /*!
+ @brief Create a new JpegImage instance and return an auto-pointer to it.
+ Caller owns the returned object and the auto-pointer ensures that
+ it will be deleted.
+ */
+ Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create);
+ //! Check if the file iIo is a JPEG image.
+ bool isJpegType(BasicIo& iIo, bool advance);
+
+ const byte JpegBase::sos_ = 0xda;
+ const byte JpegBase::eoi_ = 0xd9;
+ const byte JpegBase::app0_ = 0xe0;
+ const byte JpegBase::app1_ = 0xe1;
+ const byte JpegBase::app13_ = 0xed;
+ const byte JpegBase::com_ = 0xfe;
+ const uint16_t JpegBase::iptc_ = 0x0404;
+ const char JpegBase::exifId_[] = "Exif\0\0";
+ const char JpegBase::jfifId_[] = "JFIF\0";
+ const char JpegBase::ps3Id_[] = "Photoshop 3.0\0";
+ const char JpegBase::bimId_[] = "8BIM";
+
+ JpegBase::JpegBase(BasicIo::AutoPtr io, bool create,
+ const byte initData[], long dataSize)
+ : io_(io)
+ {
+ if (create) {
+ initImage(initData, dataSize);
+ }
+ }
+
+ int JpegBase::initImage(const byte initData[], long dataSize)
+ {
+ if (io_->open() != 0) {
+ return 4;
+ }
+ IoCloser closer(*io_);
+ if (io_->write(initData, dataSize) != dataSize) {
+ return 4;
+ }
+ return 0;
+ }
+
+ bool JpegBase::good() const
+ {
+ if (io_->open() != 0) return false;
+ IoCloser closer(*io_);
+ return isThisType(*io_, false);
+ }
+
+ void JpegBase::clearMetadata()
+ {
+ clearIptcData();
+ clearExifData();
+ clearComment();
+ }
+
+ void JpegBase::clearIptcData()
+ {
+ iptcData_.clear();
+ }
+
+ void JpegBase::clearExifData()
+ {
+ exifData_.clear();
+ }
+
+ void JpegBase::clearComment()
+ {
+ comment_.erase();
+ }
+
+ void JpegBase::setExifData(const ExifData& exifData)
+ {
+ exifData_ = exifData;
+ }
+
+ void JpegBase::setIptcData(const IptcData& iptcData)
+ {
+ iptcData_ = iptcData;
+ }
+
+ void JpegBase::setComment(const std::string& comment)
+ {
+ comment_ = comment;
+ }
+
+ void JpegBase::setMetadata(const Image& image)
+ {
+ setIptcData(image.iptcData());
+ setExifData(image.exifData());
+ setComment(image.comment());
+ }
+
+ int JpegBase::advanceToMarker() const
+ {
+ int c = -1;
+ // Skips potential padding between markers
+ while ((c=io_->getb()) != 0xff) {
+ if (c == EOF) return -1;
+ }
+
+ // Markers can start with any number of 0xff
+ while ((c=io_->getb()) == 0xff) {
+ if (c == EOF) return -1;
+ }
+ return c;
+ }
+
+ void JpegBase::readMetadata()
+ {
+ if (io_->open() != 0) {
+ throw Error(9, io_->path(), strError());
+ }
+ IoCloser closer(*io_);
+ // Ensure that this is the correct image type
+ if (!isThisType(*io_, true)) {
+ if (io_->error() || io_->eof()) throw Error(14);
+ throw Error(15);
+ }
+ clearMetadata();
+ int search = 3;
+ const long bufMinSize = 16;
+ long bufRead = 0;
+ DataBuf buf(bufMinSize);
+
+ // Read section marker
+ int marker = advanceToMarker();
+ if (marker < 0) throw Error(15);
+
+ while (marker != sos_ && marker != eoi_ && search > 0) {
+ // Read size and signature (ok if this hits EOF)
+ bufRead = io_->read(buf.pData_, bufMinSize);
+ if (io_->error()) throw Error(14);
+ uint16_t size = getUShort(buf.pData_, bigEndian);
+
+ if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
+ if (size < 8) throw Error(15);
+ // Seek to begining and read the Exif data
+ io_->seek(8-bufRead, BasicIo::cur);
+ long sizeExifData = size - 8;
+ DataBuf rawExif(sizeExifData);
+ io_->read(rawExif.pData_, sizeExifData);
+ if (io_->error() || io_->eof()) throw Error(14);
+ if (exifData_.load(rawExif.pData_, sizeExifData)) throw
Error(15);
+ --search;
+ }
+ else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) ==
0) {
+ if (size < 16) throw Error(15);
+ // Read the rest of the APP13 segment
+ // needed if bufMinSize!=16: io_->seek(16-bufRead,
BasicIo::cur);
+ DataBuf psData(size - 16);
+ io_->read(psData.pData_, psData.size_);
+ if (io_->error() || io_->eof()) throw Error(14);
+ const byte *record = 0;
+ uint16_t sizeIptc = 0;
+ uint16_t sizeHdr = 0;
+ // Find actual Iptc data within the APP13 segment
+ if (!locateIptcData(psData.pData_, psData.size_, &record,
+ &sizeHdr, &sizeIptc)) {
+ assert(sizeIptc);
+ if (iptcData_.load(record + sizeHdr, sizeIptc)) throw
Error(15);
+ }
+ --search;
+ }
+ else if (marker == com_ && comment_.empty())
+ {
+ if (size < 2) throw Error(15);
+ // Jpegs can have multiple comments, but for now only read
+ // the first one (most jpegs only have one anyway). Comments
+ // are simple single byte ISO-8859-1 strings.
+ io_->seek(2-bufRead, BasicIo::cur);
+ buf.alloc(size-2);
+ io_->read(buf.pData_, size-2);
+ if (io_->error() || io_->eof()) throw Error(14);
+ comment_.assign(reinterpret_cast<char*>(buf.pData_), size-2);
+ while ( comment_.length()
+ && comment_.at(comment_.length()-1) == '\0') {
+ comment_.erase(comment_.length()-1);
+ }
+ --search;
+ }
+ else {
+ if (size < 2) throw Error(15);
+ // Skip the remainder of the unknown segment
+ if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(15);
+ }
+ // Read the beginning of the next segment
+ marker = advanceToMarker();
+ if (marker < 0) throw Error(15);
+ }
+ } // JpegBase::readMetadata
+
+
+ // Operates on raw data (rather than file streams) to simplify reuse
+ int JpegBase::locateIptcData(const byte *pPsData,
+ long sizePsData,
+ const byte **record,
+ uint16_t *const sizeHdr,
+ uint16_t *const sizeIptc) const
+ {
+ assert(record);
+ assert(sizeHdr);
+ assert(sizeIptc);
+ // Used for error checking
+ long position = 0;
+
+ // Data should follow Photoshop format, if not exit
+ while (position <= (sizePsData - 14) &&
+ memcmp(pPsData + position, bimId_, 4)==0) {
+ const byte *hrd = pPsData + position;
+ position += 4;
+ uint16_t type = getUShort(pPsData+ position, bigEndian);
+ position += 2;
+
+ // Pascal string is padded to have an even size (including size
byte)
+ byte psSize = pPsData[position] + 1;
+ psSize += (psSize & 1);
+ position += psSize;
+ if (position >= sizePsData) return -2;
+
+ // Data is also padded to be even
+ long dataSize = getULong(pPsData + position, bigEndian);
+ position += 4;
+ if (dataSize > sizePsData - position) return -2;
+
+ if (type == iptc_) {
+ *sizeIptc = static_cast<uint16_t>(dataSize);
+ *sizeHdr = psSize + 10;
+ *record = hrd;
+ return 0;
+ }
+ position += dataSize + (dataSize & 1);
+ }
+ return 3;
+ } // JpegBase::locateIptcData
+
+ void JpegBase::writeMetadata()
+ {
+ if (io_->open() != 0) {
+ throw Error(9, io_->path(), strError());
+ }
+ IoCloser closer(*io_);
+ BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
+ assert (tempIo.get() != 0);
+
+ doWriteMetadata(*tempIo); // may throw
+ io_->close();
+ io_->transfer(*tempIo); // may throw
+ } // JpegBase::writeMetadata
+
+ void JpegBase::doWriteMetadata(BasicIo& outIo)
+ {
+ if (!io_->isopen()) throw Error(20);
+ if (!outIo.isopen()) throw Error(21);
+
+ // Ensure that this is the correct image type
+ if (!isThisType(*io_, true)) {
+ if (io_->error() || io_->eof()) throw Error(20);
+ throw Error(22);
+ }
+
+ const long bufMinSize = 16;
+ long bufRead = 0;
+ DataBuf buf(bufMinSize);
+ const long seek = io_->tell();
+ int count = 0;
+ int search = 0;
+ int insertPos = 0;
+ int skipApp1Exif = -1;
+ int skipApp13Ps3 = -1;
+ int skipCom = -1;
+ DataBuf psData;
+
+ // Write image header
+ if (writeHeader(outIo)) throw Error(21);
+
+ // Read section marker
+ int marker = advanceToMarker();
+ if (marker < 0) throw Error(22);
+
+ // First find segments of interest. Normally app0 is first and we want
+ // to insert after it. But if app0 comes after com, app1 and app13 then
+ // don't bother.
+ while (marker != sos_ && marker != eoi_ && search < 3) {
+ // Read size and signature (ok if this hits EOF)
+ bufRead = io_->read(buf.pData_, bufMinSize);
+ if (io_->error()) throw Error(20);
+ uint16_t size = getUShort(buf.pData_, bigEndian);
+
+ if (marker == app0_) {
+ if (size < 2) throw Error(22);
+ insertPos = count + 1;
+ if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
+ }
+ else if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) ==
0) {
+ if (size < 8) throw Error(22);
+ skipApp1Exif = count;
+ ++search;
+ if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
+ }
+ else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) ==
0) {
+ if (size < 16) throw Error(22);
+ skipApp13Ps3 = count;
+ ++search;
+ // needed if bufMinSize!=16: io_->seek(16-bufRead,
BasicIo::cur);
+ psData.alloc(size - 16);
+ // Load PS data now to allow reinsertion at any point
+ io_->read(psData.pData_, psData.size_);
+ if (io_->error() || io_->eof()) throw Error(20);
+ }
+ else if (marker == com_ && skipCom == -1) {
+ if (size < 2) throw Error(22);
+ // Jpegs can have multiple comments, but for now only handle
+ // the first one (most jpegs only have one anyway).
+ skipCom = count;
+ ++search;
+ if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
+ }
+ else {
+ if (size < 2) throw Error(22);
+ if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
+ }
+ marker = advanceToMarker();
+ if (marker < 0) throw Error(22);
+ ++count;
+ }
+
+ if (exifData_.count() > 0) ++search;
+ if (iptcData_.count() > 0) ++search;
+ if (!comment_.empty()) ++search;
+
+ io_->seek(seek, BasicIo::beg);
+ count = 0;
+ marker = advanceToMarker();
+ if (marker < 0) throw Error(22);
+
+ // To simplify this a bit, new segments are inserts at either the start
+ // or right after app0. This is standard in most jpegs, but has the
+ // potential to change segment ordering (which is allowed).
+ // Segments are erased if there is no assigned metadata.
+ while (marker != sos_ && search > 0) {
+ // Read size and signature (ok if this hits EOF)
+ bufRead = io_->read(buf.pData_, bufMinSize);
+ if (io_->error()) throw Error(20);
+ // Careful, this can be a meaningless number for empty
+ // images with only an eoi_ marker
+ uint16_t size = getUShort(buf.pData_, bigEndian);
+
+ if (insertPos == count) {
+ byte tmpBuf[18];
+ if (!comment_.empty()) {
+ // Write COM marker, size of comment, and string
+ tmpBuf[0] = 0xff;
+ tmpBuf[1] = com_;
+ us2Data(tmpBuf + 2,
+ static_cast<uint16_t>(comment_.length()+3),
bigEndian);
+ if (outIo.write(tmpBuf, 4) != 4) throw Error(21);
+ if (outIo.write((byte*)comment_.data(),
(long)comment_.length())
+ != (long)comment_.length()) throw Error(21);
+ if (outIo.putb(0)==EOF) throw Error(21);
+ if (outIo.error()) throw Error(21);
+ --search;
+ }
+ if (exifData_.count() > 0) {
+ // Write APP1 marker, size of APP1 field, Exif id and Exif
data
+ DataBuf rawExif(exifData_.copy());
+ tmpBuf[0] = 0xff;
+ tmpBuf[1] = app1_;
+ us2Data(tmpBuf + 2,
+ static_cast<uint16_t>(rawExif.size_+8),
+ bigEndian);
+ memcpy(tmpBuf + 4, exifId_, 6);
+ if (outIo.write(tmpBuf, 10) != 10) throw Error(21);
+ if (outIo.write(rawExif.pData_, rawExif.size_)
+ != rawExif.size_) throw Error(21);
+ if (outIo.error()) throw Error(21);
+ --search;
+ }
+
+ const byte *record = psData.pData_;
+ uint16_t sizeIptc = 0;
+ uint16_t sizeHdr = 0;
+ // Safe to call with zero psData.size_
+ locateIptcData(psData.pData_, psData.size_, &record, &sizeHdr,
&sizeIptc);
+
+ // Data is rounded to be even
+ const int sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1);
+ if (psData.size_ > sizeOldData || iptcData_.count() > 0) {
+ // rawIptc may have size of zero.
+ DataBuf rawIptc(iptcData_.copy());
+ // write app13 marker, new size, and ps3Id
+ tmpBuf[0] = 0xff;
+ tmpBuf[1] = app13_;
+ const int sizeNewData = rawIptc.size_ ?
+ rawIptc.size_ + (rawIptc.size_ & 1) + 12 : 0;
+ us2Data(tmpBuf + 2,
+
static_cast<uint16_t>(psData.size_-sizeOldData+sizeNewData+16),
+ bigEndian);
+ memcpy(tmpBuf + 4, ps3Id_, 14);
+ if (outIo.write(tmpBuf, 18) != 18) throw Error(21);
+ if (outIo.error()) throw Error(21);
+
+ const long sizeFront = (long)(record - psData.pData_);
+ const long sizeEnd = psData.size_ - sizeFront -
sizeOldData;
+ // write data before old record.
+ if (outIo.write(psData.pData_, sizeFront) != sizeFront)
throw Error(21);
+
+ // write new iptc record if we have it
+ if (iptcData_.count() > 0) {
+ memcpy(tmpBuf, bimId_, 4);
+ us2Data(tmpBuf+4, iptc_, bigEndian);
+ tmpBuf[6] = 0;
+ tmpBuf[7] = 0;
+ ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian);
+ if (outIo.write(tmpBuf, 12) != 12) throw Error(21);
+ if (outIo.write(rawIptc.pData_, rawIptc.size_)
+ != rawIptc.size_) throw Error(21);
+ // data is padded to be even (but not included in size)
+ if (rawIptc.size_ & 1) {
+ if (outIo.putb(0)==EOF) throw Error(21);
+ }
+ if (outIo.error()) throw Error(21);
+ --search;
+ }
+
+ // write existing stuff after record
+ if (outIo.write(record+sizeOldData, sizeEnd)
+ != sizeEnd) throw Error(21);
+ if (outIo.error()) throw Error(21);
+ }
+ }
+ if (marker == eoi_) {
+ break;
+ }
+ else if (skipApp1Exif==count || skipApp13Ps3==count ||
skipCom==count) {
+ --search;
+ io_->seek(size-bufRead, BasicIo::cur);
+ }
+ else {
+ if (size < 2) throw Error(22);
+ buf.alloc(size+2);
+ io_->seek(-bufRead-2, BasicIo::cur);
+ io_->read(buf.pData_, size+2);
+ if (io_->error() || io_->eof()) throw Error(20);
+ if (outIo.write(buf.pData_, size+2) != size+2) throw Error(21);
+ if (outIo.error()) throw Error(21);
+ }
+
+ // Next marker
+ marker = advanceToMarker();
+ if (marker < 0) throw Error(22);
+ ++count;
+ }
+
+ // Copy rest of the Io
+ io_->seek(-2, BasicIo::cur);
+ buf.alloc(4096);
+ long readSize = 0;
+ while ((readSize=io_->read(buf.pData_, buf.size_))) {
+ if (outIo.write(buf.pData_, readSize) != readSize) throw Error(21);
+ }
+ if (outIo.error()) throw Error(21);
+
+ } // JpegBase::doWriteMetadata
+
+
+ const byte JpegImage::soi_ = 0xd8;
+ const byte JpegImage::blank_[] = {
+
0xFF,0xD8,0xFF,0xDB,0x00,0x84,0x00,0x10,0x0B,0x0B,0x0B,0x0C,0x0B,0x10,0x0C,0x0C,
+
0x10,0x17,0x0F,0x0D,0x0F,0x17,0x1B,0x14,0x10,0x10,0x14,0x1B,0x1F,0x17,0x17,0x17,
+
0x17,0x17,0x1F,0x1E,0x17,0x1A,0x1A,0x1A,0x1A,0x17,0x1E,0x1E,0x23,0x25,0x27,0x25,
+
0x23,0x1E,0x2F,0x2F,0x33,0x33,0x2F,0x2F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x01,0x11,0x0F,0x0F,0x11,0x13,0x11,0x15,0x12,
+
0x12,0x15,0x14,0x11,0x14,0x11,0x14,0x1A,0x14,0x16,0x16,0x14,0x1A,0x26,0x1A,0x1A,
+
0x1C,0x1A,0x1A,0x26,0x30,0x23,0x1E,0x1E,0x1E,0x1E,0x23,0x30,0x2B,0x2E,0x27,0x27,
+
0x27,0x2E,0x2B,0x35,0x35,0x30,0x30,0x35,0x35,0x40,0x40,0x3F,0x40,0x40,0x40,0x40,
+
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0xC0,0x00,0x11,0x08,0x00,0x01,0x00,
+
0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xFF,0xC4,0x00,0x4B,0x00,
+
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
0x00,0x07,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xDA,0x00,0x0C,0x03,0x01,0x00,0x02,
+ 0x11,0x03,0x11,0x00,0x3F,0x00,0xA0,0x00,0x0F,0xFF,0xD9 };
+
+ JpegImage::JpegImage(BasicIo::AutoPtr io, bool create)
+ : JpegBase(io, create, blank_, sizeof(blank_))
+ {
+ }
+
+ //! @cond IGNORE
+ JpegImage::JpegRegister::JpegRegister()
+ {
+ ImageFactory::registerImage(
+ Image::jpeg, newJpegInstance, isJpegType);
+ }
+ //! @endcond
+
+ int JpegImage::writeHeader(BasicIo& outIo) const
+ {
+ // Jpeg header
+ byte tmpBuf[2];
+ tmpBuf[0] = 0xff;
+ tmpBuf[1] = soi_;
+ if (outIo.write(tmpBuf, 2) != 2) return 4;
+ if (outIo.error()) return 4;
+ return 0;
+ }
+
+ bool JpegImage::isThisType(BasicIo& iIo, bool advance) const
+ {
+ return isJpegType(iIo, advance);
+ }
+
+ Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create)
+ {
+ Image::AutoPtr image = Image::AutoPtr(new JpegImage(io, create));
+ if (!image->good()) {
+ image.reset();
+ }
+ return image;
+ }
+
+ bool isJpegType(BasicIo& iIo, bool advance)
+ {
+ bool result = true;
+ byte tmpBuf[2];
+ iIo.read(tmpBuf, 2);
+ if (iIo.error() || iIo.eof()) return false;
+
+ if (0xff!=tmpBuf[0] || JpegImage::soi_!=tmpBuf[1]) {
+ result = false;
+ }
+ if (!advance || !result ) iIo.seek(-2, BasicIo::cur);
+ return result;
+ }
+
+ const char ExvImage::exiv2Id_[] = "Exiv2";
+ const byte ExvImage::blank_[] = { 0xff,0x01,'E','x','i','v','2',0xff,0xd9
};
+
+ ExvImage::ExvImage(BasicIo::AutoPtr io, bool create)
+ : JpegBase(io, create, blank_, sizeof(blank_))
+ {
+ }
+
+ //! @cond IGNORE
+ ExvImage::ExvRegister::ExvRegister()
+ {
+ ImageFactory::registerImage(
+ Image::exv, newExvInstance, isExvType);
+ }
+ //! @endcond
+
+ int ExvImage::writeHeader(BasicIo& outIo) const
+ {
+ // Exv header
+ byte tmpBuf[7];
+ tmpBuf[0] = 0xff;
+ tmpBuf[1] = 0x01;
+ memcpy(tmpBuf + 2, exiv2Id_, 5);
+ if (outIo.write(tmpBuf, 7) != 7) return 4;
+ if (outIo.error()) return 4;
+ return 0;
+ }
+
+ bool ExvImage::isThisType(BasicIo& iIo, bool advance) const
+ {
+ return isExvType(iIo, advance);
+ }
+
+ Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create)
+ {
+ Image::AutoPtr image;
+ if (create) {
+ image = Image::AutoPtr(new ExvImage(io, true));
+ }
+ else {
+ image = Image::AutoPtr(new ExvImage(io, false));
+ }
+ if (!image->good()) image.reset();
+ return image;
+ }
+
+ bool isExvType(BasicIo& iIo, bool advance)
+ {
+ bool result = true;
+ byte tmpBuf[7];
+ iIo.read(tmpBuf, 7);
+ if (iIo.error() || iIo.eof()) return false;
+
+ if ( 0xff != tmpBuf[0] || 0x01 != tmpBuf[1]
+ || memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) {
+ result = false;
+ }
+ if (!advance || !result ) iIo.seek(-7, BasicIo::cur);
+ return result;
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/jpgimage.hpp
===================================================================
--- Extractor/src/plugins/exiv2/jpgimage.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/jpgimage.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,405 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file jpgimage.hpp
+ @brief Class JpegImage to access JPEG images
+ @version $Rev: 563 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @author Brad Schick (brad)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 15-Jan-05, brad: split out from image.cpp
+ */
+#ifndef JPGIMAGE_HPP_
+#define JPGIMAGE_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "image.hpp"
+#include "basicio.hpp"
+#include "exif.hpp"
+#include "iptc.hpp"
+
+// + standard includes
+#include <string>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Abstract helper base class to access JPEG images.
+ */
+ class JpegBase : public Image {
+ public:
+ //! @name Creators
+ //@{
+ //! Virtual destructor.
+ virtual ~JpegBase() {}
+ //@}
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read all metadata from the image. Before this method
+ is called, the various metadata types (Iptc, Exif) will be empty.
+
+ This method returns success even when no metadata is found in
+ the image. Callers must therefore check the size of individual
+ metadata types before accessing the data.
+
+ @throw Error if opening or reading of the file fails or the image
+ data is not valid (does not look like JPEG data).
+ */
+ void readMetadata();
+ /*!
+ @brief Write metadata back to the image.
+
+ All existing metadata sections in the image are either created,
+ replaced, or erased. If values for a given metadata type have been
+ assigned, a section for that metadata type will either be created or
+ replaced. If no values have been assigned to a given metadata type,
+ any exists section for that metadata type will be removed from the
+ image.
+
+ @throw Error if the operation fails
+ */
+ void writeMetadata();
+ /*!
+ @brief Assign new exif data. The new exif data is not written
+ to the image until the writeMetadata() method is called.
+ @param exifData An ExifData instance holding exif data to be copied
+ */
+ void setExifData(const ExifData& exifData);
+ void clearExifData();
+ void setIptcData(const IptcData& iptcData);
+ void clearIptcData();
+ void setComment(const std::string& comment);
+ void clearComment();
+ void setMetadata(const Image& image);
+ void clearMetadata();
+ //@}
+
+ //! @name Accessors
+ //@{
+ bool good() const;
+ const ExifData& exifData() const { return exifData_; }
+ ExifData& exifData() { return exifData_; }
+ const IptcData& iptcData() const { return iptcData_; }
+ IptcData& iptcData() { return iptcData_; }
+ std::string comment() const { return comment_; }
+ BasicIo& io() const { return *io_; }
+ //@}
+ protected:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor that can either open an existing image or create
+ a new image from scratch. If a new image is to be created, any
+ existing data is overwritten.
+ @param io An auto-pointer that owns a BasicIo instance used for
+ reading and writing image metadata. \b Important: The constructor
+ takes ownership of the passed in BasicIo instance through the
+ auto-pointer. Callers should not continue to use the BasicIo
+ instance after it is passed to this method. Use the Image::io()
+ method to get a temporary reference.
+ @param create Specifies if an existing image should be read (false)
+ or if a new image should be created (true).
+ @param initData Data to initialize newly created images. Only used
+ when \em create is true. Should contain data for the smallest
+ valid image of the calling subclass.
+ @param dataSize Size of initData in bytes.
+ */
+ JpegBase(BasicIo::AutoPtr io, bool create,
+ const byte initData[], long dataSize);
+ //@}
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Writes the image header (aka signature) to the BasicIo
instance.
+ @param oIo BasicIo instance that the header is written to.
+ @return 0 if successful;<BR>
+ 4 if the output file can not be written to;<BR>
+ */
+ virtual int writeHeader(BasicIo& oIo) const =0;
+ //@}
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Determine if the content of the BasicIo instance is of the
+ type supported by this class.
+
+ The advance flag determines if the read position in the stream is
+ moved (see below). This applies only if the type matches and the
+ function returns true. If the type does not match, the stream
+ position is not changed. However, if reading from the stream fails,
+ the stream position is undefined. Consult the stream state to obtain
+ more information in this case.
+
+ @param iIo BasicIo instance to read from.
+ @param advance Flag indicating whether the position of the io
+ should be advanced by the number of characters read to
+ analyse the data (true) or left at its original
+ position (false). This applies only if the type matches.
+ @return true if the data matches the type of this class;<BR>
+ false if the data does not match;<BR>
+ */
+ virtual bool isThisType(BasicIo& iIo, bool advance) const =0;
+ //@}
+
+ // Constant Data
+ static const byte sos_; //!< JPEG SOS marker
+ static const byte eoi_; //!< JPEG EOI marker
+ static const byte app0_; //!< JPEG APP0 marker
+ static const byte app1_; //!< JPEG APP1 marker
+ static const byte app13_; //!< JPEG APP13 marker
+ static const byte com_; //!< JPEG Comment marker
+ static const char exifId_[]; //!< Exif identifier
+ static const char jfifId_[]; //!< JFIF identifier
+ static const char ps3Id_[]; //!< Photoshop marker
+ static const char bimId_[]; //!< Photoshop marker
+ static const uint16_t iptc_; //!< Photoshop Iptc marker
+
+ private:
+ // DATA
+ BasicIo::AutoPtr io_; //!< Image data io pointer
+ ExifData exifData_; //!< Exif data container
+ IptcData iptcData_; //!< Iptc data container
+ std::string comment_; //!< JPEG comment
+
+ // METHODS
+ /*!
+ @brief Advances associated io instance to one byte past the next
+ Jpeg marker and returns the marker. This method should be called
+ when the BasicIo instance is positioned one byte past the end of
a
+ Jpeg segment.
+ @return the next Jpeg segment marker if successful;<BR>
+ -1 if a maker was not found before EOF;<BR>
+ */
+ int advanceToMarker() const;
+ /*!
+ @brief Locates Photoshop formated Iptc data in a memory buffer.
+ Operates on raw data to simplify reuse.
+ @param pPsData Pointer to buffer containing entire payload of
+ Photoshop formated APP13 Jpeg segment.
+ @param sizePsData Size in bytes of pPsData.
+ @param record Output value that is set to the start of the Iptc
+ data block within pPsData (may not be null).
+ @param sizeHdr Output value that is set to the size of the header
+ within the Iptc data block pointed to by record (may not
+ be null).
+ @param sizeIptc Output value that is set to the size of the actual
+ Iptc data within the Iptc data block pointed to by record
+ (may not be null).
+ @return 0 if successful;<BR>
+ 3 if no Iptc data was found in pPsData;<BR>
+ -2 if the pPsData buffer does not contain valid data.
+ */
+ int locateIptcData(const byte *pPsData,
+ long sizePsData,
+ const byte **record,
+ uint16_t *const sizeHdr,
+ uint16_t *const sizeIptc) const;
+ /*!
+ @brief Initialize the image with the provided data.
+ @param initData Data to be written to the associated BasicIo
+ @param dataSize Size in bytes of data to be written
+ @return 0 if successful;<BR>
+ 4 if the image can not be written to.
+ */
+ int initImage(const byte initData[], long dataSize);
+ /*!
+ @brief Provides the main implementation of writeMetadata() by
+ writing all buffered metadata to the provided BasicIo.
+ @param oIo BasicIo instance to write to (a temporary location).
+
+ @return 4 if opening or writing to the associated BasicIo fails
+ */
+ void doWriteMetadata(BasicIo& oIo);
+
+ // NOT Implemented
+ //! Default constructor.
+ JpegBase();
+ //! Copy constructor
+ JpegBase(const JpegBase& rhs);
+ //! Assignment operator
+ JpegBase& operator=(const JpegBase& rhs);
+ }; // class JpegBase
+
+ /*!
+ @brief Class to access JPEG images
+ */
+ class JpegImage : public JpegBase {
+ friend bool isJpegType(BasicIo& iIo, bool advance);
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor that can either open an existing Jpeg image or
create
+ a new image from scratch. If a new image is to be created, any
+ existing data is overwritten. Since the constructor can not
return
+ a result, callers should check the good() method after object
+ construction to determine success or failure.
+ @param io An auto-pointer that owns a BasicIo instance used for
+ reading and writing image metadata. \b Important: The constructor
+ takes ownership of the passed in BasicIo instance through the
+ auto-pointer. Callers should not continue to use the BasicIo
+ instance after it is passed to this method. Use the Image::io()
+ method to get a temporary reference.
+ @param create Specifies if an existing image should be read (false)
+ or if a new file should be created (true).
+ */
+ JpegImage(BasicIo::AutoPtr io, bool create);
+ //! Destructor
+ ~JpegImage() {}
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct JpegRegister{
+ JpegRegister();
+ };
+ //! @endcond
+ protected:
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Determine if the content of the BasicIo instance is a Jpeg
image.
+ See base class for more details.
+ @param iIo BasicIo instance to read from.
+ @param advance Flag indicating whether the position of the io
+ should be advanced by the number of characters read to
+ analyse the data (true) or left at its original
+ position (false). This applies only if the type matches.
+ @return true if the data matches a Jpeg image;<BR>
+ false if the data does not match;<BR>
+ */
+ bool isThisType(BasicIo& iIo, bool advance) const;
+ //@}
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Writes a Jpeg header (aka signature) to the BasicIo instance.
+ @param oIo BasicIo instance that the header is written to.
+ @return 0 if successful;<BR>
+ 2 if the input image is invalid or can not be read;<BR>
+ 4 if the temporary image can not be written to;<BR>
+ -3 other temporary errors;<BR>
+ */
+ int writeHeader(BasicIo& oIo) const;
+ //@}
+ private:
+ // Constant data
+ static const byte soi_; // SOI marker
+ static const byte blank_[]; // Minimal Jpeg image
+
+ // NOT Implemented
+ //! Default constructor
+ JpegImage();
+ //! Copy constructor
+ JpegImage(const JpegImage& rhs);
+ //! Assignment operator
+ JpegImage& operator=(const JpegImage& rhs);
+ }; // class JpegImage
+
+ static JpegImage::JpegRegister jpegReg;
+
+ //! Helper class to access %Exiv2 files
+ class ExvImage : public JpegBase {
+ friend bool isExvType(BasicIo& iIo, bool advance);
+ public:
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor that can either open an existing Exv image or
create
+ a new image from scratch. If a new image is to be created, any
+ existing data is overwritten. Since the constructor can not
return
+ a result, callers should check the good() method after object
+ construction to determine success or failure.
+ @param io An auto-pointer that owns a BasicIo instance used for
+ reading and writing image metadata. \b Important: The constructor
+ takes ownership of the passed in BasicIo instance through the
+ auto-pointer. Callers should not continue to use the BasicIo
+ instance after it is passed to this method. Use the Image::io()
+ method to get a temporary reference.
+ @param create Specifies if an existing image should be read (false)
+ or if a new file should be created (true).
+ */
+ ExvImage(BasicIo::AutoPtr io, bool create);
+ //! Destructor
+ ~ExvImage() {}
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct ExvRegister{
+ ExvRegister();
+ };
+ //! @endcond
+ protected:
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Determine if the content of the BasicIo instance is an Exv
+ image. See base class for more details.
+ @param iIo BasicIo instance to read from.
+ @param advance Flag indicating whether the position of the io
+ should be advanced by the number of characters read to
+ analyse the data (true) or left at its original
+ position (false). This applies only if the type matches.
+ @return true if the data matches a Jpeg image;<BR>
+ false if the data does not match;<BR>
+ */
+ virtual bool isThisType(BasicIo& iIo, bool advance) const;
+ //@}
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Writes an Exv header (aka signature) to the BasicIo instance.
+ @param oIo BasicIo instance that the header is written to.
+ @return 0 if successful;<BR>
+ 4 if the output file can not be written to;<BR>
+ */
+ int writeHeader(BasicIo& oIo) const;
+ //@}
+ private:
+ // Constant data
+ static const char exiv2Id_[]; // Exv identifier
+ static const byte blank_[]; // Minimal exiv file
+
+ // NOT Implemented
+ //! Default constructor
+ ExvImage();
+ //! Copy constructor
+ ExvImage(const ExvImage& rhs);
+ //! Assignment operator
+ ExvImage& operator=(const ExvImage& rhs);
+ }; // class ExvImage
+
+ static ExvImage::ExvRegister exvReg;
+} // namespace Exiv2
+
+
+#endif // #ifndef JPGIMAGE_HPP_
Added: Extractor/src/plugins/exiv2/makernote.cpp
===================================================================
--- Extractor/src/plugins/exiv2/makernote.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/makernote.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,422 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: makernote.cpp
+ Version: $Rev: 579 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 18-Feb-04, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: makernote.cpp 579 2005-06-11 04:11:23Z ahuggel $");
+
+// Define DEBUG_* to output debug information to std::cerr, e.g, by calling
+// make like this: make DEFS=-DDEBUG_MAKERNOTE makernote.o
+//#define DEBUG_MAKERNOTE
+//#define DEBUG_REGISTRY
+
+//
*****************************************************************************
+// included header files
+#include "makernote.hpp"
+#include "error.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <iostream>
+#include <cassert>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ MakerNote::MakerNote(bool alloc)
+ : alloc_(alloc), offset_(0), byteOrder_(invalidByteOrder)
+ {
+ }
+
+ MakerNote::AutoPtr MakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ MakerNote::AutoPtr MakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ IfdMakerNote::IfdMakerNote(IfdId ifdId, bool alloc, bool hasNext)
+ : MakerNote(alloc),
+ absOffset_(true), adjOffset_(0), ifd_(ifdId, 0, alloc, hasNext)
+ {
+ }
+
+ IfdMakerNote::IfdMakerNote(const IfdMakerNote& rhs)
+ : MakerNote(rhs), absOffset_(rhs.absOffset_),
adjOffset_(rhs.adjOffset_),
+ header_(rhs.header_.size_), ifd_(rhs.ifd_)
+ {
+ memcpy(header_.pData_, rhs.header_.pData_, header_.size_);
+ }
+
+ int IfdMakerNote::read(const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ // Remember the offset
+ offset_ = offset;
+ // Set byte order if none is set yet
+ if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
+ // Read and check the header (and set offset adjustment)
+ int rc = readHeader(buf, len, byteOrder);
+ if (rc == 0) {
+ rc = checkHeader();
+ }
+ // Adjust the offset
+ offset = absOffset_ ? offset + adjOffset_ : adjOffset_;
+ // Read the makernote IFD
+ if (rc == 0) {
+ rc = ifd_.read(buf + headerSize(),
+ len - headerSize(),
+ byteOrder_,
+ offset);
+ }
+ if (rc == 0) {
+ // IfdMakerNote currently does not support multiple IFDs
+ if (ifd_.next() != 0) {
+ std::cerr << "Warning: Makernote IFD has a next pointer != 0 ("
+ << ifd_.next()
+ << "). Ignored.\n";
+ }
+ }
+#ifdef DEBUG_MAKERNOTE
+ hexdump(std::cerr, buf, len, offset);
+ if (rc == 0) ifd_.print(std::cerr);
+#endif
+
+ return rc;
+ } // IfdMakerNote::read
+
+ long IfdMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset)
+ {
+ // Remember the new offset
+ offset_ = offset;
+ // Set byte order if none is set yet
+ if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
+ // Adjust the offset
+ offset = absOffset_ ? offset + adjOffset_ : adjOffset_;
+
+ long len = 0;
+ len += copyHeader(buf);
+ len += ifd_.copy(buf + len, byteOrder_, offset);
+
+ return len;
+ } // IfdMakerNote::copy
+
+ int IfdMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ // Default implementation does nothing, assuming there is no header
+ return 0;
+ }
+
+ void IfdMakerNote::updateBase(byte* pNewBase)
+ {
+ if (absOffset_) {
+ ifd_.updateBase(pNewBase);
+ }
+ }
+
+ int IfdMakerNote::checkHeader() const
+ {
+ // Default implementation does nothing, assuming there is no header
+ return 0;
+ }
+
+ long IfdMakerNote::copyHeader(byte* buf) const
+ {
+ if (header_.size_ != 0) memcpy(buf, header_.pData_, header_.size_);
+ return header_.size_;
+ }
+
+ long IfdMakerNote::headerSize() const
+ {
+ return header_.size_;
+ }
+
+ Entries::const_iterator IfdMakerNote::findIdx(int idx) const
+ {
+ return ifd_.findIdx(idx);
+ }
+
+ long IfdMakerNote::size() const
+ {
+ return headerSize() + ifd_.size() + ifd_.dataSize();
+ }
+
+ IfdMakerNote::AutoPtr IfdMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ IfdMakerNote::AutoPtr IfdMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ MakerNoteFactory::Registry* MakerNoteFactory::pRegistry_ = 0;
+ MakerNoteFactory::IfdIdRegistry* MakerNoteFactory::pIfdIdRegistry_ = 0;
+
+ void MakerNoteFactory::init()
+ {
+ if (0 == pRegistry_) {
+ pRegistry_ = new Registry;
+ }
+ if (0 == pIfdIdRegistry_) {
+ pIfdIdRegistry_ = new IfdIdRegistry;
+ }
+ } // MakerNoteFactory::init
+
+ void MakerNoteFactory::registerMakerNote(IfdId ifdId,
+ MakerNote::AutoPtr makerNote)
+ {
+ init();
+ MakerNote* pMakerNote = makerNote.release();
+ assert(pMakerNote);
+ (*pIfdIdRegistry_)[ifdId] = pMakerNote;
+ } // MakerNoteFactory::registerMakerNote
+
+ MakerNote::AutoPtr MakerNoteFactory::create(IfdId ifdId, bool alloc)
+ {
+ assert(pIfdIdRegistry_ != 0);
+ IfdIdRegistry::const_iterator i = pIfdIdRegistry_->find(ifdId);
+ if (i == pIfdIdRegistry_->end()) return MakerNote::AutoPtr(0);
+ assert(i->second);
+ return i->second->create(alloc);
+ } // MakerNoteFactory::create
+
+ void MakerNoteFactory::registerMakerNote(const std::string& make,
+ const std::string& model,
+ CreateFct createMakerNote)
+ {
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Registering MakerNote create function for \""
+ << make << "\" and \"" << model << "\".\n";
+#endif
+ init();
+ // Todo: use case insensitive make and model comparisons
+
+ // Find or create a registry entry for make
+ ModelRegistry* pModelRegistry = 0;
+ assert(pRegistry_ != 0);
+ Registry::const_iterator end1 = pRegistry_->end();
+ Registry::const_iterator pos1;
+ for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) {
+ if (pos1->first == make) break;
+ }
+ if (pos1 != end1) {
+ pModelRegistry = pos1->second;
+ }
+ else {
+ pModelRegistry = new ModelRegistry;
+ pRegistry_->push_back(std::make_pair(make, pModelRegistry));
+ }
+ // Find or create a registry entry for model
+ ModelRegistry::iterator end2 = pModelRegistry->end();
+ ModelRegistry::iterator pos2;
+ for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) {
+ if (pos2->first == model) break;
+ }
+ if (pos2 != end2) {
+ pos2->second = createMakerNote;
+ }
+ else {
+ pModelRegistry->push_back(std::make_pair(model, createMakerNote));
+ }
+ } // MakerNoteFactory::registerMakerNote
+
+ MakerNote::AutoPtr MakerNoteFactory::create(const std::string& make,
+ const std::string& model,
+ bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Entering MakerNoteFactory::create(\""
+ << make << "\", \"" << model << "\", "
+ << (alloc == true ? "true" : "false") << ")\n";
+#endif
+ // loop through each make of the registry to find the best matching
make
+ int score = 0;
+ ModelRegistry* pModelRegistry = 0;
+#ifdef DEBUG_REGISTRY
+ std::string makeMatch;
+ std::cerr << "Searching make registry...\n";
+#endif
+ assert(pRegistry_ != 0);
+ Registry::const_iterator end1 = pRegistry_->end();
+ Registry::const_iterator pos1;
+ for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) {
+ int rc = match(pos1->first, make);
+ if (rc > score) {
+ score = rc;
+#ifdef DEBUG_REGISTRY
+ makeMatch = pos1->first;
+#endif
+ pModelRegistry = pos1->second;
+ }
+ }
+ if (pModelRegistry == 0) return MakerNote::AutoPtr(0);
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Best match is \"" << makeMatch << "\".\n";
+#endif
+
+ // loop through each model of the model registry to find the best match
+ score = 0;
+ CreateFct createMakerNote = 0;
+#ifdef DEBUG_REGISTRY
+ std::string modelMatch;
+ std::cerr << "Searching model registry...\n";
+#endif
+ ModelRegistry::const_iterator end2 = pModelRegistry->end();
+ ModelRegistry::const_iterator pos2;
+ for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) {
+ int rc = match(pos2->first, model);
+ if (rc > score) {
+ score = rc;
+#ifdef DEBUG_REGISTRY
+ modelMatch = pos2->first;
+#endif
+ createMakerNote = pos2->second;
+ }
+ }
+ if (createMakerNote == 0) return MakerNote::AutoPtr(0);
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Best match is \"" << modelMatch << "\".\n";
+#endif
+
+ return createMakerNote(alloc, buf, len, byteOrder, offset);
+ } // MakerNoteFactory::create
+
+ int MakerNoteFactory::match(const std::string& regEntry,
+ const std::string& key)
+ {
+#ifdef DEBUG_REGISTRY
+ std::cerr << " Matching registry entry \"" << regEntry << "\" ("
+ << (int)regEntry.size() << ") with key \"" << key << "\" ("
+ << (int)key.size() << "): ";
+#endif
+ // Todo: make the comparisons case insensitive
+
+ // Handle exact match (this is only necessary because of the different
+ // return value - the following algorithm also finds exact matches)
+ if (regEntry == key) {
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Exact match (score: " << (int)key.size() + 2 <<
")\n";
+#endif
+ return static_cast<int>(key.size()) + 2;
+ }
+ std::string uKey = key;
+ std::string uReg = regEntry;
+
+ int count = 0; // number of matching
characters
+ std::string::size_type ei = 0; // index in the registry entry
+ std::string::size_type ki = 0; // index in the key
+
+ while (ei != std::string::npos) {
+
+ std::string::size_type pos = uReg.find('*', ei);
+ if (pos != ei) {
+ std::string ss = pos == std::string::npos ?
+ uReg.substr(ei) : uReg.substr(ei, pos - ei);
+
+ if (ki == std::string::npos) {
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Not a match.\n";
+#endif
+ return 0;
+ }
+
+ bool found = false;
+ // Find the substr ss in the key starting from index ki.
+ // Take care of the special cases
+ // + where the substr must match the key from beg to end,
+ // + from beg,
+ // + to end
+ // + and where it can be anywhere in the key.
+ // If found, ki is adjusted to the position in the key after
ss.
+ if (ei == 0 && pos == std::string::npos) { // ei == 0 => ki == 0
+ if (0 == uKey.compare(ss)) {
+ found = true;
+ ki = std::string::npos;
+ }
+ }
+ else if (ei == 0) { // ei == 0 => ki == 0
+ if (0 == uKey.compare(0, ss.size(), ss)) {
+ found = true;
+ ki = ss.size();
+ }
+ }
+ else if (pos == std::string::npos) {
+ if ( ss.size() <= uKey.size()
+ && ki <= uKey.size() - ss.size()) {
+ if (0 == uKey.compare(
+ uKey.size() - ss.size(), ss.size(), ss)) {
+ found = true;
+ ki = std::string::npos;
+ }
+ }
+ }
+ else {
+ std::string::size_type idx = uKey.find(ss, ki);
+ if (idx != std::string::npos) {
+ found = true;
+ ki = idx + ss.size();
+ }
+ }
+
+ if (found) {
+ count += static_cast<int>(ss.size());
+ }
+ else {
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Not a match.\n";
+#endif
+ return 0;
+ }
+ } // if the substr is not empty
+
+ ei = pos == std::string::npos ? std::string::npos : pos + 1;
+
+ } // while ei doesn't point to the end of the registry entry
+
+#ifdef DEBUG_REGISTRY
+ std::cerr << "Match (score: " << count + 1 << ")\n";
+#endif
+ return count + 1;
+
+ } // MakerNoteFactory::match
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/makernote.hpp
===================================================================
--- Extractor/src/plugins/exiv2/makernote.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/makernote.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,474 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file makernote.hpp
+ @brief Contains the Exif %MakerNote interface, IFD %MakerNote and a
+ MakerNote factory
+ @version $Rev: 569 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 18-Feb-04, ahu: created
+ */
+#ifndef MAKERNOTE_HPP_
+#define MAKERNOTE_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "ifd.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <utility>
+#include <vector>
+#include <map>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Exif makernote interface
+
+ %MakerNote is a low-level container for makernote entries. The ExifData
+ container uses makernote entries just like the other Exif metadata. Thus,
+ clients can access Exif and makernote tags and their values uniformly
+ through the ExifData interface. The role of %MakerNote is very similar to
+ that of class Ifd (but makernotes do not need to be in IFD format, see
+ below). In addition, it provides %MakerNote specific tag descriptions and
+ print functions to interpret the makernote values.
+
+ MakerNote holds methods and functionality to
+ - read the makernote from a character buffer
+ - copy the makernote to a character buffer
+ - maintain a list of makernote entries (similar to IFD entries)
+ - interpret (print) the values of makernote tags
+
+ Makernotes can be added to the system by subclassing %MakerNote and
+ registering a create function for the new subclass together with the
+ camera make and model (which may contain wildcards) in the
+ MakerNoteFactory. Since the majority of makernotes are in IFD format,
+ subclass IfdMakerNote is provided. It contains an IFD container and
+ implements all interface methods related to the makernote entries. <BR>
+
+ To implement a new IFD makernote, all that you need to do is
+ - subclass %IfdMakerNote,
+ - implement methods to read and check the header (if any) as well as
+ clone and create functions,
+ - add a list of tag descriptions and appropriate print functions and
+ - register the camera make/model and create function in the makernote
factory.
+ .
+ See existing makernote implementations for examples, e.g., CanonMakerNote
+ or FujiMakerNote.
+
+ Finally, the header file which defines the static variable
+ \em register*MakerNote needs to be included from mn.hpp, to ensure that
+ the makernote is automatically registered in the factory.
+ */
+ class MakerNote {
+ //! @name Not implemented
+ //@{
+ //! Assignment not allowed (memory management mode alloc_ is const)
+ MakerNote& operator=(const MakerNote& rhs);
+ //@}
+
+ public:
+ //! Shortcut for a %MakerNote auto pointer.
+ typedef std::auto_ptr<MakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory
management
+ is required for the Entries.
+ */
+ explicit MakerNote(bool alloc =true);
+ //! Virtual destructor.
+ virtual ~MakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read the makernote, including the makernote header, from
+ character buffer buf of length len at position offset (from
the
+ start of the TIFF header) and encoded in byte order byteOrder.
+ Return 0 if successful.
+ */
+ virtual int read(const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset) =0;
+ /*!
+ @brief Copy (write) the makerNote to the character buffer buf at
+ position offset (from the start of the TIFF header), encoded
+ in byte order byteOrder. Update internal offsets if necessary.
+ Return the number of bytes written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder, long offset) =0;
+ /*!
+ @brief Add the entry to the makernote. No duplicate-check is
performed,
+ i.e., it is possible to add multiple entries with the same
tag.
+ The memory allocation mode of the entry to be added must be
the
+ same as that of the makernote and the IFD id of the entry must
+ be set to 'makerIfd'.
+ */
+ virtual void add(const Entry& entry) =0;
+ //! The first makernote entry
+ virtual Entries::iterator begin() =0;
+ //! End of the makernote entries
+ virtual Entries::iterator end() =0;
+ /*!
+ @brief Update the base pointer of the %MakerNote and all its entries
+ to \em pNewBase.
+
+ Allows to re-locate the underlying data buffer to a new location
+ \em pNewBase. This method only has an effect in non-alloc mode.
+ */
+ virtual void updateBase(byte* pNewBase) =0;
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! 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
+ long offset() const { return offset_; }
+ /*!
+ @brief Return an auto-pointer to an newly created, empty instance of
+ the same type as this. The makernote entries are <B>not</B>
+ copied. The caller owns the new object and the auto-pointer
+ ensures that it will be deleted.
+
+ @param alloc Memory management model for the newly created object.
+ Indicates if memory required to store data should be allocated
+ and deallocated (true) or not (false). If false, only pointers
+ to the buffer provided to read() will be kept. See Ifd for
more
+ background on this concept.
+ */
+ AutoPtr create(bool alloc =true) const;
+ /*!
+ @brief Return an auto-pointer to a clone of this object. The caller
+ owns the new object and the auto-pointer ensures that it will
+ be deleted.
+
+ @note In non-alloc mode the clone potentially contains pointers to
+ the same data buffer as the original.
+ Use updateBase(byte* pNewBase) to adjust them.
+ */
+ AutoPtr clone() const;
+ //! The first makernote entry
+ virtual Entries::const_iterator begin() const =0;
+ //! End of the makernote entries
+ virtual Entries::const_iterator end() const =0;
+ //! Find an entry by idx, return a const iterator to the record
+ virtual Entries::const_iterator findIdx(int idx) const =0;
+ //! Return the size of the makernote in bytes
+ virtual long size() const =0;
+ //@}
+
+ protected:
+ // DATA
+ /*!
+ @brief Flag to control the memory management: <BR>
+ True: requires memory allocation and deallocation, <BR>
+ False: no memory management needed.
+ */
+ const bool alloc_;
+ /*!
+ @brief Offset of the makernote from the start of the TIFF header
+ (for offset()).
+ */
+ long offset_;
+ /*!
+ @brief Alternative byte order to use, invalid if the byte order of
the
+ Exif block can be used
+ */
+ ByteOrder byteOrder_;
+
+ private:
+ //! Internal virtual create function.
+ virtual MakerNote* create_(bool alloc =true) const =0;
+ //! Internal virtual copy constructor.
+ virtual MakerNote* clone_() const =0;
+
+ }; // class MakerNote
+
+ //! Type for a pointer to a function creating a makernote
+ typedef MakerNote::AutoPtr (*CreateFct)(bool, const byte*, long,
ByteOrder, long);
+
+ /*!
+ @brief Interface for MakerNotes in IFD format. See MakerNote.
+ */
+ class IfdMakerNote : public MakerNote {
+ //! @name Not implemented
+ //@{
+ //! Assignment not allowed (Ifd does not have an assignment operator)
+ IfdMakerNote& operator=(const IfdMakerNote& rhs);
+ //@}
+
+ public:
+ //! Shortcut for an %IfdMakerNote auto pointer.
+ typedef std::auto_ptr<IfdMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Requires an %Ifd id and allows to choose whether
+ or not memory management is needed for the Entries and whether
+ the IFD has a next pointer.
+ */
+ explicit IfdMakerNote(IfdId ifdId, bool alloc =true, bool hasNext
=true);
+ //! Copy constructor
+ IfdMakerNote(const IfdMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~IfdMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ virtual int read(const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+ /*!
+ @brief Read the makernote header from the makernote databuffer. This
+ method must set the offset adjustment (adjOffset_), if needed
+ (assuming that the required information is in the header).
+ Return 0 if successful.
+ @note The default implementation does nothing, assuming there is no
+ header
+ */
+ virtual int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ virtual long copy(byte* buf, ByteOrder byteOrder, long offset);
+ virtual void add(const Entry& entry) { ifd_.add(entry); }
+ virtual Entries::iterator begin() { return ifd_.begin(); }
+ virtual Entries::iterator end() { return ifd_.end(); }
+ virtual void updateBase(byte* pNewBase);
+ //@}
+
+ //! @name Accessors
+ //@{
+ virtual Entries::const_iterator begin() const { return ifd_.begin(); }
+ virtual Entries::const_iterator end() const { return ifd_.end(); }
+ virtual Entries::const_iterator findIdx(int idx) const;
+ virtual long size() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ /*!
+ @brief Check the makernote header. This will typically check if a
+ required prefix string is present in the header. Return 0 if
+ successful.
+ @note The default implementation does nothing, assuming there is no
+ header
+ */
+ virtual int checkHeader() const;
+ /*!
+ @brief Write the makernote header to a character buffer, return the
+ number of characters written.
+ @note The default implementation copies the header_ buffer.
+ */
+ virtual long copyHeader(byte* buf) const;
+ /*!
+ @brief Return the size of the makernote header in bytes.
+ @note The default implementation returns the size of the header_
+ buffer.
+ */
+ virtual long headerSize() const;
+ //@}
+
+ protected:
+ // DATA
+ /*!
+ @brief True: Adjustment of the IFD offsets is to be added to the
+ offset from the start of the TIFF header (i.e., the
+ start of the Exif data section),
+ False: Adjustment of the IFD offsets is a suitable absolute
+ value. Ignore the offset from the start of the TIFF
+ header.
+ */
+ bool absOffset_;
+ /*!
+ @brief Adjustment of the IFD offsets relative to the start of the
+ TIFF header or to the start of the makernote, depending on
+ the setting of absOffset_.
+ */
+ long adjOffset_;
+ //! Data buffer for the makernote header
+ DataBuf header_;
+ //! The makernote IFD
+ Ifd ifd_;
+
+ private:
+ virtual IfdMakerNote* create_(bool alloc =true) const =0;
+ virtual IfdMakerNote* clone_() const =0;
+
+ }; // class IfdMakerNote
+
+ /*!
+ @brief Factory for MakerNote objects.
+
+ Maintains an associative list (tree) of camera makes/models and
+ corresponding %MakerNote create functions. Creates an instance of the
+ %MakerNote for one camera make/model. The factory is implemented as a
+ static class.
+ */
+ class MakerNoteFactory {
+ public:
+ /*!
+ @brief Register a %MakerNote create function for a camera make and
+ model.
+
+ Registers a create function for a %MakerNote for a given make and
+ model combination with the factory. Both the make and model strings
+ may contain wildcards ('*', e.g., "Canon*"). If the make already
+ exists in the registry, then a new branch for the model is added. If
+ the model also already exists, then the new create function replaces
+ the old one.
+
+ @param make Camera manufacturer. (Typically the string from the Exif
+ make tag.)
+ @param model Camera model. (Typically the string from the Exif
+ model tag.)
+ @param createMakerNote Pointer to a function to create a new
+ %MakerNote of a particular type.
+ */
+ static void registerMakerNote(const std::string& make,
+ const std::string& model,
+ CreateFct createMakerNote);
+
+ //! Register a %MakerNote prototype in the IFD id registry.
+ static void registerMakerNote(IfdId ifdId, MakerNote::AutoPtr
makerNote);
+
+ /*!
+ @brief Create the appropriate %MakerNote based on camera make and
+ model and possibly the contents of the makernote itself,
return
+ an auto-pointer to the newly created MakerNote instance.
Return
+ 0 if no %MakerNote is defined for the camera model.
+
+ The method searches the make-model tree for a make and model
+ combination in the registry that matches the search key. The search
is
+ case insensitive (Todo: implement case-insensitive comparisons) and
+ wildcards in the registry entries are supported. First the best
+ matching make is searched, then the best matching model for this make
+ is searched. If there is no matching make or no matching model within
+ the models registered for the best matching make, then no makernote
+ is created and the function returns 0. If a match is found, the
+ function invokes the registered create function and returns an
+ auto-pointer to the newly created MakerNote. The makernote pointed to
+ is owned by the caller of the function and the auto-pointer ensures
+ that it is deleted. The best match is an exact match, then a match
is
+ rated according to the number of matching characters. The makernote
+ buffer is passed on to the create function, which can based on its
+ content, automatically determine the correct version or flavour of
the
+ makernote required. This is used, e.g., to determine which of the
+ three Nikon makernotes to create.
+
+ @param make Camera manufacturer. (Typically the string from the Exif
+ make tag.)
+ @param model Camera model. (Typically the string from the Exif
+ model tag.)
+ @param alloc Memory management model for the new MakerNote.
Determines
+ if memory required to store data should be allocated and
+ deallocated (true) or not (false). If false, only pointers to
+ the buffer provided to read() will be kept. See Ifd for more
+ background on this concept.
+ @param buf Pointer to the makernote character buffer.
+ @param len Length of the makernote character buffer.
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded.
+ @param offset Offset from the start of the TIFF header of the
makernote
+ buffer.
+
+ @return An auto-pointer that owns a %MakerNote for the camera model.
+ If the camera is not supported, the pointer is 0.
+ */
+ static MakerNote::AutoPtr create(const std::string& make,
+ const std::string& model,
+ bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+ //! Create a %MakerNote for an IFD id.
+ static MakerNote::AutoPtr create(IfdId ifdId, bool alloc =true);
+
+ /*!
+ @brief Match a registry entry with a key (used for make and model).
+
+ The matching algorithm is case insensitive and wildcards ('*') in the
+ registry entry are supported. The best match is an exact match, then
+ a match is rated according to the number of matching characters.
+
+ @return A score value indicating how good the key and registry entry
+ match. 0 means no match, values greater than 0 indicate a
+ match, larger values are better matches:<BR>
+ 0: key and registry entry do not match<BR>
+ 1: a pure wildcard match, i.e., the registry entry is just
+ a wildcard.<BR>
+ Score values greater than 1 are computed by adding 1 to the
+ number of matching characters, except for an exact match,
+ which scores 2 plus the number of matching characters.
+ */
+ static int match(const std::string& regEntry, const std::string& key);
+
+ private:
+ //! @name Creators
+ //@{
+ //! Prevent construction: not implemented.
+ MakerNoteFactory() {}
+ //! Prevent copy construction: not implemented.
+ MakerNoteFactory(const MakerNoteFactory& rhs);
+ //@}
+
+ //! Creates the private static instance
+ static void init();
+
+ //! Type used to store model labels and %MakerNote create functions
+ typedef std::vector<std::pair<std::string, CreateFct> > ModelRegistry;
+ //! Type used to store a list of make labels and model registries
+ typedef std::vector<std::pair<std::string, ModelRegistry*> > Registry;
+ //! Type used to store a list of IFD ids and %MakerNote prototypes
+ typedef std::map<IfdId, MakerNote*> IfdIdRegistry;
+
+ // DATA
+ //! List of makernote types and corresponding makernote create
functions.
+ static Registry* pRegistry_;
+ //! List of makernote IFD ids and corresponding create functions.
+ static IfdIdRegistry* pIfdIdRegistry_;
+
+ }; // class MakerNoteFactory
+
+} // namespace Exiv2
+
+#endif // #ifndef MAKERNOTE_HPP_
Added: Extractor/src/plugins/exiv2/metacopy.cpp
===================================================================
--- Extractor/src/plugins/exiv2/metacopy.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/metacopy.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,182 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ Abstract : Tester application for image file handling
+
+ File : metacopy.cpp
+ Version : $Rev: 560 $
+ Author(s): Brad Schick (brad) <address@hidden>
+ History : 13-Jul-04, brad: created
+ */
+//
*****************************************************************************
+// included header files
+#include "image.hpp"
+#include "iptc.hpp"
+#include "exif.hpp"
+#include "types.hpp"
+#include "metacopy.hpp"
+#include <iostream>
+#include <fstream>
+#include <cassert>
+
+//
*****************************************************************************
+// Main
+int main(int argc, char* const argv[])
+{
+try {
+ // Handle command line arguments
+ Params params;
+ if (params.getopt(argc, argv)) {
+ params.usage();
+ return 1;
+ }
+ if (params.help_) {
+ params.help();
+ return 2;
+ }
+
+ // Use MemIo to increase test coverage.
+ Exiv2::BasicIo::AutoPtr fileIo(new Exiv2::FileIo(params.read_));
+ Exiv2::BasicIo::AutoPtr memIo(new Exiv2::MemIo);
+ memIo->transfer(*fileIo);
+
+ Exiv2::Image::AutoPtr readImg = Exiv2::ImageFactory::open(memIo);
+ assert(readImg.get() != 0);
+ readImg->readMetadata();
+
+ Exiv2::Image::AutoPtr writeImg = Exiv2::ImageFactory::open(params.write_);
+ assert(writeImg.get() != 0);
+ if (params.preserve_) writeImg->readMetadata();
+ if (params.iptc_) {
+ writeImg->setIptcData(readImg->iptcData());
+ }
+ if (params.exif_) {
+ writeImg->setExifData(readImg->exifData());
+ }
+ if (params.comment_) {
+ writeImg->setComment(readImg->comment());
+ }
+
+ try {
+ writeImg->writeMetadata();
+ }
+ catch (const Exiv2::AnyError&) {
+ std::cerr << params.progname() <<
+ ": Could not write metadata to (" << params.write_ << ")\n";
+ return 8;
+ }
+
+ return 0;
+}
+catch (Exiv2::AnyError& e) {
+ std::cerr << "Caught Exiv2 exception '" << e << "'\n";
+ return 10;
+}
+}
+
+int Params::option(int opt, const std::string& optarg, int optopt)
+{
+ int rc = 0;
+ switch (opt) {
+ case 'h': help_ = true; break;
+ case 'i': iptc_ = true; break;
+ case 'e': exif_ = true; break;
+ case 'c': comment_ = true; break;
+ case 'p': preserve_ = true; break;
+ case 'a':
+ iptc_ =true;
+ exif_ =true;
+ comment_ =true;
+ break;
+ case ':':
+ std::cerr << progname() << ": Option -" << static_cast<char>(optopt)
+ << " requires an argument\n";
+ rc = 1;
+ break;
+ case '?':
+ std::cerr << progname() << ": Unrecognized option -"
+ << static_cast<char>(optopt) << "\n";
+ rc = 1;
+ break;
+ default:
+ std::cerr << progname()
+ << ": getopt returned unexpected character code "
+ << std::hex << opt << "\n";
+ rc = 1;
+ break;
+ }
+
+ return rc;
+}
+
+int Params::nonoption(const std::string& argv)
+{
+ if (!write_.empty()) {
+ std::cerr << progname() << ": Unexpected extra argument (" << argv <<
")\n";
+ return 1;
+ }
+ if (first_) read_ = argv;
+ else write_ = argv;
+ first_ = false;
+ return 0;
+}
+
+int Params::getopt(int argc, char* const argv[])
+{
+ int rc = Util::Getopt::getopt(argc, argv, optstring_);
+ // Further consistency checks
+ if (help_==false) {
+ if (rc==0 && read_.empty() ) {
+ std::cerr << progname() << ": Read and write files must be
specified\n";
+ rc = 1;
+ }
+ if (rc==0 && write_.empty() ) {
+ std::cerr << progname() << ": Write file must be specified\n";
+ rc = 1;
+ }
+ if (preserve_ && iptc_ && exif_ && comment_ ) {
+ std::cerr << progname() << ": Option -p has no effect when all
metadata types are specified.\n";
+ rc = 1;
+ }
+ }
+ return rc;
+} // Params::getopt
+
+
+void Params::usage(std::ostream& os) const
+{
+ os << "\nReads and writes raw metadata. Use -h option for help.\n"
+ << "Usage: " << progname()
+ << " [-iecaph] readfile writefile\n";
+}
+
+void Params::help(std::ostream& os) const
+{
+ usage(os);
+ os << "\nOptions:\n"
+ << " -i Read Iptc data from readfile and write to writefile.\n"
+ << " -e Read Exif data from readfile and write to writefile.\n"
+ << " -c Read Jpeg comment from readfile and write to
writefile.\n"
+ << " -a Read all metadata from readfile and write to
writefile.\n"
+ << " -p Preserve existing metadata in writefile if not
replaced.\n"
+ << " -h Display this help and exit.\n\n";
+} // Params::help
+
Added: Extractor/src/plugins/exiv2/metacopy.hpp
===================================================================
--- Extractor/src/plugins/exiv2/metacopy.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/metacopy.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,86 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file metacopy.hpp
+ @brief Defines class Params, used for the command line handling
+ @version $Rev: 538 $
+ @author Brad Schick (brad) <address@hidden>
+ @date 13-Jul-04, brad: created
+ */
+#ifndef METACOPY_HPP_
+#define METACOPY_HPP_
+
+#include "utils.hpp"
+
+class Params : public Util::Getopt {
+private:
+ std::string optstring_;
+ bool first_;
+
+public:
+ bool help_; //!< Help option flag.
+ bool iptc_; //!< Iptc option flag.
+ bool exif_; //!< Exif option flag.
+ bool comment_; //!< JPEG comment option flag.
+ bool preserve_; //!< Preserve existing metadata option flag.
+ std::string read_; //!< Source file
+ std::string write_; //!< Destination file
+
+public:
+ /*!
+ @brief Default constructor. Note that optstring_ is initialized here.
+ */
+ Params() : optstring_(":iecaph"),
+ first_(true),
+ help_(false),
+ iptc_(false),
+ exif_(false),
+ comment_(false),
+ preserve_(false)
+ {}
+
+ /*!
+ @brief Call Getopt::getopt() with optstring, to initiate command line
+ argument parsing, perform consistency checks after all command
line
+ arguments are parsed.
+
+ @param argc Argument count as passed to main() on program invocation.
+ @param argv Argument array as passed to main() on program invocation.
+
+ @return 0 if successful, >0 in case of errors.
+ */
+ int getopt(int argc, char* const argv[]);
+
+ //! Handle options and their arguments.
+ virtual int option(int opt, const std::string& optarg, int optopt);
+
+ //! Handle non-option parameters.
+ virtual int nonoption(const std::string& argv);
+
+ //! Print a minimal usage note to an output stream.
+ void usage(std::ostream& os =std::cout) const;
+
+ //! Print further usage explanations to an output stream.
+ void help(std::ostream& os =std::cout) const;
+
+}; // class Params
+
+#endif // METACOPY_HPP_
Added: Extractor/src/plugins/exiv2/metadatum.cpp
===================================================================
--- Extractor/src/plugins/exiv2/metadatum.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/metadatum.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,76 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: metadatum.cpp
+ Version: $Rev: 538 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ Brad Schick (brad) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 31-Jul-04, brad: isolated as a component
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: metadatum.cpp 538 2005-03-12 16:43:06Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "metadatum.hpp"
+
+// + standard includes
+#include <iostream>
+#include <iomanip>
+
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Key::AutoPtr Key::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ std::ostream& operator<<(std::ostream& os, const Metadatum& md)
+ {
+ os << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << md.tag() << " "
+ << std::setw(40) << std::setfill(' ') << std::left
+ << md.key() << " "
+ << std::setw(9) << std::setfill(' ') << std::left
+ << md.typeName() << " "
+ << std::dec << md.value()
+ << "\n";
+ return os;
+ }
+
+ bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs)
+ {
+ return lhs.tag() < rhs.tag();
+ }
+
+
+ bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs)
+ {
+ return lhs.key() < rhs.key();
+ }
+
+} // namespace Exiv2
+
Added: Extractor/src/plugins/exiv2/metadatum.hpp
===================================================================
--- Extractor/src/plugins/exiv2/metadatum.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/metadatum.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,294 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file metadatum.hpp
+ @brief Provides abstract base classes Metadatum and Key
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @author Brad Schick (brad)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created<BR>
+ 31-Jul-04, brad: isolated as a component<BR>
+ 23-Aug-04, ahu: added Key
+ */
+#ifndef METADATUM_HPP_
+#define METADATUM_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Abstract base class defining the %Key of a metadatum.
+ Keys are used to identify and group metadata.
+ */
+ class Key {
+ public:
+ //! Shortcut for a %Key auto pointer.
+ typedef std::auto_ptr<Key> AutoPtr;
+
+ //! @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_t tag() const =0;
+ /*!
+ @brief Return an auto-pointer to a copy of itself (deep copy).
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+ */
+ AutoPtr clone() const;
+ /*!
+ @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; }
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual Key* clone_() const =0;
+
+ }; // 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
+ //@{
+ /*!
+ @brief Set the value. This method copies (clones) the value pointed
+ to by pValue.
+ */
+ virtual void setValue(const Value* pValue) =0;
+ /*!
+ @brief Set the value to the string buf.
+ Uses Value::read(const std::string& buf). If the metadatum
does
+ not have a value yet, then an AsciiValue is created.
+ */
+ virtual void setValue(const std::string& buf) =0;
+ //@}
+
+ //! @name Accessors
+ //@{
+ /*!
+ @brief Write value to a data buffer and return the number
+ of bytes written.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return Number of characters written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder) const =0;
+ /*!
+ @brief Return the key of the metadatum. The key is of the form
+ 'familyName.ifdItem.tagName'. Note however that the key
+ is not necessarily unique, i.e., an ExifData may contain
+ multiple metadata with the same key.
+ */
+ virtual std::string key() 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
+ virtual uint16_t tag() const =0;
+ //! Return the type id of the value
+ virtual TypeId typeId() const =0;
+ //! Return the name of the type
+ virtual const char* typeName() const =0;
+ //! Return the size in bytes of one component of this type
+ virtual long typeSize() const =0;
+ //! Return the number of components in the value
+ virtual long count() const =0;
+ //! Return the size of the value in bytes
+ virtual long size() const =0;
+ //! Return the value as a string.
+ virtual std::string toString() const =0;
+ /*!
+ @brief Return the n-th component of the value converted to long. The
+ return value is -1 if the value of the Metadatum is not set
and
+ the behaviour of the method is undefined if there is no n-th
+ component.
+ */
+ virtual long toLong(long n =0) const =0;
+ /*!
+ @brief Return the n-th component of the value converted to float.
The
+ return value is -1 if the value of the Metadatum is not set
and
+ the behaviour of the method is undefined if there is no n-th
+ component.
+ */
+ virtual float toFloat(long n =0) const =0;
+ /*!
+ @brief Return the n-th component of the value converted to
+ Rational. The return value is -1/1 if the value of the
+ Metadatum is not set and the behaviour of the method is
+ undefined if there is no n-th component.
+ */
+ virtual Rational toRational(long n =0) const =0;
+ /*!
+ @brief Return an auto-pointer to a copy (clone) of the value. The
+ caller owns this copy and the auto-poiner ensures that it will
+ be deleted.
+
+ This method is provided for users who need full control over the
+ value. A caller may, e.g., downcast the pointer to the appropriate
+ subclass of Value to make use of the interface of the subclass to set
+ or modify its contents.
+
+ @return An auto-pointer containing a pointer to a copy (clone) of
the
+ value, 0 if the value is not set.
+ */
+ virtual Value::AutoPtr getValue() const =0;
+ /*!
+ @brief Return a constant reference to the value.
+
+ This method is provided mostly for convenient and versatile output of
+ the value which can (to some extent) be formatted through standard
+ stream manipulators. Do not attempt to write to the value through
+ this reference.
+
+ <b>Example:</b> <br>
+ @code
+ ExifData::const_iterator i = exifData.findKey(key);
+ if (i != exifData.end()) {
+ std::cout << i->key() << " " << std::hex << i->value() << "\n";
+ }
+ @endcode
+
+ @return A constant reference to the value.
+ @throw Error if the value is not set.
+ */
+ virtual const Value& value() const =0;
+ //@}
+
+ protected:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Assignment operator. Protected so that it can only be used
+ by subclasses but not directly.
+ */
+ Metadatum& operator=(const Metadatum& rhs) { return *this; }
+ //@}
+
+ }; // class Metadatum
+
+ //! Unary predicate that matches a Exifdatum with a given key
+ class FindMetadatumByKey {
+ public:
+ //! Constructor, initializes the object with the tag to look for
+ FindMetadatumByKey(const std::string& key) : key_(key) {}
+ /*!
+ @brief Returns true if the key of the argument metadatum is equal
+ to that of the object.
+ */
+ bool operator()(const Metadatum& metadatum) const
+ { return key_ == metadatum.key(); }
+
+ private:
+ std::string key_;
+
+ }; // class FindMetadatumByTag
+
+
+ /*!
+ @brief Output operator for Metadatum types, printing the interpreted
+ tag value.
+ */
+ std::ostream& operator<<(std::ostream& os, const Metadatum& md);
+ /*!
+ @brief Compare two metadata by tag. Return true if the tag of metadatum
+ lhs is less than that of rhs.
+ */
+ bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs);
+ /*!
+ @brief Compare two metadata by key. Return true if the key of metadatum
+ lhs is less than that of rhs.
+ */
+ bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs);
+
+} // namespace Exiv2
+
+#endif // #ifndef METADATUM_HPP_
Added: Extractor/src/plugins/exiv2/mn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/mn.hpp 2005-07-03 19:32:53 UTC (rev 1227)
+++ Extractor/src/plugins/exiv2/mn.hpp 2005-07-03 19:43:52 UTC (rev 1228)
@@ -0,0 +1,43 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file mn.hpp
+ @brief Include all makernote header files. Makes sure that the static
+ variable used to register makernotes is instantiated.
+ @version $Rev: 581 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 28-May-05, ahu: created
+ */
+#ifndef MN_HPP_
+#define MN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "canonmn.hpp"
+#include "fujimn.hpp"
+#include "nikonmn.hpp"
+#include "olympusmn.hpp"
+#include "panasonicmn.hpp"
+#include "sigmamn.hpp"
+#include "sonymn.hpp"
+
+#endif // #ifndef MN_HPP_
Added: Extractor/src/plugins/exiv2/nikonmn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/nikonmn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/nikonmn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,870 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * Lens database to decode Exif.Nikon3.LensData
+ * Copyright (C) 2005 Robert Rottmerhusen <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: nikonmn.cpp
+ Version: $Rev: 588 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 17-May-04, ahu: created
+ 25-May-04, ahu: combined all Nikon formats in one component
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: nikonmn.cpp 588 2005-06-14 13:57:39Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "nikonmn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+#include "image.hpp"
+#include "tags.hpp"
+#include "error.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+#include <cstring>
+
+#define EXV_HAVE_LENSDATA
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ Nikon1MakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("NIKON*", "*",
createNikonMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ nikon1IfdId, MakerNote::AutoPtr(new Nikon1MakerNote));
+
+ ExifTags::registerMakerTagInfo(nikon1IfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Nikon1 MakerNote Tag Info
+ const TagInfo Nikon1MakerNote::tagInfo_[] = {
+ TagInfo(0x0001, "Version", "Nikon Makernote version", nikon1IfdId,
makerTags, undefined, printValue),
+ TagInfo(0x0002, "ISOSpeed", "ISO speed setting", nikon1IfdId,
makerTags, unsignedShort, print0x0002),
+ TagInfo(0x0003, "ColorMode", "Color mode", nikon1IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0004, "Quality", "Image quality setting", nikon1IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0005, "WhiteBalance", "White balance", nikon1IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0006, "Sharpening", "Image sharpening setting", nikon1IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0007, "Focus", "Focus mode", nikon1IfdId, makerTags,
asciiString, print0x0007),
+ TagInfo(0x0008, "Flash", "Flash mode", nikon1IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x000a, "0x000a", "Unknown", nikon1IfdId, makerTags,
unsignedRational, printValue),
+ TagInfo(0x000f, "ISOSelection", "ISO selection", nikon1IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0010, "DataDump", "Data dump", nikon1IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0080, "ImageAdjustment", "Image adjustment setting",
nikon1IfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0082, "Adapter", "Adapter used", nikon1IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0085, "FocusDistance", "Manual focus distance", nikon1IfdId,
makerTags, unsignedRational, print0x0085),
+ TagInfo(0x0086, "DigitalZoom", "Digital zoom setting", nikon1IfdId,
makerTags, unsignedRational, print0x0086),
+ TagInfo(0x0088, "AFFocusPos", "AF focus position", nikon1IfdId,
makerTags, undefined, print0x0088),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownNikon1MnTag)", "Unknown Nikon1MakerNote tag",
nikon1IfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ Nikon1MakerNote::Nikon1MakerNote(bool alloc)
+ : IfdMakerNote(nikon1IfdId, alloc)
+ {
+ }
+
+ Nikon1MakerNote::Nikon1MakerNote(const Nikon1MakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ Nikon1MakerNote::AutoPtr Nikon1MakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ Nikon1MakerNote* Nikon1MakerNote::create_(bool alloc) const
+ {
+ return new Nikon1MakerNote(alloc);
+ }
+
+ Nikon1MakerNote::AutoPtr Nikon1MakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Nikon1MakerNote* Nikon1MakerNote::clone_() const
+ {
+ return new Nikon1MakerNote(*this);
+ }
+
+ std::ostream& Nikon1MakerNote::print0x0002(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() > 1) {
+ os << value.toLong(1);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& Nikon1MakerNote::print0x0007(std::ostream& os,
+ const Value& value)
+ {
+ std::string focus = value.toString();
+ if (focus == "AF-C ") os << "Continuous autofocus";
+ else if (focus == "AF-S ") os << "Single autofocus";
+ else os << "(" << value << ")";
+ return os;
+ }
+
+ std::ostream& Nikon1MakerNote::print0x0085(std::ostream& os,
+ const Value& value)
+ {
+ Rational distance = value.toRational();
+ if (distance.first == 0) {
+ os << "Unknown";
+ }
+ else if (distance.second != 0) {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(2)
+ << (float)distance.first / distance.second
+ << " m";
+ os.copyfmt(oss);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& Nikon1MakerNote::print0x0086(std::ostream& os,
+ const Value& value)
+ {
+ Rational zoom = value.toRational();
+ if (zoom.first == 0) {
+ os << "Not used";
+ }
+ else if (zoom.second != 0) {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(1)
+ << (float)zoom.first / zoom.second
+ << "x";
+ os.copyfmt(oss);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& Nikon1MakerNote::print0x0088(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() > 1) {
+ switch (value.toLong(1)) {
+ case 0: os << "Center"; break;
+ case 1: os << "Top"; break;
+ case 2: os << "Bottom"; break;
+ case 3: os << "Left"; break;
+ case 4: os << "Right"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ //! @cond IGNORE
+ Nikon2MakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote(
+ nikon2IfdId, MakerNote::AutoPtr(new Nikon2MakerNote));
+
+ ExifTags::registerMakerTagInfo(nikon2IfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Nikon2 MakerNote Tag Info
+ const TagInfo Nikon2MakerNote::tagInfo_[] = {
+ TagInfo(0x0002, "0x0002", "Unknown", nikon2IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0003, "Quality", "Image quality setting", nikon2IfdId,
makerTags, unsignedShort, print0x0003),
+ TagInfo(0x0004, "ColorMode", "Color mode", nikon2IfdId, makerTags,
unsignedShort, print0x0004),
+ TagInfo(0x0005, "ImageAdjustment", "Image adjustment setting",
nikon2IfdId, makerTags, unsignedShort, print0x0005),
+ TagInfo(0x0006, "ISOSpeed", "ISO speed setting", nikon2IfdId,
makerTags, unsignedShort, print0x0006),
+ TagInfo(0x0007, "WhiteBalance", "White balance", nikon2IfdId,
makerTags, unsignedShort, print0x0007),
+ TagInfo(0x0008, "Focus", "Focus mode", nikon2IfdId, makerTags,
unsignedRational, printValue),
+ TagInfo(0x0009, "0x0009", "Unknown", nikon2IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x000a, "DigitalZoom", "Digital zoom setting", nikon2IfdId,
makerTags, unsignedRational, print0x000a),
+ TagInfo(0x000b, "Adapter", "Adapter used", nikon2IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0f00, "0x0f00", "Unknown", nikon2IfdId, makerTags,
unsignedLong, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownNikon2MnTag)", "Unknown Nikon2MakerNote tag",
nikon2IfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ Nikon2MakerNote::Nikon2MakerNote(bool alloc)
+ : IfdMakerNote(nikon2IfdId, alloc)
+ {
+ byte buf[] = {
+ 'N', 'i', 'k', 'o', 'n', '\0', 0x00, 0x01
+ };
+ readHeader(buf, 8, byteOrder_);
+ }
+
+ Nikon2MakerNote::Nikon2MakerNote(const Nikon2MakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int Nikon2MakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 8) return 1;
+
+ header_.alloc(8);
+ memcpy(header_.pData_, buf, header_.size_);
+ adjOffset_ = 8;
+ return 0;
+ }
+
+ int Nikon2MakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the Nikon prefix
+ if ( header_.size_ < 8
+ || std::string(reinterpret_cast<char*>(header_.pData_), 6)
+ != std::string("Nikon\0", 6)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ Nikon2MakerNote::AutoPtr Nikon2MakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ Nikon2MakerNote* Nikon2MakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote(new Nikon2MakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ Nikon2MakerNote::AutoPtr Nikon2MakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Nikon2MakerNote* Nikon2MakerNote::clone_() const
+ {
+ return new Nikon2MakerNote(*this);
+ }
+
+ std::ostream& Nikon2MakerNote::print0x0003(std::ostream& os,
+ const Value& value)
+ {
+ long quality = value.toLong();
+ switch (quality) {
+ case 1: os << "VGA Basic"; break;
+ case 2: os << "VGA Normal"; break;
+ case 3: os << "VGA Fine"; break;
+ case 4: os << "SXGA Basic"; break;
+ case 5: os << "SXGA Normal"; break;
+ case 6: os << "SXGA Fine"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon2MakerNote::print0x0004(std::ostream& os,
+ const Value& value)
+ {
+ long color = value.toLong();
+ switch (color) {
+ case 1: os << "Color"; break;
+ case 2: os << "Monochrome"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon2MakerNote::print0x0005(std::ostream& os,
+ const Value& value)
+ {
+ long adjustment = value.toLong();
+ switch (adjustment) {
+ case 0: os << "Normal"; break;
+ case 1: os << "Bright+"; break;
+ case 2: os << "Bright-"; break;
+ case 3: os << "Contrast+"; break;
+ case 4: os << "Contrast-"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon2MakerNote::print0x0006(std::ostream& os,
+ const Value& value)
+ {
+ long iso = value.toLong();
+ switch (iso) {
+ case 0: os << "80"; break;
+ case 2: os << "160"; break;
+ case 4: os << "320"; break;
+ case 5: os << "100"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon2MakerNote::print0x0007(std::ostream& os,
+ const Value& value)
+ {
+ long wb = value.toLong();
+ switch (wb) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Preset"; break;
+ case 2: os << "Daylight"; break;
+ case 3: os << "Incandescent"; break;
+ case 4: os << "Fluorescent"; break;
+ case 5: os << "Cloudy"; break;
+ case 6: os << "Speedlight"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon2MakerNote::print0x000a(std::ostream& os,
+ const Value& value)
+ {
+ Rational zoom = value.toRational();
+ if (zoom.first == 0) {
+ os << "Not used";
+ }
+ else if (zoom.second != 0) {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(1)
+ << (float)zoom.first / zoom.second
+ << "x";
+ os.copyfmt(oss);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ //! @cond IGNORE
+ Nikon3MakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote(
+ nikon3IfdId, MakerNote::AutoPtr(new Nikon3MakerNote));
+
+ ExifTags::registerMakerTagInfo(nikon3IfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Nikon3 MakerNote Tag Info
+ const TagInfo Nikon3MakerNote::tagInfo_[] = {
+ TagInfo(0x0001, "Version", "Nikon Makernote version", nikon3IfdId,
makerTags, undefined, printValue),
+ TagInfo(0x0002, "ISOSpeed", "ISO speed used", nikon3IfdId, makerTags,
unsignedShort, print0x0002),
+ TagInfo(0x0003, "ColorMode", "Color mode", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0004, "Quality", "Image quality setting", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0005, "WhiteBalance", "White balance", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0006, "Sharpening", "Image sharpening setting", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0007, "Focus", "Focus mode", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0008, "FlashSetting", "Flash setting", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0009, "FlashMode", "Flash mode", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x000b, "WhiteBalanceBias", "White balance bias", nikon3IfdId,
makerTags, signedShort, printValue),
+// TagInfo(0x000c, "ColorBalance1", "Color balance 1", nikon3IfdId,
makerTags, xxx, printValue),
+ TagInfo(0x000d, "0x000d", "Unknown", nikon3IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x000e, "ExposureDiff", "Exposure difference", nikon3IfdId,
makerTags, undefined, printValue),
+ TagInfo(0x000f, "ISOSelection", "ISO selection", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0010, "DataDump", "Data dump", nikon3IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0011, "ThumbOffset", "Thumbnail IFD offset", nikon3IfdId,
makerTags, unsignedLong, printValue),
+ TagInfo(0x0012, "FlashComp", "Flash compensation setting",
nikon3IfdId, makerTags, undefined, print0x0012),
+ TagInfo(0x0013, "ISOSetting", "ISO speed setting", nikon3IfdId,
makerTags, unsignedShort, print0x0002), // use 0x0002 print fct
+ TagInfo(0x0016, "ImageBoundry", "Image boundry", nikon3IfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x0017, "0x0017", "Unknown", nikon3IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0018, "FlashBracketComp", "Flash bracket compensation
applied", nikon3IfdId, makerTags, undefined, print0x0012), // use 0x0012 print
fct
+ TagInfo(0x0019, "ExposureBracketComp", "AE bracket compensation
applied", nikon3IfdId, makerTags, signedRational, printValue),
+ TagInfo(0x0080, "ImageAdjustment", "Image adjustment setting",
nikon3IfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0081, "ToneComp", "Tone compensation setting (contrast)",
nikon3IfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0082, "AuxiliaryLens", "Auxiliary lens (adapter)",
nikon3IfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0083, "LensType", "Lens type", nikon3IfdId, makerTags,
unsignedByte, printValue),
+ TagInfo(0x0084, "Lens", "Lens", nikon3IfdId, makerTags,
unsignedRational, print0x0084),
+ TagInfo(0x0085, "FocusDistance", "Manual focus distance", nikon3IfdId,
makerTags, unsignedRational, printValue),
+ TagInfo(0x0086, "DigitalZoom", "Digital zoom setting", nikon3IfdId,
makerTags, unsignedRational, printValue),
+ TagInfo(0x0087, "FlashType", "Type of flash used", nikon3IfdId,
makerTags, unsignedByte, print0x0087),
+ TagInfo(0x0088, "AFFocusPos", "AF focus position", nikon3IfdId,
makerTags, undefined, print0x0088),
+ TagInfo(0x0089, "Bracketing", "Bracketing", nikon3IfdId, makerTags,
unsignedShort, print0x0089),
+ TagInfo(0x008a, "0x008a", "Unknown", nikon3IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x008b, "LensFStops", "Number of lens stops", nikon3IfdId,
makerTags, undefined, print0x008b),
+// TagInfo(0x008c, "NEFCurve1", "NEF curve 1", nikon3IfdId, makerTags,
xxx, printValue),
+ TagInfo(0x008d, "ColorMode", "Color mode", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x008f, "SceneMode", "Scene mode", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0090, "LightingType", "Lighting type", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0091, "0x0091", "Unknown", nikon3IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0092, "HueAdjustment", "Hue adjustment", nikon3IfdId,
makerTags, signedShort, printValue),
+ TagInfo(0x0094, "Saturation", "Saturation adjustment", nikon3IfdId,
makerTags, signedShort, printValue),
+ TagInfo(0x0095, "NoiseReduction", "Noise reduction", nikon3IfdId,
makerTags, asciiString, printValue),
+// TagInfo(0x0096, "NEFCurve2", "NEF curve 2", nikon3IfdId, makerTags,
xxx, printValue),
+ TagInfo(0x0097, "ColorBalance2", "Color balance 2", nikon3IfdId,
makerTags, undefined, printValue),
+ TagInfo(0x0098, "LensData", "Lens data", nikon3IfdId, makerTags,
undefined, print0x0098),
+ TagInfo(0x0099, "NEFThumbnailSize", "NEF thumbnail size", nikon3IfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x009a, "0x009a", "Unknown", nikon3IfdId, makerTags,
unsignedRational, printValue),
+ TagInfo(0x009b, "0x009b", "Unknown", nikon3IfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x009f, "0x009f", "Unknown", nikon3IfdId, makerTags,
signedShort, printValue),
+ TagInfo(0x00a0, "SerialNumber", "Camera serial number", nikon3IfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x00a2, "0x00a2", "Unknown", nikon3IfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x00a3, "0x00a3", "Unknown", nikon3IfdId, makerTags,
unsignedByte, printValue),
+ TagInfo(0x00a5, "0x00a5", "Unknown", nikon3IfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x00a6, "0x00a6", "Unknown", nikon3IfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x00a7, "ShutterCount", "Number of shots taken by camera",
nikon3IfdId, makerTags, unsignedLong, printValue),
+ TagInfo(0x00a8, "0x00a8", "Unknown", nikon3IfdId, makerTags,
undefined, printValue),
+ TagInfo(0x00a9, "ImageOptimization", "Image optimization",
nikon3IfdId, makerTags, asciiString, printValue),
+ TagInfo(0x00aa, "Saturation", "Saturation", nikon3IfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x00ab, "VariProgram", "Vari program", nikon3IfdId, makerTags,
asciiString, printValue),
+// TagInfo(0x0e00, "PrintIM", "Print image matching", nikon3IfdId,
makerTags, xxx, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownNikon3MnTag)", "Unknown Nikon3MakerNote tag",
nikon3IfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ Nikon3MakerNote::Nikon3MakerNote(bool alloc)
+ : IfdMakerNote(nikon3IfdId, alloc)
+ {
+ absOffset_ = false;
+ byte buf[] = {
+ 'N', 'i', 'k', 'o', 'n', '\0',
+ 0x02, 0x10, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x08
+ };
+ readHeader(buf, 18, byteOrder_);
+ }
+
+ Nikon3MakerNote::Nikon3MakerNote(const Nikon3MakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int Nikon3MakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 18) return 1;
+
+ header_.alloc(18);
+ memcpy(header_.pData_, buf, header_.size_);
+ TiffHeader tiffHeader;
+ tiffHeader.read(header_.pData_ + 10);
+ byteOrder_ = tiffHeader.byteOrder();
+ adjOffset_ = tiffHeader.offset();
+ return 0;
+ }
+
+ int Nikon3MakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the Nikon prefix
+ if ( header_.size_ < 18
+ || std::string(reinterpret_cast<char*>(header_.pData_), 6)
+ != std::string("Nikon\0", 6)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ Nikon3MakerNote::AutoPtr Nikon3MakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ Nikon3MakerNote* Nikon3MakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote(new Nikon3MakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ Nikon3MakerNote::AutoPtr Nikon3MakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ Nikon3MakerNote* Nikon3MakerNote::clone_() const
+ {
+ return new Nikon3MakerNote(*this);
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0002(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() > 1) {
+ os << value.toLong(1);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0012(std::ostream& os,
+ const Value& value)
+ {
+ // From the PHP JPEG Metadata Toolkit
+ long fec = value.toLong();
+ switch (fec) {
+ case 0x06: os << "+1.0 EV"; break;
+ case 0x04: os << "+0.7 EV"; break;
+ case 0x03: os << "+0.5 EV"; break;
+ case 0x02: os << "+0.3 EV"; break;
+ case 0x00: os << "0.0 EV"; break;
+ case 0xfe: os << "-0.3 EV"; break;
+ case 0xfd: os << "-0.5 EV"; break;
+ case 0xfc: os << "-0.7 EV"; break;
+ case 0xfa: os << "-1.0 EV"; break;
+ case 0xf8: os << "-1.3 EV"; break;
+ case 0xf7: os << "-1.5 EV"; break;
+ case 0xf6: os << "-1.7 EV"; break;
+ case 0xf4: os << "-2.0 EV"; break;
+ case 0xf2: os << "-2.3 EV"; break;
+ case 0xf1: os << "-2.5 EV"; break;
+ case 0xf0: os << "-2.7 EV"; break;
+ case 0xee: os << "-3.0 EV"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0084(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() == 4) {
+ long len1 = value.toLong(0);
+ long len2 = value.toLong(1);
+ Rational fno1 = value.toRational(2);
+ Rational fno2 = value.toRational(3);
+ os << len1;
+ if (len2 != len1) {
+ os << "-" << len2;
+ }
+ os << "mm "
+ << "F" << (float)fno1.first / fno1.second;
+ if (fno2 != fno1) {
+ os << "-" << (float)fno2.first / fno2.second;
+ }
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0087(std::ostream& os,
+ const Value& value)
+ {
+ // From Exiftool
+ long flash = value.toLong();
+ switch (flash) {
+ case 0: os << "Not used"; break;
+ case 8: os << "Fired, commander mode"; break;
+ case 9: os << "Fired, TTL mode"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0088(std::ostream& os,
+ const Value& value)
+ {
+ // Mappings taken from Exiftool
+ long afpos = value.toLong();
+ switch (afpos) {
+ case 0x0000: os << "Center"; break;
+ case 0x0100: os << "Top"; break;
+ case 0x0200: os << "Bottom"; break;
+ case 0x0300: os << "Left"; break;
+ case 0x0400: os << "Right"; break;
+
+ // D70
+ case 0x00001: os << "Single area, center"; break;
+ case 0x10002: os << "Single area, top"; break;
+ case 0x20004: os << "Single area, bottom"; break;
+ case 0x30008: os << "Single area, left"; break;
+ case 0x40010: os << "Single area, right"; break;
+
+ case 0x1000001: os << "Dynamic area, center"; break;
+ case 0x1010002: os << "Dynamic area, top"; break;
+ case 0x1020004: os << "Dynamic area, bottom"; break;
+ case 0x1030008: os << "Dynamic area, left"; break;
+ case 0x1040010: os << "Dynamic area, right"; break;
+
+ case 0x2000001: os << "Closest subject, center"; break;
+ case 0x2010002: os << "Closest subject, top"; break;
+ case 0x2020004: os << "Closest subject, bottom"; break;
+ case 0x2030008: os << "Closest subject, left"; break;
+ case 0x2040010: os << "Closest subject, right"; break;
+
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0089(std::ostream& os,
+ const Value& value)
+ {
+ // From Exiftool
+ long b = value.toLong();
+ switch (b) {
+ case 0x00: os << "Single"; break;
+ case 0x01: os << "Continuous"; break;
+ case 0x02: os << "Delay"; break;
+ case 0x03: os << "Remote with delay"; break;
+ case 0x04: os << "Remote"; break;
+ case 0x16: os << "Exposure bracketing"; break;
+ case 0x64: os << "White balance bracketing"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x008b(std::ostream& os,
+ const Value& value)
+ {
+ // Decoded by Robert Rottmerhusen <address@hidden>
+ if (value.size() != 4) return os << "(" << value << ")";
+ float a = value.toFloat(0);
+ long b = value.toLong(1);
+ long c = value.toLong(2);
+ if (c == 0) return os << "(" << value << ")";
+ return os << a * b / c;
+ }
+
+ std::ostream& Nikon3MakerNote::print0x0098(std::ostream& os,
+ const Value& value)
+ {
+#ifdef EXV_HAVE_LENSDATA
+ //# List of AF F-Mount lenses - version 1.12
+ //#-----------------------------------------
+ //# created by Robert Rottmerhusen 2005
+ //# for use in non-commercial, GPL or open source software only!
+ //# please contact me for adding lenses or use in commercial software.
+ //#
+ //#"data from TAG 0x98" "ltyp""manuf" "lens name from manuf";
+ //#
+ struct {unsigned char lid,stps,focs,focl,aps,apl,lfw, ltype; char
*manuf, *lensname;}
+ fmountlens[] = {
+ {0x01,0x58,0x50,0x50,0x14,0x14,0x02,0x00, "Nikon", "AF Nikkor 50mm
f/1.8"},
+ {0x02,0x42,0x44,0x5C,0x2A,0x34,0x08,0x00, "Nikon", "AF Zoom-Nikkor
35-70mm f/3.3-4.5"},
+ {0x04,0x48,0x3C,0x3C,0x24,0x24,0x03,0x00, "Nikon", "AF Nikkor 28mm
f/2.8"},
+ {0x05,0x54,0x50,0x50,0x0C,0x0C,0x04,0x00, "Nikon", "AF Nikkor 50mm
f/1.4"},
+ {0x07,0x40,0x3C,0x62,0x2C,0x34,0x03,0x00, "Nikon", "AF Zoom-Nikkor
28-85mm f/3.5-4.5"},
+ {0x08,0x40,0x44,0x6A,0x2C,0x34,0x04,0x00, "Nikon", "AF Zoom-Nikkor
35-105mm f/3.5-4.5"},
+ {0x09,0x48,0x37,0x37,0x24,0x24,0x04,0x00, "Nikon", "AF Nikkor 24mm
f/2.8"},
+ {0x0A,0x48,0x8E,0x8E,0x24,0x24,0x03,0x00, "Nikon", "AF Nikkor
300mm f/2.8 IF-ED"},
+ {0x0B,0x48,0x7C,0x7C,0x24,0x24,0x05,0x00, "Nikon", "AF Nikkor
180mm f/2.8 IF-ED"},
+ {0x0E,0x48,0x5C,0x81,0x30,0x30,0x05,0x00, "Nikon", "AF Zoom-Nikkor
70-210mm f/4"},
+ {0x0F,0x58,0x50,0x50,0x14,0x14,0x05,0x00, "Nikon", "AF Nikkor 50mm
f/1.8 N"},
+ {0x10,0x48,0x8E,0x8E,0x30,0x30,0x08,0x00, "Nikon", "AF Nikkor
300mm f/4 IF-ED"},
+ {0x12,0x48,0x5C,0x81,0x30,0x3C,0x09,0x00, "Nikon", "AF Nikkor
70-210mm f/4-5.6"},
+ {0x13,0x42,0x37,0x50,0x2A,0x34,0x0B,0x00, "Nikon", "AF Zoom-Nikkor
24-50mm f/3.3-4.5"},
+ {0x14,0x48,0x60,0x80,0x24,0x24,0x0B,0x00, "Nikon", "AF Zoom-Nikkor
80-200mm f/2.8 ED"},
+ {0x15,0x4C,0x62,0x62,0x14,0x14,0x0C,0x00, "Nikon", "AF Nikkor 85mm
f/1.8"},
+ {0x1B,0x44,0x5E,0x8E,0x34,0x3C,0x10,0x00, "Nikon", "AF Zoom-Nikkor
75-300mm f/4.5-5.6"},
+ {0x1C,0x48,0x30,0x30,0x24,0x24,0x12,0x00, "Nikon", "AF Nikkor 20mm
f/2.8"},
+ {0x1D,0x42,0x44,0x5C,0x2A,0x34,0x12,0x00, "Nikon", "AF Zoom-Nikkor
35-70mm f/3.3-4.5 N"},
+ {0x1E,0x54,0x56,0x56,0x24,0x24,0x13,0x00, "Nikon", "AF
Micro-Nikkor 60mm f/2.8"},
+ {0x25,0x48,0x44,0x5c,0x24,0x24,0x1B,0x02, "Nikon", "AF Zoom-Nikkor
35-70mm f/2.8D"},
+ {0x25,0x48,0x44,0x5c,0x24,0x24,0x52,0x02, "Nikon", "AF Zoom-Nikkor
35-70mm f/2.8D N"},
+ {0x27,0x48,0x8E,0x8E,0x24,0x24,0xF2,0x02, "Nikon", "AF-I Nikkor
300mm f/2.8D IF-ED"},
+ {0x2A,0x54,0x3C,0x3C,0x0C,0x0C,0x26,0x02, "Nikon", "AF Nikkor 28mm
f/1.4D"},
+ {0x2C,0x48,0x6A,0x6A,0x18,0x18,0x27,0x02, "Nikon", "AF DC-Nikkor
105mm f/2D"},
+ {0x2D,0x48,0x80,0x80,0x30,0x30,0x21,0x02, "Nikon", "AF
Micro-Nikkor 200mm f/4D IF-ED"},
+ {0x31,0x54,0x56,0x56,0x24,0x24,0x25,0x02, "Nikon", "AF
Micro-Nikkor 60mm f/2.8D"},
+ {0x32,0x54,0x6A,0x6A,0x24,0x24,0x35,0x02, "Nikon", "AF
Micro-Nikkor 105mm f/2.8D"},
+ {0x33,0x48,0x2D,0x2D,0x24,0x24,0x31,0x02, "Nikon", "AF Nikkor 18mm
f/2.8D"},
+ {0x36,0x48,0x37,0x37,0x24,0x24,0x34,0x02, "Nikon", "AF Nikkor 24mm
f/2.8D"},
+ {0x37,0x48,0x30,0x30,0x24,0x24,0x36,0x02, "Nikon", "AF Nikkor 20mm
f/2.8D"},
+ {0x38,0x4C,0x62,0x62,0x14,0x14,0x37,0x02, "Nikon", "AF Nikkor 85mm
f/1.8D"},
+ {0x3B,0x48,0x44,0x5C,0x24,0x24,0x3A,0x02, "Nikon", "AF Zoom-Nikkor
35-70mm f/2.8D N"},
+ {0x3E,0x48,0x3C,0x3C,0x24,0x24,0x3D,0x02, "Nikon", "AF Nikkor 28mm
f/2.8D"},
+ {0x41,0x48,0x7c,0x7c,0x24,0x24,0x43,0x02, "Nikon", "AF Nikkor
180mm f/2.8D IF-ED"},
+ {0x42,0x54,0x44,0x44,0x18,0x18,0x44,0x02, "Nikon", "AF Nikkor 35mm
f/2D"},
+ {0x43,0x54,0x50,0x50,0x0C,0x0C,0x46,0x02, "Nikon", "AF Nikkor 50mm
f/1.4D"},
+ {0x46,0x3C,0x44,0x60,0x30,0x3C,0x49,0x02, "Nikon", "AF Zoom-Nikkor
35-80mm f/4-5.6D"},
+ {0x48,0x48,0x8E,0x8E,0x24,0x24,0x4B,0x02, "Nikon", "AF-S Nikkor
300mm f/2.8D IF-ED"},
+ {0x4A,0x54,0x62,0x62,0x0C,0x0C,0x4D,0x02, "Nikon", "AF Nikkor 85mm
f/1.4D IF"},
+ {0x4C,0x40,0x37,0x6E,0x2C,0x3C,0x4F,0x02, "Nikon", "AF Zoom-Nikkor
24-120mm f/3.5-5.6D IF"},
+ {0x4D,0x40,0x3C,0x80,0x2C,0x3C,0x62,0x02, "Nikon", "AF Zoom-Nikkor
28-200mm f/3.5-5.6D IF"},
+ {0x4E,0x48,0x72,0x72,0x18,0x18,0x51,0x02, "Nikon", "AF DC-Nikkor
135mm f/2D"},
+ {0x53,0x48,0x60,0x80,0x24,0x24,0x60,0x02, "Nikon", "AF Zoom-Nikkor
80-200mm f/2.8D ED"},
+ {0x54,0x44,0x5C,0x7C,0x34,0x3C,0x58,0x02, "Nikon", "AF Zoom-Micro
Nikkor 70-180mm f/4.5-5.6D ED"},
+ {0x56,0x48,0x5C,0x8E,0x30,0x3C,0x5A,0x02, "Nikon", "AF Zoom-Nikkor
70-300mm f/4-5.6D ED"},
+ {0x59,0x48,0x98,0x98,0x24,0x24,0x5D,0x02, "Nikon", "AF-S Nikkor
400mm f/2.8D IF-ED"},
+ {0x5A,0x3C,0x3E,0x56,0x30,0x3C,0x5E,0x06, "Nikon", "IX-Nikkor
30-60mm f/4-5.6"},
+ {0x5D,0x48,0x3C,0x5C,0x24,0x24,0x63,0x02, "Nikon", "AF-S
Zoom-Nikkor 28-70mm f/2.8D IF-ED"},
+ {0x5E,0x48,0x60,0x80,0x24,0x24,0x64,0x02, "Nikon", "AF-S
Zoom-Nikkor 80-200mm f/2.8D IF-ED"},
+ {0x5F,0x40,0x3C,0x6A,0x2C,0x34,0x65,0x02, "Nikon", "AF Zoom-Nikkor
28-105mm f/3.5-4.5D IF"},
+ {0x63,0x48,0x2B,0x44,0x24,0x24,0x68,0x02, "Nikon", "AF-S Nikkor
17-35mm f/2.8D IF-ED"},
+ {0x64,0x00,0x62,0x62,0x24,0x24,0x6A,0x02, "Nikon", "PC
Micro-Nikkor 85mm f/2.8D"},
+ {0x65,0x44,0x60,0x98,0x34,0x3C,0x6B,0x0A, "Nikon", "AF VR
Zoom-Nikkor 80-400mm f/4.5-5.6D ED"},
+ {0x66,0x40,0x2D,0x44,0x2C,0x34,0x6C,0x02, "Nikon", "AF Zoom-Nikkor
18-35mm f/3.5-4.5D IF-ED"},
+ {0x67,0x48,0x37,0x62,0x24,0x30,0x6D,0x02, "Nikon", "AF Zoom-Nikkor
24-85mm f/2.8-4D IF"},
+ {0x68,0x42,0x3C,0x60,0x2A,0x3C,0x6E,0x06, "Nikon", "AF Zoom-Nikkor
28-80mm f/3.3-5.6G"},
+ {0x69,0x48,0x5C,0x8E,0x30,0x3C,0x6F,0x06, "Nikon", "AF Zoom-Nikkor
70-300mm f/4-5.6G"},
+ {0x6A,0x48,0x8E,0x8E,0x30,0x30,0x70,0x02, "Nikon", "AF-S Nikkor
300mm f/4D IF-ED"},
+ {0x6D,0x48,0x8E,0x8E,0x24,0x24,0x73,0x02, "Nikon", "AF-S Nikkor
300mm f/2.8D IF-ED II"},
+ {0x6E,0x48,0x98,0x98,0x24,0x24,0x74,0x02, "Nikon", "AF-S Nikkor
400mm f/2.8D IF-ED II"},
+ {0x70,0x3C,0xA6,0xA6,0x30,0x30,0x76,0x02, "Nikon", "AF-S Nikkor
600mm f/4D IF-ED"},
+ {0x72,0x48,0x4C,0x4C,0x24,0x24,0x77,0x00, "Nikon", "Nikkor 45mm
f/2.8 P"},
+ {0x74,0x40,0x37,0x62,0x2C,0x34,0x78,0x06, "Nikon", "AF-S
Zoom-Nikkor 24-85mm f/3.5-4.5G IF-ED"},
+ {0x75,0x40,0x3C,0x68,0x2C,0x3C,0x79,0x06, "Nikon", "AF Zoom-Nikkor
28-100mm f/3.5-5.6G"},
+ {0x76,0x58,0x50,0x50,0x14,0x14,0x7A,0x02, "Nikon", "AF Nikkor 50mm
f/1.8D"},
+ {0x77,0x48,0x5C,0x80,0x24,0x24,0x7B,0x0E, "Nikon", "AF-S VR
Zoom-Nikkor 70-200mm f/2.8G IF-ED"},
+ {0x78,0x40,0x37,0x6E,0x2C,0x3C,0x7C,0x0E, "Nikon", "AF-S VR
Zoom-Nikkor 24-120mm f/3.5-5.6G IF-ED"},
+ {0x79,0x40,0x3C,0x80,0x2C,0x3C,0x7F,0x06, "Nikon", "AF Zoom-Nikkor
28-200mm f/3.5-5.6G IF-ED"},
+ {0x7A,0x3C,0x1F,0x37,0x30,0x30,0x7E,0x06, "Nikon", "AF-S DX
Zoom-Nikkor 12-24mm f/4G IF-ED"},
+ {0x7B,0x48,0x80,0x98,0x30,0x30,0x80,0x0E, "Nikon", "AF-S VR
Zoom-Nikkor 200-400mm f/4G IF-ED"},
+ {0x7D,0x48,0x2B,0x53,0x24,0x24,0x82,0x06, "Nikon", "AF-S DX
Zoom-Nikkor 17-55mm f/2.8G IF-ED"},
+ {0x7F,0x40,0x2D,0x5C,0x2C,0x34,0x84,0x06, "Nikon", "AF-S DX
Zoom-Nikkor 18-70mm f/3.5-4.5G IF-ED"},
+ {0x80,0x48,0x1A,0x1A,0x24,0x24,0x85,0x06, "Nikon", "AF DX
Fisheye-Nikkor 10.5mm f/2.8G ED"},
+ {0x81,0x54,0x80,0x80,0x18,0x18,0x86,0x0E, "Nikon", "AF-S VR Nikkor
200mm f/2G IF-ED"},
+ {0x82,0x48,0x8E,0x8E,0x24,0x24,0x87,0x0E, "Nikon", "AF-S VR Nikkor
300mm f/2.8G IF-ED"},
+ {0x89,0x3C,0x53,0x80,0x30,0x3C,0x8B,0x06, "Nikon", "AF-S DX
Zoom-Nikkor 55-200mm f/4-5.6G ED"},
+ {0x8C,0x40,0x2D,0x53,0x2C,0x3C,0x8E,0x06, "Nikon", "AF-S DX
Zoom-Nikkor 18-55mm f/3.5-5.6G ED"},
+ {0x06,0x3F,0x68,0x68,0x2C,0x2C,0x06,0x00, "Cosina", "100mm F/3.5
Macro"},
+ {0x02,0x3F,0x24,0x24,0x2C,0x2C,0x02,0x00, "Sigma", "14mm F3.5"},
+ {0x02,0x46,0x37,0x37,0x25,0x25,0x02,0x00, "Sigma", "24mm F2.8
Macro"},
+ {0x02,0x3F,0x3C,0x5C,0x2D,0x35,0x02,0x00, "Sigma", "28-70mm
F3.5-4.5 UC"},
+ {0x02,0x40,0x44,0x73,0x2B,0x36,0x02,0x00, "Sigma", "35-135mm
F3.5-4.5 a"},
+ {0x02,0x37,0x5E,0x8E,0x35,0x3D,0x02,0x00, "Sigma", "75-300mm
F4.5-5.6 APO"},
+ {0x02,0x48,0x65,0x65,0x24,0x24,0x02,0x00, "Sigma", "90mm F2.8
Macro"},
+ {0x02,0x2F,0x98,0x98,0x3D,0x3D,0x02,0x00, "Sigma", "400mm F5.6
APO"},
+ {0x26,0x40,0x3C,0x8E,0x2C,0x40,0x1C,0x02, "Sigma", "28-300mm
F3.5-6.3 Macro D"},
+ {0x26,0x40,0x3C,0x80,0x2B,0x3C,0x1C,0x02, "Sigma", "28-200mm
F3.5-5.6 Compact Aspherical Hyperzoom Macro D"},
+ {0x26,0x40,0x3C,0x60,0x2C,0x3C,0x1C,0x02, "Sigma", "28-80mm
F3.5-5.6 Mini Zoom Macro II Aspherical D"},
+ {0x26,0x54,0x37,0x5C,0x24,0x24,0x1C,0x02, "Sigma", "24-70mm F2.8
EX DG Macro D"},
+ {0x26,0x40,0x2D,0x70,0x2B,0x3C,0x1C,0x06, "Sigma", "18-125mm
F3.5-5.6 DC G"},
+ {0x26,0x48,0x2D,0x50,0x24,0x24,0x1C,0x06, "Sigma", "18-50mm F2.8
EX DC G"},
+ {0x26,0x40,0x2D,0x50,0x2C,0x3C,0x1C,0x06, "Sigma", "18-50mm
F3.5-5.6 DC G"},
+ {0x48,0x38,0x1F,0x37,0x34,0x3C,0x4B,0x06, "Sigma", "12-24mm
F4.5-5.6 EX Aspherical DG HSM G"},
+ {0x48,0x48,0x2B,0x44,0x24,0x30,0x4B,0x06, "Sigma", "17-35mm F2.8-4
EX DG Aspherical HSM G"},
+ {0x48,0x3C,0x50,0xA0,0x30,0x40,0x4B,0x02, "Sigma", "50-500mmF4-6.3
EX APO RF HSM D"},
+ {0x48,0x54,0x5C,0x80,0x24,0x24,0x4B,0x02, "Sigma", "70-200mm F2.8
EX APO IF HSM D"},
+ {0x48,0x48,0x68,0x8E,0x30,0x30,0x4B,0x02, "Sigma", "100-300mm F4
EX IF HSM D"},
+ {0x48,0x48,0x76,0x76,0x24,0x24,0x4B,0x06, "Sigma", "150mm F2.8 EX
DG APO Macro HSM G"},
+ {0x77,0x44,0x61,0x98,0x34,0x3C,0x7B,0x0E, "Sigma", "80-400mm
f4.5-5.6 EX OS G"},
+ {0x03,0x43,0x5C,0x81,0x35,0x35,0x02,0x00, "Soligor", "AF C/D ZOOM
UMCS 70-210mm 1:4.5"},
+ {0x00,0x3C,0x1F,0x37,0x30,0x30,0x00,0x06, "Tokina", "AT-X 124 AF
PRO DX - AF 12-24mm f/4"},
+ {0x00,0x40,0x2B,0x2B,0x2C,0x2C,0x00,0x02, "Tokina", "AT-X 17 AF
PRO - AF 17mm f/3.5"},
+ {0x00,0x54,0x68,0x68,0x24,0x24,0x00,0x02, "Tokina", "AT-X M100 PRO
D - 100mm F2.8"},
+ {0x4D,0x41,0x3C,0x8E,0x2B,0x40,0x62,0x02, "Tamron", "AF28-300mm
F/3.5-6.3 XR Di LD Aspherical (IF)"},
+ {0x00,0x3F,0x2D,0x80,0x2B,0x40,0x00,0x06, "Tamron", "AF18-200mm
F/3.5-6.3 XR Di II LD Aspherical (IF)"},
+ {0x32,0x53,0x64,0x64,0x24,0x24,0x35,0x02, "Tamron", "SP AF90mm
F/2.8 Di 1:1 Macro"},
+ {0x00,0x48,0x3C,0x6A,0x24,0x24,0x00,0x02, "Unknown", "28-105mm
F/2.8D"},
+ {0x00,0x49,0x30,0x48,0x22,0x2B,0x00,0x02, "Unknown", "20-40mm
F/2.7-3.3D"},
+ {0x07,0x46,0x2B,0x44,0x24,0x30,0x03,0x02, "Unknown", "AF17-35mm
D"},
+ {0x1E,0x5D,0x64,0x64,0x20,0x20,0x13,0x00, "Unknown", "90mm F/2.5"},
+ {0x20,0x3C,0x80,0x98,0x3D,0x3D,0x1E,0x02, "Unknown", "200-400mm
F/5.6D"},
+ {0x2F,0x40,0x30,0x44,0x2C,0x34,0x29,0x02, "Unknown", "20-35mm
F/3.5-4.5D"},
+ {0,0,0,0,0,0,0,0, NULL, NULL}
+ };
+
+ if (value.typeId() != undefined) return os << value;
+
+ DataBuf lens(value.size());
+ // ByteOrder is only to satisfy the interface
+ value.copy(lens.pData_, invalidByteOrder);
+
+ int idx = 0;
+ if (0 == memcmp(lens.pData_, "0100", 4)) {
+ idx = 6;
+ }
+ else if (0 == memcmp(lens.pData_, "0101", 4)) {
+ idx = 11;
+ }
+ else if (0 == memcmp(lens.pData_, "0201", 4)) {
+ // Here we should decrypt(lens.pData_ + 4, lens.size_ - 4);
+ // however, the decrypt algorithm requires access to serial number
+ // and shutter count tags but print functions are static...
+ idx = 11;
+ }
+ if (idx == 0 || lens.size_ < idx + 7) {
+ // Unknown version or not enough data
+ return os << value;
+ }
+ for (int i = 0; fmountlens[i].lensname != NULL; ++i) {
+ if ( lens.pData_[idx] == fmountlens[i].lid
+ && lens.pData_[idx+1] == fmountlens[i].stps
+ && lens.pData_[idx+2] == fmountlens[i].focs
+ && lens.pData_[idx+3] == fmountlens[i].focl
+ && lens.pData_[idx+4] == fmountlens[i].aps
+ && lens.pData_[idx+5] == fmountlens[i].apl
+ && lens.pData_[idx+6] == fmountlens[i].lfw) {
+ // Lens found in database
+ return os << fmountlens[i].manuf << " " <<
fmountlens[i].lensname;
+ }
+ }
+ // Lens not found in database
+ return os << value;
+#else
+ return os << value;
+#endif // EXV_HAVE_LENSDATA
+ }
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createNikonMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ // If there is no "Nikon" string it must be Nikon1 format
+ if (len < 6 || std::string(reinterpret_cast<const char*>(buf), 6)
+ != std::string("Nikon\0", 6)) {
+ return MakerNote::AutoPtr(new Nikon1MakerNote(alloc));
+ }
+ // If the "Nikon" string is not followed by a TIFF header, we assume
+ // Nikon2 format
+ TiffHeader tiffHeader;
+ if ( len < 18
+ || tiffHeader.read(buf + 10) != 0 || tiffHeader.tag() != 0x002a) {
+ return MakerNote::AutoPtr(new Nikon2MakerNote(alloc));
+ }
+ // Else we have a Nikon3 makernote
+ return MakerNote::AutoPtr(new Nikon3MakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/nikonmn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/nikonmn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/nikonmn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,309 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file nikonmn.hpp
+ @brief Nikon MakerNote formats.
+
+ The Nikon MakerNote formats are implemented according to the following
references<BR>
+ Format 1:
+ <ul>
+ <li><a href="http://www.tawbaware.com/990exif.htm">MakerNote EXIF Tag of the
Nikon 990</a> by Max Lyons</li></ul>
+ Format 2:
+ <ul><li>"Appendix 2: Makernote of Nikon" of the document
+ <a href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html">
+ Exif file format</a> by TsuruZoh Tachibanaya</li></ul>
+ Format 3:
+ <ul><li>"EXIFutils Field Reference Guide"</li>
+ <li><a
href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html#Nikon_Type_3_Tags">Nikon
Type 3 Makernote Tags Definition</a>
+ of the PHP JPEG Metadata Toolkit by Evan Hunter</li>
+ <li>Nikon tag information from <a
href="http://www.sno.phy.queensu.ca/~phil/exiftool/">ExifTool</a> by Phil
Harvey</li>
+ <li>Email communication with Robert Rottmerhusen</li>
+ </ul>
+
+ @version $Rev: 588 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 17-May-04, ahu: created<BR>
+ 25-May-04, ahu: combined all Nikon formats in one component
+ */
+#ifndef NIKONMN_HPP_
+#define NIKONMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createNikonMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! A MakerNote format used by Nikon cameras, such as the E990 and D1.
+ class Nikon1MakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %Nikon1MakerNote auto pointer.
+ typedef std::auto_ptr<Nikon1MakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ Nikon1MakerNote(bool alloc =true);
+ //! Copy constructor
+ Nikon1MakerNote(const Nikon1MakerNote& rhs);
+ //! Virtual destructor
+ virtual ~Nikon1MakerNote() {}
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Nikon1 %MakerNote tags
+ //@{
+ //! Print ISO setting
+ static std::ostream& print0x0002(std::ostream& os, const Value& value);
+ //! Print autofocus mode
+ static std::ostream& print0x0007(std::ostream& os, const Value& value);
+ //! Print manual focus distance
+ static std::ostream& print0x0085(std::ostream& os, const Value& value);
+ //! Print digital zoom setting
+ static std::ostream& print0x0086(std::ostream& os, const Value& value);
+ //! Print AF focus position
+ static std::ostream& print0x0088(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ Nikon1MakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ Nikon1MakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class Nikon1MakerNote
+
+ static Nikon1MakerNote::RegisterMn registerNikon1MakerNote;
+
+ /*!
+ @brief A second MakerNote format used by Nikon cameras, including the
+ E700, E800, E900, E900S, E910, E950
+ */
+ class Nikon2MakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %Nikon2MakerNote auto pointer.
+ typedef std::auto_ptr<Nikon2MakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ Nikon2MakerNote(bool alloc =true);
+ //! Copy constructor
+ Nikon2MakerNote(const Nikon2MakerNote& rhs);
+ //! Virtual destructor
+ virtual ~Nikon2MakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Nikon2 %MakerNote tags
+ //@{
+ //! Print quality setting
+ static std::ostream& print0x0003(std::ostream& os, const Value& value);
+ //! Print color mode setting
+ static std::ostream& print0x0004(std::ostream& os, const Value& value);
+ //! Print image adjustment setting
+ static std::ostream& print0x0005(std::ostream& os, const Value& value);
+ //! Print ISO speed setting
+ static std::ostream& print0x0006(std::ostream& os, const Value& value);
+ //! Print white balance setting
+ static std::ostream& print0x0007(std::ostream& os, const Value& value);
+ //! Print digital zoom setting
+ static std::ostream& print0x000a(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ Nikon2MakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ Nikon2MakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class Nikon2MakerNote
+
+ static Nikon2MakerNote::RegisterMn registerNikon2MakerNote;
+
+ //! A third MakerNote format used by Nikon cameras, e.g., E5400, SQ, D2H,
D70
+ class Nikon3MakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %Nikon3MakerNote auto pointer.
+ typedef std::auto_ptr<Nikon3MakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ Nikon3MakerNote(bool alloc =true);
+ //! Copy constructor
+ Nikon3MakerNote(const Nikon3MakerNote& rhs);
+ //! Virtual destructor
+ virtual ~Nikon3MakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Nikon3 %MakerNote tags
+ //@{
+ //! Print ISO setting
+ static std::ostream& print0x0002(std::ostream& os, const Value& value);
+ //! Print flash compensation
+ static std::ostream& print0x0012(std::ostream& os, const Value& value);
+ //! Print lens information
+ static std::ostream& print0x0084(std::ostream& os, const Value& value);
+ //! Print flash used information
+ static std::ostream& print0x0087(std::ostream& os, const Value& value);
+ //! Print AF point
+ static std::ostream& print0x0088(std::ostream& os, const Value& value);
+ //! Print bracketing information
+ static std::ostream& print0x0089(std::ostream& os, const Value& value);
+ //! Print number of lens stops
+ static std::ostream& print0x008b(std::ostream& os, const Value& value);
+ //! Print number of lens data
+ static std::ostream& print0x0098(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ Nikon3MakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ Nikon3MakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class Nikon3MakerNote
+
+ static Nikon3MakerNote::RegisterMn registerNikon3MakerNote;
+
+} // namespace Exiv2
+
+#endif // #ifndef NIKONMN_HPP_
Added: Extractor/src/plugins/exiv2/olympusmn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/olympusmn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/olympusmn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,318 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: olympusmn.cpp
+ Version: $Rev: 581 $
+ Author(s): Will Stokes (wuz) <address@hidden>
+ Andreas Huggel (ahu) <address@hidden>
+ History: 10-Mar-05, wuz: created
+ Credits: See header file.
+ */
+
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: olympusmn.cpp 581 2005-06-12 05:54:57Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "olympusmn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ OlympusMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote(
+ "OLYMPUS*", "*", createOlympusMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ olympusIfdId, MakerNote::AutoPtr(new OlympusMakerNote));
+
+ ExifTags::registerMakerTagInfo(olympusIfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Olympus Tag Info
+ const TagInfo OlympusMakerNote::tagInfo_[] = {
+ TagInfo(0x0200, "SpecialMode", "Picture taking mode", olympusIfdId,
makerTags, unsignedLong, print0x0200),
+ TagInfo(0x0201, "Quality", "Image quality setting", olympusIfdId,
makerTags, unsignedShort, print0x0201),
+ TagInfo(0x0202, "Macro", "Macro mode", olympusIfdId, makerTags,
unsignedShort, print0x0202),
+ TagInfo(0x0203, "BWMode", "Black and White Mode", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x0204, "DigitalZoom", "Digital zoom ratio", olympusIfdId,
makerTags, unsignedRational, print0x0204),
+ TagInfo(0x0205, "FocalPlaneDiagonal", "Focal plane diagonal",
olympusIfdId, makerTags, unsignedRational, printValue),
+ TagInfo(0x0206, "0x0206", "Unknown", olympusIfdId, makerTags,
signedShort, printValue),
+ TagInfo(0x0207, "FirmwareVersion", "Software firmware version",
olympusIfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0208, "PictureInfo", "ASCII format data such as
[PictureInfo]", olympusIfdId, makerTags, asciiString, printValue),
+ TagInfo(0x0209, "CameraID", "CameraID data", olympusIfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0300, "PreCaptureFrames", "Pre-capture frames",
olympusIfdId, makerTags, unsignedShort, printValue),
+ TagInfo(0x0301, "0x0301", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0302, "OneTouchWB", "OneTouchWB", olympusIfdId, makerTags,
unsignedShort, print0x0302),
+ TagInfo(0x0303, "0x0303", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0304, "0x0304", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0f00, "DataDump", "Various camera settings", olympusIfdId,
makerTags, undefined, printValue),
+ TagInfo(0x1000, "0x1000", "Unknown", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1001, "0x1001", "Unknown", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1002, "0x1002", "Unknown", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1003, "0x1003", "Unknown", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1004, "FlashMode", "Flash mode", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1005, "FlashDevice", "Flash device", olympusIfdId,
makerTags, unsignedShort, print0x1005),
+ TagInfo(0x1006, "Bracket", "Bracket", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1007, "0x1007", "Unknown", olympusIfdId, makerTags,
signedShort, printValue),
+ TagInfo(0x1008, "0x1008", "Unknown", olympusIfdId, makerTags,
signedShort, printValue),
+ TagInfo(0x1009, "0x1009", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x100a, "0x100a", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x100b, "FocusMode", "Focus mode", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x100c, "FocusDistance", "Focus distance", olympusIfdId,
makerTags, unsignedRational, printValue),
+ TagInfo(0x100d, "Zoom", "Zoom", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x100e, "MacroFocus", "Macro focus", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x100f, "SharpnessFactor", "Sharpness factor", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x1010, "0x1010", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1011, "ColorMatrix", "Color matrix", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x1012, "BlackLevel", "Black level", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1013, "0x1013", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1014, "0x1014", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1015, "WhiteBalance", "White balance", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x1016, "0x1016", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1017, "RedBalance", "Red balance", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1018, "BlueBalance", "Blue balance", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x1019, "0x1019", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x101a, "SerialNumber", "Serial number", olympusIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x101b, "0x101b", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x101c, "0x101c", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x101d, "0x101d", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x101e, "0x101e", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x101f, "0x101f", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x1020, "0x1020", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x1021, "0x1021", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x1022, "0x1022", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x1023, "FlashBias", "Flash bias", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1024, "0x1024", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1025, "0x1025", "Unknown", olympusIfdId, makerTags,
signedRational, printValue),
+ TagInfo(0x1026, "0x1026", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1027, "0x1027", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1028, "0x1028", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1029, "Contrast", "Contrast setting", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x102a, "SharpnessFactor", "Sharpness factor", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x102b, "ColorControl", "Color control", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x102c, "ValidBits", "Valid bits", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x102d, "Coring Filter", "Coring filter", olympusIfdId,
makerTags, unsignedShort, printValue),
+ TagInfo(0x102e, "ImageWidth", "Image width", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x102f, "ImageHeight", "Image height", olympusIfdId,
makerTags, unsignedLong, printValue),
+ TagInfo(0x1030, "0x1030", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1031, "0x1031", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x1032, "0x1032", "Unknown", olympusIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x1033, "0x1033", "Unknown", olympusIfdId, makerTags,
unsignedLong, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownOlympusMakerNoteTag)", "Unknown
OlympusMakerNote tag", olympusIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ OlympusMakerNote::OlympusMakerNote(bool alloc)
+ : IfdMakerNote(olympusIfdId, alloc)
+ {
+ byte buf[] = {
+ 'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00
+ };
+ readHeader(buf, 8, byteOrder_);
+ }
+
+ OlympusMakerNote::OlympusMakerNote(const OlympusMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int OlympusMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 8) return 1;
+
+ // Copy the header
+ header_.alloc(8);
+ memcpy(header_.pData_, buf, header_.size_);
+ // Adjust the offset of the IFD for the prefix
+ adjOffset_ = 8;
+
+ return 0;
+ }
+
+ int OlympusMakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the OLYMPUS prefix
+ if ( header_.size_ < 8
+ || std::string(reinterpret_cast<char*>(header_.pData_), 5)
+ != std::string("OLYMP", 5)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ OlympusMakerNote::AutoPtr OlympusMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ OlympusMakerNote* OlympusMakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote = AutoPtr(new OlympusMakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ OlympusMakerNote::AutoPtr OlympusMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ OlympusMakerNote* OlympusMakerNote::clone_() const
+ {
+ return new OlympusMakerNote(*this);
+ }
+
+ std::ostream& OlympusMakerNote::print0x0200(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() != 3 || value.typeId() != unsignedLong) {
+ return os << value;
+ }
+ long l0 = value.toLong(0);
+ switch (l0) {
+ case 0: os << "Normal"; break;
+ case 2: os << "Fast"; break;
+ case 3: os << "Panorama"; break;
+ default: os << "(" << l0 << ")"; break;
+ }
+ if (l0 != 0) {
+ os << ", ";
+ long l1 = value.toLong(1);
+ os << "Sequence number " << l1;
+ }
+ if (l0 != 0 && l0 != 2) {
+ os << ", ";
+ long l2 = value.toLong(2);
+ switch (l2) {
+ case 1: os << "Left to Right"; break;
+ case 2: os << "Right to Left"; break;
+ case 3: os << "Bottom to Top"; break;
+ case 4: os << "Top to Bottom"; break;
+ default: os << "(" << l2 << ")"; break;
+ }
+ }
+ return os;
+ } // OlympusMakerNote::print0x0200
+
+ //! Quality
+ const TagDetails quality[] = {
+ { 0, "(start)" },
+ { 1, "Standard Quality (SQ)" },
+ { 2, "High Quality (HQ)" },
+ { 3, "Super High Quality (SHQ)" },
+ { 6, "Raw" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& OlympusMakerNote::print0x0201(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(quality).print(os, value);
+ } // OlympusMakerNote::print0x0201
+
+ //! Macro
+ const TagDetails macro[] = {
+ { -1, "(start)" },
+ { 0, "Off" },
+ { 1, "On" },
+ { 2, "Super Macro" },
+ { -1, "(end)" }
+ };
+
+ std::ostream& OlympusMakerNote::print0x0202(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(macro).print(os, value);
+ } // OlympusMakerNote::print0x0202
+
+ std::ostream& OlympusMakerNote::print0x0204(std::ostream& os,
+ const Value& value)
+ {
+ float f = value.toFloat();
+ if (f == 0.0 || f == 1.0) return os << "None";
+ return os << std::fixed << std::setprecision(1) << f << "x";
+ } // OlympusMakerNote::print0x0204
+
+ //! OneTouchWB
+ const TagDetails oneTouchWb[] = {
+ { -1, "(start)" },
+ { 0, "Off" },
+ { 1, "On" },
+ { 2, "On (Preset)" },
+ { -1, "(end)" }
+ };
+
+ std::ostream& OlympusMakerNote::print0x0302(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(oneTouchWb).print(os, value);
+ } // OlympusMakerNote::print0x0302
+
+ //! FlashDevice
+ const TagDetails flashDevice[] = {
+ { -1, "(start)" },
+ { 0, "None" },
+ { 1, "Internal" },
+ { 4, "External" },
+ { 4, "Internal + External" },
+ { -1, "(end)" }
+ };
+
+ std::ostream& OlympusMakerNote::print0x1005(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(flashDevice).print(os, value);
+ } // OlympusMakerNote::print0x1005
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createOlympusMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new OlympusMakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/olympusmn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/olympusmn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/olympusmn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,161 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file olympusmn.hpp
+ @brief Olympus MakerNote implemented using the following references:
+ <a
href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html#APP1">Exif
file format, Appendix 1: MakerNote of Olympus Digicams</a> by TsuruZoh
Tachibanaya,
+ Olympus.pm of <a
href="http://www.sno.phy.queensu.ca/~phil/exiftool/">ExifTool</a> by Phil
Harvey,
+ <a
href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/olympus_mn.html">Olympus
Makernote Format Specification</a> by Evan Hunter,
+ email communication with <a href="mailto:address@hidden">Will
Stokes</a>
+ @version $Rev: 580 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @author Will Stokes (wuz)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 10-Mar-05, wuz: created
+ */
+#ifndef OLYMPUSMN_HPP_
+#define OLYMPUSMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createOlympusMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Olympus cameras
+ class OlympusMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %OlympusMakerNote auto pointer.
+ typedef std::auto_ptr<OlympusMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ OlympusMakerNote(bool alloc =true);
+ //! Copy constructor
+ OlympusMakerNote(const OlympusMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~OlympusMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Olympus %MakerNote tags
+ //@{
+ //! Print 'Special Mode'
+ static std::ostream& print0x0200(std::ostream& os, const Value& value);
+ //! Print Jpeg quality
+ static std::ostream& print0x0201(std::ostream& os, const Value& value);
+ //! Print Macro mode
+ static std::ostream& print0x0202(std::ostream& os, const Value& value);
+ //! Print Digital Zoom Factor
+ static std::ostream& print0x0204(std::ostream& os, const Value& value);
+ //! Print OneTouchWB
+ static std::ostream& print0x0302(std::ostream& os, const Value& value);
+ //! Print FlashDevice
+ static std::ostream& print0x1005(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ OlympusMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ OlympusMakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class OlympusMakerNote
+
+ static OlympusMakerNote::RegisterMn registerOlympusMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef OLYMPUSMN_HPP_
Added: Extractor/src/plugins/exiv2/panasonicmn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/panasonicmn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/panasonicmn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,361 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: panasonicmn.cpp
+ Version: $Rev: 581 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 11-Jun-04, ahu: created
+ Credits: See header file
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: panasonicmn.cpp 581 2005-06-12 05:54:57Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "panasonicmn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ PanasonicMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("Panasonic", "*",
createPanasonicMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ panasonicIfdId, MakerNote::AutoPtr(new PanasonicMakerNote));
+
+ ExifTags::registerMakerTagInfo(panasonicIfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Panasonic MakerNote Tag Info
+ const TagInfo PanasonicMakerNote::tagInfo_[] = {
+ TagInfo(0x0001, "Quality", "Image Quality", panasonicIfdId, makerTags,
unsignedShort, print0x0001),
+ TagInfo(0x0002, "FirmwareVersion", "Firmware version", panasonicIfdId,
makerTags, undefined, printValue),
+ TagInfo(0x0003, "WhiteBalance", "White balance setting",
panasonicIfdId, makerTags, unsignedShort, print0x0003),
+ TagInfo(0x0004, "0x0004", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0007, "FocusMode", "Focus mode", panasonicIfdId, makerTags,
unsignedShort, print0x0007),
+ TagInfo(0x000f, "SpotMode", "Spot mode", panasonicIfdId, makerTags,
unsignedByte, print0x000f),
+ TagInfo(0x001a, "ImageStabilizer", "Image stabilizer", panasonicIfdId,
makerTags, unsignedShort, print0x001a),
+ TagInfo(0x001c, "Macro", "Macro mode", panasonicIfdId, makerTags,
unsignedShort, print0x001c),
+ TagInfo(0x001f, "ShootingMode", "Shooting mode", panasonicIfdId,
makerTags, unsignedShort, print0x001f),
+ TagInfo(0x0020, "Audio", "Audio", panasonicIfdId, makerTags,
unsignedShort, print0x0020),
+ TagInfo(0x0021, "DataDump", "Data dump", panasonicIfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0022, "0x0022", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0023, "WhiteBalanceBias", "White balance adjustment",
panasonicIfdId, makerTags, unsignedShort, print0x0023),
+ TagInfo(0x0024, "FlashBias", "Flash bias", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0025, "SerialNumber", "Serial number", panasonicIfdId,
makerTags, undefined, printValue),
+ TagInfo(0x0026, "0x0026", "Unknown", panasonicIfdId, makerTags,
undefined, printValue),
+ TagInfo(0x0027, "0x0027", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0028, "ColorEffect", "Color effect", panasonicIfdId,
makerTags, unsignedShort, print0x0028),
+ TagInfo(0x0029, "0x0029", "Unknown", panasonicIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x002a, "0x002a", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x002b, "0x002b", "Unknown", panasonicIfdId, makerTags,
unsignedLong, printValue),
+ TagInfo(0x002c, "Contrast", "Contrast setting", panasonicIfdId,
makerTags, unsignedShort, print0x002c),
+ TagInfo(0x002d, "NoiseReduction", "Noise reduction", panasonicIfdId,
makerTags, unsignedShort, print0x002d),
+ TagInfo(0x002e, "0x002e", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x002f, "0x002f", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0030, "0x0030", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0031, "0x0031", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x0032, "0x0032", "Unknown", panasonicIfdId, makerTags,
unsignedShort, printValue),
+ TagInfo(0x4449, "0x4449", "Unknown", panasonicIfdId, makerTags,
undefined, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownPanasonicMakerNoteTag)", "Unknown
PanasonicMakerNote tag", panasonicIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ PanasonicMakerNote::PanasonicMakerNote(bool alloc)
+ : IfdMakerNote(panasonicIfdId, alloc, false)
+ {
+ byte buf[] = {
+ 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00
+ };
+ readHeader(buf, 12, byteOrder_);
+ }
+
+ PanasonicMakerNote::PanasonicMakerNote(const PanasonicMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int PanasonicMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 12) return 1;
+
+ header_.alloc(12);
+ memcpy(header_.pData_, buf, header_.size_);
+ // Adjust the offset of the IFD for the prefix
+ adjOffset_ = 12;
+ return 0;
+ }
+
+ int PanasonicMakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the Panasonic prefix
+ if ( header_.size_ < 12
+ || std::string(reinterpret_cast<char*>(header_.pData_), 9)
+ != std::string("Panasonic", 9)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ PanasonicMakerNote::AutoPtr PanasonicMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ PanasonicMakerNote* PanasonicMakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote = AutoPtr(new PanasonicMakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ PanasonicMakerNote::AutoPtr PanasonicMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ PanasonicMakerNote* PanasonicMakerNote::clone_() const
+ {
+ return new PanasonicMakerNote(*this);
+ }
+
+ //! Quality
+ const TagDetails quality[] = {
+ { 0, "(start)" },
+ { 2, "High" },
+ { 3, "Standard" },
+ { 6, "Very High" },
+ { 7, "Raw" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x0001(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(quality).print(os, value);
+ } // PanasonicMakerNote::print0x0001
+
+ //! WhiteBalance
+ const TagDetails whiteBalance[] = {
+ { 0, "(start)" },
+ { 1, "Auto" },
+ { 2, "Daylight" },
+ { 3, "Cloudy" },
+ { 4, "Halogen" },
+ { 5, "Manual" },
+ { 8, "Flash" },
+ { 10, "Black and White" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x0003(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(whiteBalance).print(os, value);
+ } // PanasonicMakerNote::print0x0003
+
+ //! FocusMode
+ const TagDetails focusMode[] = {
+ { 0, "(start)" },
+ { 1, "Auto" },
+ { 2, "Manual" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x0007(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(focusMode).print(os, value);
+ } // PanasonicMakerNote::print0x0007
+
+ std::ostream& PanasonicMakerNote::print0x000f(std::ostream& os,
+ const Value& value)
+ {
+ if (value.count() < 2 || value.typeId() != unsignedByte) {
+ return os << value;
+ }
+ long l0 = value.toLong(0);
+ if (l0 == 1) os << "On";
+ else if (l0 == 16) os << "Off";
+ else os << value;
+ return os;
+ } // PanasonicMakerNote::print0x000f
+
+ //! ImageStabilizer
+ const TagDetails imageStabilizer[] = {
+ { 0, "(start)" },
+ { 2, "On, Mode 1" },
+ { 3, "Off" },
+ { 4, "On, Mode 2" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x001a(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(imageStabilizer).print(os, value);
+ } // PanasonicMakerNote::print0x001a
+
+ //! Macro
+ const TagDetails macro[] = {
+ { 0, "(start)" },
+ { 1, "On" },
+ { 2, "Off" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x001c(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(macro).print(os, value);
+ } // PanasonicMakerNote::print0x001c
+
+ //! ShootingMode
+ const TagDetails shootingMode[] = {
+ { 0, "(start)" },
+ { 1, "Normal" },
+ { 2, "Portrait" },
+ { 3, "Scenery" },
+ { 4, "Sports" },
+ { 5, "Night Portrait" },
+ { 6, "Program" },
+ { 7, "Aperture Priority" },
+ { 8, "Shutter Priority" },
+ { 9, "Macro" },
+ { 11, "Manual" },
+ { 13, "Panning" },
+ { 18, "Fireworks" },
+ { 19, "Party" },
+ { 20, "Snow" },
+ { 21, "Night Scenery" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x001f(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(shootingMode).print(os, value);
+ } // PanasonicMakerNote::print0x001f
+
+ //! Audio
+ const TagDetails Audio[] = {
+ { 0, "(start)" },
+ { 1, "Yes" },
+ { 2, "No" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x0020(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(Audio).print(os, value);
+ } // PanasonicMakerNote::print0x0020
+
+ std::ostream& PanasonicMakerNote::print0x0023(std::ostream& os,
+ const Value& value)
+ {
+ return os << std::fixed << std::setprecision(1)
+ << value.toLong() / 3 << " EV";
+ } // PanasonicMakerNote::print0x0023
+
+ //! ColorEffect
+ const TagDetails colorEffect[] = {
+ { 0, "(start)" },
+ { 1, "Off" },
+ { 2, "Warm" },
+ { 3, "Cool" },
+ { 4, "Black and White" },
+ { 5, "Sepia" },
+ { 0, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x0028(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(colorEffect).print(os, value);
+ } // PanasonicMakerNote::print0x0028
+
+ //! Contrast
+ const TagDetails contrast[] = {
+ { -1, "(start)" },
+ { 0, "Standard" },
+ { 1, "Low" },
+ { 2, "High" },
+ { 0x100, "Low" },
+ { 0x110, "Standard" },
+ { 0x120, "High" },
+ { -1, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x002c(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(contrast).print(os, value);
+ } // PanasonicMakerNote::print0x002c
+
+ //! NoiseReduction
+ const TagDetails noiseReduction[] = {
+ { -1, "(start)" },
+ { 0, "Standard" },
+ { 1, "Low" },
+ { 2, "High" },
+ { -1, "(end)" }
+ };
+
+ std::ostream& PanasonicMakerNote::print0x002d(std::ostream& os,
+ const Value& value)
+ {
+ return TagTranslator(noiseReduction).print(os, value);
+ } // PanasonicMakerNote::print0x002d
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createPanasonicMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new PanasonicMakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/panasonicmn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/panasonicmn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/panasonicmn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,170 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file panasonicmn.hpp
+ @brief Panasonic MakerNote implemented using the following references:
+ <a href="http://www.compton.nu/panasonic.html">Panasonic MakerNote
Information</a> by Tom Hughes,
+ Panasonic.pm of <a
href="http://www.sno.phy.queensu.ca/~phil/exiftool/">ExifTool</a> by Phil
Harvey,
+ <a
href="http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html">Panasonic
Makernote Format Specification</a> by Evan Hunter.
+ @version $Rev: 581 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 11-Jun-05, ahu: created
+ */
+#ifndef PANASONICMN_HPP_
+#define PANASONICMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createPanasonicMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Panasonic cameras
+ class PanasonicMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %PanasonicMakerNote auto pointer.
+ typedef std::auto_ptr<PanasonicMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ PanasonicMakerNote(bool alloc =true);
+ //! Copy constructor
+ PanasonicMakerNote(const PanasonicMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~PanasonicMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Panasonic %MakerNote tags
+ //@{
+ //! Print Quality
+ static std::ostream& print0x0001(std::ostream& os, const Value& value);
+ //! Print WhiteBalance
+ static std::ostream& print0x0003(std::ostream& os, const Value& value);
+ //! Print FocusMode
+ static std::ostream& print0x0007(std::ostream& os, const Value& value);
+ //! Print SpotMode
+ static std::ostream& print0x000f(std::ostream& os, const Value& value);
+ //! Print ImageStabilizer
+ static std::ostream& print0x001a(std::ostream& os, const Value& value);
+ //! Print Macro
+ static std::ostream& print0x001c(std::ostream& os, const Value& value);
+ //! Print ShootingMode
+ static std::ostream& print0x001f(std::ostream& os, const Value& value);
+ //! Print Audio
+ static std::ostream& print0x0020(std::ostream& os, const Value& value);
+ //! Print WhiteBalanceBias
+ static std::ostream& print0x0023(std::ostream& os, const Value& value);
+ //! Print ColorEffect
+ static std::ostream& print0x0028(std::ostream& os, const Value& value);
+ //! Print Contrast
+ static std::ostream& print0x002c(std::ostream& os, const Value& value);
+ //! Print NoiseReduction
+ static std::ostream& print0x002d(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ PanasonicMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ PanasonicMakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class PanasonicMakerNote
+
+ static PanasonicMakerNote::RegisterMn registerPanasonicMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef PANASONICMN_HPP_
Added: Extractor/src/plugins/exiv2/rcsid.hpp
===================================================================
--- Extractor/src/plugins/exiv2/rcsid.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/rcsid.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,62 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file rcsid.hpp
+ @brief Define an RCS id string in every object file compiled from a source
+ file that includes rcsid.hpp.
+
+ This is a simplified version of the ACE_RCSID macro that is used in the
+ <a href="http://www.cs.wustl.edu/~schmidt/ACE.html">ACE(TM)</a> distribution.
+
+ @version $Rev: 538 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 02-Feb-04, ahu: created
+ */
+#ifndef RCSID_HPP_
+#define RCSID_HPP_
+
+#if !defined (EXIV2_RCSID)
+/*!
+ @brief Macro to store version information in each object file.
+
+ Use this macro by including the following two lines at the beginning
of
+ each *.cpp file. See the ident(1) manual pages for more information.
+
+ @code
+ #include "rcsid.hpp"
+ EXIV2_RCSID("@(#) $Id$");
+ @endcode
+
+ The macro hack itself has the following purposes:
+ -# To define the RCS id string variable in the local namespace, so
+ that there won't be any duplicate extern symbols at link time.
+ -# To avoid warnings of the type "variable declared and never used".
+
+ */
+#define EXIV2_RCSID(id) \
+ namespace { \
+ inline const char* getRcsId(const char*) { return id ; } \
+ const char* rcsId = getRcsId(rcsId); \
+ }
+
+#endif // #if !defined (EXIV2_RCSID)
+#endif // #ifndef RCSID_HPP_
Added: Extractor/src/plugins/exiv2/sigmamn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/sigmamn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/sigmamn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,211 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: sigmamn.cpp
+ Version: $Rev: 569 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 02-Apr-04, ahu: created
+ Credits: Sigma and Foveon MakerNote implemented according to the
specification
+ in "SIGMA and FOVEON EXIF MakerNote Documentation" by Foveon.
+ <http://www.x3f.info/technotes/FileDocs/MakerNoteDoc.html>
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: sigmamn.cpp 569 2005-05-28 05:48:43Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "sigmamn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ SigmaMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("SIGMA", "*",
createSigmaMakerNote);
+ MakerNoteFactory::registerMakerNote("FOVEON", "*",
createSigmaMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ sigmaIfdId, MakerNote::AutoPtr(new SigmaMakerNote));
+
+ ExifTags::registerMakerTagInfo(sigmaIfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Sigma (Foveon) MakerNote Tag Info
+ const TagInfo SigmaMakerNote::tagInfo_[] = {
+ TagInfo(0x0002, "SerialNumber", "Camera serial number", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0003, "DriveMode", "Drive Mode", sigmaIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0004, "ResolutionMode", "Resolution Mode", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0005, "AutofocusMode", "Autofocus mode", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0006, "FocusSetting", "Focus setting", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0007, "WhiteBalance", "White balance", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0008, "ExposureMode", "Exposure mode", sigmaIfdId,
makerTags, asciiString, print0x0008),
+ TagInfo(0x0009, "MeteringMode", "Metering mode", sigmaIfdId,
makerTags, asciiString, print0x0009),
+ TagInfo(0x000a, "LensRange", "Lens focal length range", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x000b, "ColorSpace", "Color space", sigmaIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x000c, "Exposure", "Exposure", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x000d, "Contrast", "Contrast", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x000e, "Shadow", "Shadow", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x000f, "Highlight", "Highlight", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x0010, "Saturation", "Saturation", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x0011, "Sharpness", "Sharpness", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x0012, "FillLight", "X3 Fill light", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x0014, "ColorAdjustment", "Color adjustment", sigmaIfdId,
makerTags, asciiString, printStripLabel),
+ TagInfo(0x0015, "AdjustmentMode", "Adjustment mode", sigmaIfdId,
makerTags, asciiString, printValue),
+ TagInfo(0x0016, "Quality", "Quality", sigmaIfdId, makerTags,
asciiString, printStripLabel),
+ TagInfo(0x0017, "Firmware", "Firmware", sigmaIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0018, "Software", "Software", sigmaIfdId, makerTags,
asciiString, printValue),
+ TagInfo(0x0019, "AutoBracket", "Auto bracket", sigmaIfdId, makerTags,
asciiString, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownSigmaMakerNoteTag)", "Unknown SigmaMakerNote
tag", sigmaIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ SigmaMakerNote::SigmaMakerNote(bool alloc)
+ : IfdMakerNote(sigmaIfdId, alloc)
+ {
+ byte buf[] = {
+ 'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00
+ };
+ readHeader(buf, 10, byteOrder_);
+ }
+
+ SigmaMakerNote::SigmaMakerNote(const SigmaMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int SigmaMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 10) return 1;
+
+ // Copy the header. My one and only Sigma sample has two undocumented
+ // extra bytes (0x01, 0x00) between the ID string and the start of the
+ // Makernote IFD. So we copy 10 bytes into the header.
+ header_.alloc(10);
+ memcpy(header_.pData_, buf, header_.size_);
+ // Adjust the offset of the IFD for the prefix
+ adjOffset_ = 10;
+ return 0;
+ }
+
+ int SigmaMakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the SIGMA or FOVEON prefix
+ if ( header_.size_ < 10
+ || std::string(reinterpret_cast<char*>(header_.pData_), 8)
+ != std::string("SIGMA\0\0\0", 8)
+ && std::string(reinterpret_cast<char*>(header_.pData_), 8)
+ != std::string("FOVEON\0\0", 8)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ SigmaMakerNote::AutoPtr SigmaMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ SigmaMakerNote* SigmaMakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote = AutoPtr(new SigmaMakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ SigmaMakerNote::AutoPtr SigmaMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ SigmaMakerNote* SigmaMakerNote::clone_() const
+ {
+ return new SigmaMakerNote(*this);
+ }
+
+ std::ostream& SigmaMakerNote::printStripLabel(std::ostream& os,
+ const Value& value)
+ {
+ std::string v = value.toString();
+ std::string::size_type pos = v.find(':');
+ if (pos != std::string::npos) {
+ if (v[pos + 1] == ' ') ++pos;
+ v = v.substr(pos + 1);
+ }
+ return os << v;
+ }
+
+ std::ostream& SigmaMakerNote::print0x0008(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toString()[0]) {
+ case 'P': os << "Program"; break;
+ case 'A': os << "Aperture priority"; break;
+ case 'S': os << "Shutter priority"; break;
+ case 'M': os << "Manual"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& SigmaMakerNote::print0x0009(std::ostream& os,
+ const Value& value)
+ {
+ switch (value.toString()[0]) {
+ case 'A': os << "Average"; break;
+ case 'C': os << "Center"; break;
+ case '8': os << "8-Segment"; break;
+ default: os << "(" << value << ")"; break;
+ }
+ return os;
+ }
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createSigmaMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new SigmaMakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/sigmamn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/sigmamn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/sigmamn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,151 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file sigmamn.hpp
+ @brief Sigma and Foveon MakerNote implemented according to the
specification
+ <a href="http://www.x3f.info/technotes/FileDocs/MakerNoteDoc.html">
+ SIGMA and FOVEON EXIF MakerNote Documentation</a> by Foveon.
+ @version $Rev: 569 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 02-Apr-04, ahu: created
+ */
+#ifndef SIGMAMN_HPP_
+#define SIGMAMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createSigmaMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Sigma (Foveon) cameras
+ class SigmaMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %SigmaMakerNote auto pointer.
+ typedef std::auto_ptr<SigmaMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ SigmaMakerNote(bool alloc =true);
+ //! Copy constructor
+ SigmaMakerNote(const SigmaMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~SigmaMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @name Print functions for Sigma (Foveon) %MakerNote tags
+ //@{
+ //! Strip the label from the value and print the remainder
+ static std::ostream& printStripLabel(std::ostream& os, const Value&
value);
+ //! Print exposure mode
+ static std::ostream& print0x0008(std::ostream& os, const Value& value);
+ //! Print metering mode
+ static std::ostream& print0x0009(std::ostream& os, const Value& value);
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ SigmaMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ SigmaMakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class SigmaMakerNote
+
+ static SigmaMakerNote::RegisterMn registerSigmaMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef SIGMAMN_HPP_
Added: Extractor/src/plugins/exiv2/sonymn.cpp
===================================================================
--- Extractor/src/plugins/exiv2/sonymn.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/sonymn.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,150 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: sonymn.cpp
+ Version: $Rev: 569 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 18-Apr-05, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: sonymn.cpp 569 2005-05-28 05:48:43Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "sonymn.hpp"
+#include "makernote.hpp"
+#include "value.hpp"
+
+// + standard includes
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+
+// Define DEBUG_MAKERNOTE to output debug information to std::cerr
+#undef DEBUG_MAKERNOTE
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ //! @cond IGNORE
+ SonyMakerNote::RegisterMn::RegisterMn()
+ {
+ MakerNoteFactory::registerMakerNote("SONY", "*", createSonyMakerNote);
+ MakerNoteFactory::registerMakerNote(
+ sonyIfdId, MakerNote::AutoPtr(new SonyMakerNote));
+
+ ExifTags::registerMakerTagInfo(sonyIfdId, tagInfo_);
+ }
+ //! @endcond
+
+ // Sony MakerNote Tag Info
+ const TagInfo SonyMakerNote::tagInfo_[] = {
+ TagInfo(0x2000, "0x2000", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9001, "0x9001", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9002, "0x9002", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9003, "0x9003", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9004, "0x9004", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9005, "0x9005", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9006, "0x9006", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9007, "0x9007", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ TagInfo(0x9008, "0x9008", "Unknown", sonyIfdId, makerTags, undefined,
printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownSonyMakerNoteTag)", "Unknown SonyMakerNote
tag", sonyIfdId, makerTags, invalidTypeId, printValue)
+ };
+
+ SonyMakerNote::SonyMakerNote(bool alloc)
+ : IfdMakerNote(sonyIfdId, alloc, false)
+ {
+ byte buf[] = {
+ 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0'
+ };
+ readHeader(buf, 12, byteOrder_);
+ }
+
+ SonyMakerNote::SonyMakerNote(const SonyMakerNote& rhs)
+ : IfdMakerNote(rhs)
+ {
+ }
+
+ int SonyMakerNote::readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder)
+ {
+ if (len < 12) return 1;
+ header_.alloc(12);
+ memcpy(header_.pData_, buf, header_.size_);
+ // Adjust the offset of the IFD for the prefix
+ adjOffset_ = 12;
+ return 0;
+ }
+
+ int SonyMakerNote::checkHeader() const
+ {
+ int rc = 0;
+ // Check the SONY prefix
+ if ( header_.size_ < 12
+ || std::string(reinterpret_cast<char*>(header_.pData_), 12)
+ != std::string("SONY DSC \0\0\0", 12)) {
+ rc = 2;
+ }
+ return rc;
+ }
+
+ SonyMakerNote::AutoPtr SonyMakerNote::create(bool alloc) const
+ {
+ return AutoPtr(create_(alloc));
+ }
+
+ SonyMakerNote* SonyMakerNote::create_(bool alloc) const
+ {
+ AutoPtr makerNote = AutoPtr(new SonyMakerNote(alloc));
+ assert(makerNote.get() != 0);
+ makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
+ return makerNote.release();
+ }
+
+ SonyMakerNote::AutoPtr SonyMakerNote::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ SonyMakerNote* SonyMakerNote::clone_() const
+ {
+ return new SonyMakerNote(*this);
+ }
+
+//
*****************************************************************************
+// free functions
+
+ MakerNote::AutoPtr createSonyMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset)
+ {
+ return MakerNote::AutoPtr(new SonyMakerNote(alloc));
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/sonymn.hpp
===================================================================
--- Extractor/src/plugins/exiv2/sonymn.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/sonymn.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,139 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file sonymn.hpp
+ @brief Basic Sony MakerNote implementation
+ @version $Rev: 569 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 18-Apr-05, ahu: created
+ */
+#ifndef SONYMN_HPP_
+#define SONYMN_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+#include "makernote.hpp"
+#include "tags.hpp"
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return an auto-pointer to a newly created empty MakerNote
+ initialized to operate in the memory management model indicated.
+ The caller owns this copy and the auto-pointer ensures that it
+ will be deleted.
+
+ @param alloc Memory management model for the new MakerNote. Determines if
+ memory required to store data should be allocated and deallocated
+ (true) or not (false). If false, only pointers to the buffer
+ provided to read() will be kept. See Ifd for more background on
+ this concept.
+ @param buf Pointer to the makernote character buffer (not used).
+ @param len Length of the makernote character buffer (not used).
+ @param byteOrder Byte order in which the Exif data (and possibly the
+ makernote) is encoded (not used).
+ @param offset Offset from the start of the TIFF header of the makernote
+ buffer (not used).
+
+ @return An auto-pointer to a newly created empty MakerNote. The caller
+ owns this copy and the auto-pointer ensures that it will be
+ deleted.
+ */
+ MakerNote::AutoPtr createSonyMakerNote(bool alloc,
+ const byte* buf,
+ long len,
+ ByteOrder byteOrder,
+ long offset);
+
+//
*****************************************************************************
+// class definitions
+
+ //! MakerNote for Sony cameras
+ class SonyMakerNote : public IfdMakerNote {
+ public:
+ //! Shortcut for a %SonyMakerNote auto pointer.
+ typedef std::auto_ptr<SonyMakerNote> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor. Allows to choose whether or not memory management
+ is required for the makernote entries.
+ */
+ SonyMakerNote(bool alloc =true);
+ //! Copy constructor
+ SonyMakerNote(const SonyMakerNote& rhs);
+ //! Virtual destructor
+ virtual ~SonyMakerNote() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ int readHeader(const byte* buf,
+ long len,
+ ByteOrder byteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ int checkHeader() const;
+ AutoPtr create(bool alloc =true) const;
+ AutoPtr clone() const;
+ //@}
+
+ //! @cond IGNORE
+ // Public only so that we can create a static instance
+ struct RegisterMn {
+ RegisterMn();
+ };
+ //! @endcond
+
+ private:
+ //! Internal virtual create function.
+ SonyMakerNote* create_(bool alloc =true) const;
+ //! Internal virtual copy constructor.
+ SonyMakerNote* clone_() const;
+
+ //! Tag information
+ static const TagInfo tagInfo_[];
+
+ }; // class SonyMakerNote
+
+ static SonyMakerNote::RegisterMn registerSonyMakerNote;
+} // namespace Exiv2
+
+#endif // #ifndef SONYMN_HPP_
Added: Extractor/src/plugins/exiv2/taglist.cpp
===================================================================
--- Extractor/src/plugins/exiv2/taglist.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/taglist.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,69 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ Abstract: Print a simple comma separated list of tags defined in Exiv2
+
+ File: taglist.cpp
+ Version: $Rev: 570 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 07-Jan-04, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: taglist.cpp 570 2005-05-28 15:35:08Z ahuggel $");
+
+#include "makernote.hpp"
+#include "tags.hpp"
+#include "datasets.hpp"
+#include "error.hpp"
+
+#include <string>
+#include <iostream>
+
+using namespace Exiv2;
+
+int main(int argc, char* argv[])
+try {
+ int rc = 0;
+
+ switch (argc) {
+ case 2:
+ {
+ std::string item(argv[1]);
+
+ if (item == "Exif") {
+ ExifTags::taglist(std::cout);
+ break;
+ }
+
+ if (item == "Iptc") {
+ IptcDataSets::dataSetList(std::cout);
+ break;
+ }
+
+ IfdId ifdId = ExifTags::ifdIdByIfdItem(item);
+ if (ExifTags::isMakerIfd(ifdId)) {
+ ExifTags::makerTaglist(std::cout, ifdId);
+ }
+ else {
+ rc = 2;
+ }
+ break;
+ }
+ case 1:
+ ExifTags::taglist(std::cout);
+ break;
+ default:
+ rc = 1;
+ break;
+ }
+ if (rc) {
+ std::cout << "Usage: " << argv[0]
+ << "
[Exif|Canon|CanonCs1|CanonCs2|CanonCf|Fujifilm|Nikon1|Nikon2|Nikon3|Olympus|Sigma|Sony|Iptc]\n"
+ << "Print Exif tags, MakerNote tags, or Iptc datasets\n";
+ }
+ return rc;
+}
+catch (AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return 1;
+}
Added: Extractor/src/plugins/exiv2/tags.cpp
===================================================================
--- Extractor/src/plugins/exiv2/tags.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/tags.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,1230 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: tags.cpp
+ Version: $Rev: 581 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 15-Jan-04, ahu: created
+ 21-Jan-05, ahu: added MakerNote TagInfo registry and related code
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: tags.cpp 581 2005-06-12 05:54:57Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "tags.hpp"
+#include "error.hpp"
+#include "types.hpp"
+#include "ifd.hpp"
+#include "value.hpp"
+#include "makernote.hpp"
+#include "mn.hpp" // To ensure that all makernotes are
registered
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <utility>
+#include <cstdlib>
+#include <cassert>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ IfdInfo::IfdInfo(IfdId ifdId, const char* name, const char* item)
+ : ifdId_(ifdId), name_(name), item_(item)
+ {
+ }
+
+ // Todo: Allow to register new IfdInfo entries from elsewhere (the
makernotes)
+ // Important: IFD item must be unique!
+ const IfdInfo ExifTags::ifdInfo_[] = {
+ IfdInfo(ifdIdNotSet, "(Unknown IFD)", "(Unknown item)"),
+ IfdInfo(ifd0Id, "IFD0", "Image"),
+ IfdInfo(exifIfdId, "Exif", "Photo"), // just to avoid 'Exif.Exif.*'
keys
+ IfdInfo(gpsIfdId, "GPSInfo", "GPSInfo"),
+ IfdInfo(iopIfdId, "Iop", "Iop"),
+ IfdInfo(ifd1Id, "IFD1", "Thumbnail"),
+ IfdInfo(canonIfdId, "Makernote", "Canon"),
+ IfdInfo(canonCs1IfdId, "Makernote", "CanonCs1"),
+ IfdInfo(canonCs2IfdId, "Makernote", "CanonCs2"),
+ IfdInfo(canonCfIfdId, "Makernote", "CanonCf"),
+ IfdInfo(fujiIfdId, "Makernote", "Fujifilm"),
+ IfdInfo(nikon1IfdId, "Makernote", "Nikon1"),
+ IfdInfo(nikon2IfdId, "Makernote", "Nikon2"),
+ IfdInfo(nikon3IfdId, "Makernote", "Nikon3"),
+ IfdInfo(olympusIfdId, "Makernote", "Olympus"),
+ IfdInfo(panasonicIfdId, "Makernote", "Panasonic"),
+ IfdInfo(sigmaIfdId, "Makernote", "Sigma"),
+ IfdInfo(sonyIfdId, "Makernote", "Sony"),
+ IfdInfo(lastIfdId, "(Last IFD info)", "(Last IFD item)")
+ };
+
+ SectionInfo::SectionInfo(
+ SectionId sectionId,
+ const char* name,
+ const char* desc
+ )
+ : sectionId_(sectionId), name_(name), desc_(desc)
+ {
+ }
+
+ const SectionInfo ExifTags::sectionInfo_[] = {
+ SectionInfo(sectionIdNotSet, "(UnknownSection)", "Unknown section"),
+ SectionInfo(imgStruct, "ImageStructure", "Image data structure"),
+ SectionInfo(recOffset, "RecordingOffset", "Recording offset"),
+ SectionInfo(imgCharacter, "ImageCharacteristics", "Image data
characteristics"),
+ SectionInfo(otherTags, "OtherTags", "Other data"),
+ SectionInfo(exifFormat, "ExifFormat", "Exif data structure"),
+ SectionInfo(exifVersion, "ExifVersion", "Exif Version"),
+ SectionInfo(imgConfig, "ImageConfig", "Image configuration"),
+ SectionInfo(userInfo, "UserInfo", "User information"),
+ SectionInfo(relatedFile, "RelatedFile", "Related file"),
+ SectionInfo(dateTime, "DateTime", "Date and time"),
+ SectionInfo(captureCond, "CaptureConditions", "Picture taking
conditions"),
+ SectionInfo(gpsTags, "GPS", "GPS information"),
+ SectionInfo(iopTags, "Interoperability", "Interoperability
information"),
+ SectionInfo(makerTags, "Makernote", "Vendor specific information"),
+ SectionInfo(lastSectionId, "(LastSection)", "Last section")
+ };
+
+ TagInfo::TagInfo(
+ uint16_t tag,
+ const char* name,
+ const char* desc,
+ IfdId ifdId,
+ SectionId sectionId,
+ TypeId typeId,
+ PrintFct printFct
+ )
+ : tag_(tag), name_(name), desc_(desc), ifdId_(ifdId),
+ sectionId_(sectionId), typeId_(typeId), printFct_(printFct)
+ {
+ }
+
+ // Base IFD Tags (IFD0 and IFD1)
+ static const TagInfo ifdTagInfo[] = {
+ TagInfo(0x0100, "ImageWidth", "Image width", ifd0Id, imgStruct,
unsignedLong, printValue),
+ TagInfo(0x0101, "ImageLength", "Image height", ifd0Id, imgStruct,
unsignedLong, printValue),
+ TagInfo(0x0102, "BitsPerSample", "Number of bits per component",
ifd0Id, imgStruct, unsignedShort, printValue),
+ TagInfo(0x0103, "Compression", "Compression scheme", ifd0Id,
imgStruct, unsignedShort, print0x0103),
+ TagInfo(0x0106, "PhotometricInterpretation", "Pixel composition",
ifd0Id, imgStruct, unsignedShort, print0x0106),
+ TagInfo(0x010e, "ImageDescription", "Image title", ifd0Id, otherTags,
asciiString, printValue),
+ TagInfo(0x010f, "Make", "Manufacturer of image input equipment",
ifd0Id, otherTags, asciiString, printValue),
+ TagInfo(0x0110, "Model", "Model of image input equipment", ifd0Id,
otherTags, asciiString, printValue),
+ TagInfo(0x0111, "StripOffsets", "Image data location", ifd0Id,
recOffset, unsignedLong, printValue),
+ TagInfo(0x0112, "Orientation", "Orientation of image", ifd0Id,
imgStruct, unsignedShort, print0x0112),
+ TagInfo(0x0115, "SamplesPerPixel", "Number of components", ifd0Id,
imgStruct, unsignedShort, printValue),
+ TagInfo(0x0116, "RowsPerStrip", "Number of rows per strip", ifd0Id,
recOffset, unsignedLong, printValue),
+ TagInfo(0x0117, "StripByteCounts", "Bytes per compressed strip",
ifd0Id, recOffset, unsignedLong, printValue),
+ TagInfo(0x011a, "XResolution", "Image resolution in width direction",
ifd0Id, imgStruct, unsignedRational, printLong),
+ TagInfo(0x011b, "YResolution", "Image resolution in height direction",
ifd0Id, imgStruct, unsignedRational, printLong),
+ TagInfo(0x011c, "PlanarConfiguration", "Image data arrangement",
ifd0Id, imgStruct, unsignedShort, printValue),
+ TagInfo(0x0128, "ResolutionUnit", "Unit of X and Y resolution",
ifd0Id, imgStruct, unsignedShort, printUnit),
+ TagInfo(0x012d, "TransferFunction", "Transfer function", ifd0Id,
imgCharacter, unsignedShort, printValue),
+ TagInfo(0x0131, "Software", "Software used", ifd0Id, otherTags,
asciiString, printValue),
+ TagInfo(0x0132, "DateTime", "File change date and time", ifd0Id,
otherTags, asciiString, printValue),
+ TagInfo(0x013b, "Artist", "Person who created the image", ifd0Id,
otherTags, asciiString, printValue),
+ TagInfo(0x013e, "WhitePoint", "White point chromaticity", ifd0Id,
imgCharacter, unsignedRational, printValue),
+ TagInfo(0x013f, "PrimaryChromaticities", "Chromaticities of
primaries", ifd0Id, imgCharacter, unsignedRational, printValue),
+ TagInfo(0x0201, "JPEGInterchangeFormat", "Offset to JPEG SOI", ifd0Id,
recOffset, unsignedLong, printValue),
+ TagInfo(0x0202, "JPEGInterchangeFormatLength", "Bytes of JPEG data",
ifd0Id, recOffset, unsignedLong, printValue),
+ TagInfo(0x0211, "YCbCrCoefficients", "Color space transformation
matrix coefficients", ifd0Id, imgCharacter, unsignedRational, printValue),
+ TagInfo(0x0212, "YCbCrSubSampling", "Subsampling ratio of Y to C",
ifd0Id, imgStruct, unsignedShort, printValue),
+ TagInfo(0x0213, "YCbCrPositioning", "Y and C positioning", ifd0Id,
imgStruct, unsignedShort, print0x0213),
+ TagInfo(0x0214, "ReferenceBlackWhite", "Pair of black and white
reference values", ifd0Id, imgCharacter, unsignedRational, printValue),
+ TagInfo(0x8298, "Copyright", "Copyright holder", ifd0Id, otherTags,
asciiString, print0x8298),
+ TagInfo(0x8769, "ExifTag", "Exif IFD Pointer", ifd0Id, exifFormat,
unsignedLong, printValue),
+ TagInfo(0x8825, "GPSTag", "GPSInfo IFD Pointer", ifd0Id, exifFormat,
unsignedLong, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownIfdTag)", "Unknown IFD tag", ifdIdNotSet,
sectionIdNotSet, invalidTypeId, printValue)
+ };
+
+ // Exif IFD Tags
+ static const TagInfo exifTagInfo[] = {
+ TagInfo(0x829a, "ExposureTime", "Exposure time", exifIfdId,
captureCond, unsignedRational, print0x829a),
+ TagInfo(0x829d, "FNumber", "F number", exifIfdId, captureCond,
unsignedRational, print0x829d),
+ TagInfo(0x8822, "ExposureProgram", "Exposure program", exifIfdId,
captureCond, unsignedShort, print0x8822),
+ TagInfo(0x8824, "SpectralSensitivity", "Spectral sensitivity",
exifIfdId, captureCond, asciiString, printValue),
+ TagInfo(0x8827, "ISOSpeedRatings", "ISO speed ratings", exifIfdId,
captureCond, unsignedShort, print0x8827),
+ TagInfo(0x8828, "OECF", "Optoelectric coefficient", exifIfdId,
captureCond, undefined, printValue),
+ TagInfo(0x9000, "ExifVersion", "Exif Version", exifIfdId, exifVersion,
undefined, printValue),
+ TagInfo(0x9003, "DateTimeOriginal", "Date and time original image was
generated", exifIfdId, dateTime, asciiString, printValue),
+ TagInfo(0x9004, "DateTimeDigitized", "Date and time image was made
digital data", exifIfdId, dateTime, asciiString, printValue),
+ TagInfo(0x9101, "ComponentsConfiguration", "Meaning of each
component", exifIfdId, imgConfig, undefined, print0x9101),
+ TagInfo(0x9102, "CompressedBitsPerPixel", "Image compression mode",
exifIfdId, imgConfig, unsignedRational, printFloat),
+ TagInfo(0x9201, "ShutterSpeedValue", "Shutter speed", exifIfdId,
captureCond, signedRational, printFloat),
+ TagInfo(0x9202, "ApertureValue", "Aperture", exifIfdId, captureCond,
unsignedRational, printFloat),
+ TagInfo(0x9203, "BrightnessValue", "Brightness", exifIfdId,
captureCond, signedRational, printFloat),
+ TagInfo(0x9204, "ExposureBiasValue", "Exposure bias", exifIfdId,
captureCond, signedRational, print0x9204),
+ TagInfo(0x9205, "MaxApertureValue", "Maximum lens aperture",
exifIfdId, captureCond, unsignedRational, printFloat),
+ TagInfo(0x9206, "SubjectDistance", "Subject distance", exifIfdId,
captureCond, unsignedRational, print0x9206),
+ TagInfo(0x9207, "MeteringMode", "Metering mode", exifIfdId,
captureCond, unsignedShort, print0x9207),
+ TagInfo(0x9208, "LightSource", "Light source", exifIfdId, captureCond,
unsignedShort, print0x9208),
+ TagInfo(0x9209, "Flash", "Flash", exifIfdId, captureCond,
unsignedShort, print0x9209),
+ TagInfo(0x920a, "FocalLength", "Lens focal length", exifIfdId,
captureCond, unsignedRational, print0x920a),
+ TagInfo(0x9214, "SubjectArea", "Subject area", exifIfdId, captureCond,
unsignedShort, printValue),
+ TagInfo(0x927c, "MakerNote", "Manufacturer notes", exifIfdId,
userInfo, undefined, printValue),
+ TagInfo(0x9286, "UserComment", "User comments", exifIfdId, userInfo,
comment, print0x9286),
+ TagInfo(0x9290, "SubSecTime", "DateTime subseconds", exifIfdId,
dateTime, asciiString, printValue),
+ TagInfo(0x9291, "SubSecTimeOriginal", "DateTimeOriginal subseconds",
exifIfdId, dateTime, asciiString, printValue),
+ TagInfo(0x9292, "SubSecTimeDigitized", "DateTimeDigitized subseconds",
exifIfdId, dateTime, asciiString, printValue),
+ TagInfo(0xa000, "FlashpixVersion", "Supported Flashpix version",
exifIfdId, exifVersion, undefined, printValue),
+ TagInfo(0xa001, "ColorSpace", "Color space information", exifIfdId,
imgCharacter, unsignedShort, print0xa001),
+ TagInfo(0xa002, "PixelXDimension", "Valid image width", exifIfdId,
imgConfig, unsignedLong, printValue),
+ TagInfo(0xa003, "PixelYDimension", "Valid image height", exifIfdId,
imgConfig, unsignedLong, printValue),
+ TagInfo(0xa004, "RelatedSoundFile", "Related audio file", exifIfdId,
relatedFile, asciiString, printValue),
+ TagInfo(0xa005, "InteroperabilityTag", "Interoperability IFD Pointer",
exifIfdId, exifFormat, unsignedLong, printValue),
+ TagInfo(0xa20b, "FlashEnergy", "Flash energy", exifIfdId, captureCond,
unsignedRational, printValue),
+ TagInfo(0xa20c, "SpatialFrequencyResponse", "Spatial frequency
response", exifIfdId, captureCond, undefined, printValue),
+ TagInfo(0xa20e, "FocalPlaneXResolution", "Focal plane X resolution",
exifIfdId, captureCond, unsignedRational, printFloat),
+ TagInfo(0xa20f, "FocalPlaneYResolution", "Focal plane Y resolution",
exifIfdId, captureCond, unsignedRational, printFloat),
+ TagInfo(0xa210, "FocalPlaneResolutionUnit", "Focal plane resolution
unit", exifIfdId, captureCond, unsignedShort, printUnit),
+ TagInfo(0xa214, "SubjectLocation", "Subject location", exifIfdId,
captureCond, unsignedShort, printValue),
+ TagInfo(0xa215, "ExposureIndex", "Exposure index", exifIfdId,
captureCond, unsignedRational, printValue),
+ TagInfo(0xa217, "SensingMethod", "Sensing method", exifIfdId,
captureCond, unsignedShort, print0xa217),
+ TagInfo(0xa300, "FileSource", "File source", exifIfdId, captureCond,
undefined, print0xa300),
+ TagInfo(0xa301, "SceneType", "Scene type", exifIfdId, captureCond,
undefined, print0xa301),
+ TagInfo(0xa302, "CFAPattern", "CFA pattern", exifIfdId, captureCond,
undefined, printValue),
+ TagInfo(0xa401, "CustomRendered", "Custom image processing",
exifIfdId, captureCond, unsignedShort, printValue),
+ TagInfo(0xa402, "ExposureMode", "Exposure mode", exifIfdId,
captureCond, unsignedShort, print0xa402),
+ TagInfo(0xa403, "WhiteBalance", "White balance", exifIfdId,
captureCond, unsignedShort, print0xa403),
+ TagInfo(0xa404, "DigitalZoomRatio", "Digital zoom ratio", exifIfdId,
captureCond, unsignedRational, print0xa404),
+ TagInfo(0xa405, "FocalLengthIn35mmFilm", "Focal length in 35 mm film",
exifIfdId, captureCond, unsignedShort, print0xa405),
+ TagInfo(0xa406, "SceneCaptureType", "Scene capture type", exifIfdId,
captureCond, unsignedShort, print0xa406),
+ TagInfo(0xa407, "GainControl", "Gain control", exifIfdId, captureCond,
unsignedRational, print0xa407),
+ TagInfo(0xa408, "Contrast", "Contrast", exifIfdId, captureCond,
unsignedShort, print0xa408),
+ TagInfo(0xa409, "Saturation", "Saturation", exifIfdId, captureCond,
unsignedShort, print0xa409),
+ TagInfo(0xa40a, "Sharpness", "Sharpness", exifIfdId, captureCond,
unsignedShort, print0xa40a),
+ TagInfo(0xa40b, "DeviceSettingDescription", "Device settings
description", exifIfdId, captureCond, undefined, printValue),
+ TagInfo(0xa40c, "SubjectDistanceRange", "Subject distance range",
exifIfdId, captureCond, unsignedShort, print0xa40c),
+ TagInfo(0xa420, "ImageUniqueID", "Unique image ID", exifIfdId,
otherTags, asciiString, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownExifTag)", "Unknown Exif tag", ifdIdNotSet,
sectionIdNotSet, invalidTypeId, printValue)
+ };
+
+ // GPS Info Tags
+ static const TagInfo gpsTagInfo[] = {
+ TagInfo(0x0000, "GPSVersionID", "GPS tag version", gpsIfdId, gpsTags,
unsignedByte, printValue),
+ TagInfo(0x0001, "GPSLatitudeRef", "North or South Latitude", gpsIfdId,
gpsTags, asciiString, printValue),
+ TagInfo(0x0002, "GPSLatitude", "Latitude", gpsIfdId, gpsTags,
unsignedRational, printValue),
+ TagInfo(0x0003, "GPSLongitudeRef", "East or West Longitude", gpsIfdId,
gpsTags, asciiString, printValue),
+ TagInfo(0x0004, "GPSLongitude", "Longitude", gpsIfdId, gpsTags,
unsignedRational, printValue),
+ TagInfo(0x0005, "GPSAltitudeRef", "Altitude reference", gpsIfdId,
gpsTags, unsignedByte, printValue),
+ TagInfo(0x0006, "GPSAltitude", "Altitude", gpsIfdId, gpsTags,
unsignedRational, printValue),
+ TagInfo(0x0007, "GPSTimeStamp", "GPS time (atomic clock)", gpsIfdId,
gpsTags, unsignedRational, printValue),
+ TagInfo(0x0008, "GPSSatellites", "GPS satellites used for
measurement", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x0009, "GPSStatus", "GPS receiver status", gpsIfdId, gpsTags,
asciiString, printValue),
+ TagInfo(0x000a, "GPSMeasureMode", "GPS measurement mode", gpsIfdId,
gpsTags, asciiString, printValue),
+ TagInfo(0x000b, "GPSDOP", "Measurement precision", gpsIfdId, gpsTags,
unsignedRational, printValue),
+ TagInfo(0x000c, "GPSSpeedRef", "Speed unit", gpsIfdId, gpsTags,
asciiString, printValue),
+ TagInfo(0x000d, "GPSSpeed", "Speed of GPS receiver", gpsIfdId,
gpsTags, unsignedRational, printValue),
+ TagInfo(0x000e, "GPSTrackRef", "Reference for direction of movement",
gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x000f, "GPSTrack", "Direction of movement", gpsIfdId,
gpsTags, unsignedRational, printValue),
+ TagInfo(0x0010, "GPSImgDirectionRef", "Reference for direction of
image", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x0011, "GPSImgDirection", "Direction of image", gpsIfdId,
gpsTags, unsignedRational, printValue),
+ TagInfo(0x0012, "GPSMapDatum", "Geodetic survey data used", gpsIfdId,
gpsTags, asciiString, printValue),
+ TagInfo(0x0013, "GPSDestLatitudeRef", "Reference for latitude of
destination", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x0014, "GPSDestLatitude", "Latitude of destination",
gpsIfdId, gpsTags, unsignedRational, printValue),
+ TagInfo(0x0015, "GPSDestLongitudeRef", "Reference for longitude of
destination", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x0016, "GPSDestLongitude", "Longitude of destination",
gpsIfdId, gpsTags, unsignedRational, printValue),
+ TagInfo(0x0017, "GPSDestBearingRef", "Reference for bearing of
destination", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x0018, "GPSDestBearing", "Bearing of destination", gpsIfdId,
gpsTags, unsignedRational, printValue),
+ TagInfo(0x0019, "GPSDestDistanceRef", "Reference for distance to
destination", gpsIfdId, gpsTags, asciiString, printValue),
+ TagInfo(0x001a, "GPSDestDistance", "Distance to destination",
gpsIfdId, gpsTags, unsignedRational, printValue),
+ TagInfo(0x001b, "GPSProcessingMethod", "Name of GPS processing
method", gpsIfdId, gpsTags, undefined, printValue),
+ TagInfo(0x001c, "GPSAreaInformation", "Name of GPS area", gpsIfdId,
gpsTags, undefined, printValue),
+ TagInfo(0x001d, "GPSDateStamp", "GPS date", gpsIfdId, gpsTags,
asciiString, printValue),
+ TagInfo(0x001e, "GPSDifferential", "GPS differential correction",
gpsIfdId, gpsTags, unsignedShort, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownGpsTag)", "Unknown GPSInfo tag", ifdIdNotSet,
sectionIdNotSet, invalidTypeId, printValue)
+ };
+
+ // Exif Interoperability IFD Tags
+ static const TagInfo iopTagInfo[] = {
+ TagInfo(0x0001, "InteroperabilityIndex", "Interoperability
Identification", iopIfdId, iopTags, asciiString, printValue),
+ TagInfo(0x0002, "InteroperabilityVersion", "Interoperability version",
iopIfdId, iopTags, undefined, printValue),
+ TagInfo(0x1000, "RelatedImageFileFormat", "File format of image file",
iopIfdId, iopTags, asciiString, printValue),
+ TagInfo(0x1001, "RelatedImageWidth", "Image width", iopIfdId, iopTags,
unsignedLong, printValue),
+ TagInfo(0x1002, "RelatedImageLength", "Image height", iopIfdId,
iopTags, unsignedLong, printValue),
+ // End of list marker
+ TagInfo(0xffff, "(UnknownIopTag)", "Unknown Exif Interoperability
tag", ifdIdNotSet, sectionIdNotSet, invalidTypeId, printValue)
+ };
+
+ // Unknown Tag
+ static const TagInfo unknownTag(0xffff, "Unknown tag", "Unknown tag",
ifdIdNotSet, sectionIdNotSet, asciiString, printValue);
+
+ std::ostream& TagTranslator::print(std::ostream& os, const Value& value)
const
+ {
+ if (!pTagDetails_) return os << value;
+
+ long l = value.toLong();
+
+ long e = pTagDetails_[0].val_;
+ int i = 1;
+ for (; pTagDetails_[i].val_ != l && pTagDetails_[i].val_ != e; ++i) {}
+ if (pTagDetails_[i].val_ == l) {
+ os << pTagDetails_[i].label_;
+ }
+ else {
+ os << "(" << l << ")";
+ }
+ return os;
+ } // TagTranslator::print
+
+ // Tag lookup lists with tag names, desc and where they (preferably)
belong to;
+ // this is an array with pointers to one list per IFD. The IfdId is used
as the
+ // index into the array.
+ const TagInfo* ExifTags::tagInfos_[] = {
+ 0,
+ ifdTagInfo, exifTagInfo, gpsTagInfo, iopTagInfo, ifdTagInfo,
+ 0
+ };
+
+ // Lookup list for registered makernote tag info tables
+ const TagInfo* ExifTags::makerTagInfos_[];
+
+ // All makernote ifd ids, in the same order as the tag infos in
makerTagInfos_
+ IfdId ExifTags::makerIfdIds_[];
+
+ void ExifTags::registerBaseTagInfo(IfdId ifdId)
+ {
+ registerMakerTagInfo(ifdId, ifdTagInfo);
+ }
+
+ void ExifTags::registerMakerTagInfo(IfdId ifdId, const TagInfo* tagInfo)
+ {
+ int i = 0;
+ for (; i < MAX_MAKER_TAG_INFOS; ++i) {
+ if (makerIfdIds_[i] == 0) {
+ makerIfdIds_[i] = ifdId;
+ makerTagInfos_[i] = tagInfo;
+ break;
+ }
+ }
+ if (i == MAX_MAKER_TAG_INFOS) throw Error(16);
+ } // ExifTags::registerMakerTagInfo
+
+ 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) return idx;
+ }
+ return -1;
+ } // ExifTags::tagInfoIdx
+
+ const TagInfo* ExifTags::makerTagInfo(uint16_t tag, IfdId ifdId)
+ {
+ int i = 0;
+ for (; i < MAX_MAKER_TAG_INFOS && makerIfdIds_[i] != ifdId; ++i);
+ if (i == MAX_MAKER_TAG_INFOS) return 0;
+
+ for (int k = 0; makerTagInfos_[i][k].tag_ != 0xffff; ++k) {
+ if (makerTagInfos_[i][k].tag_ == tag) return &makerTagInfos_[i][k];
+ }
+
+ return 0;
+ } // ExifTags::makerTagInfo
+
+ const TagInfo* ExifTags::makerTagInfo(const std::string& tagName,
+ IfdId ifdId)
+ {
+ int i = 0;
+ for (; i < MAX_MAKER_TAG_INFOS && makerIfdIds_[i] != ifdId; ++i);
+ if (i == MAX_MAKER_TAG_INFOS) return 0;
+
+ for (int k = 0; makerTagInfos_[i][k].tag_ != 0xffff; ++k) {
+ if (makerTagInfos_[i][k].name_ == tagName) {
+ return &makerTagInfos_[i][k];
+ }
+ }
+
+ return 0;
+ } // ExifTags::makerTagInfo
+
+ bool ExifTags::isMakerIfd(IfdId ifdId)
+ {
+ int i = 0;
+ for (; i < MAX_MAKER_TAG_INFOS && makerIfdIds_[i] != ifdId; ++i);
+ return i != MAX_MAKER_TAG_INFOS && makerIfdIds_[i] != IfdId(0);
+ }
+
+ std::string ExifTags::tagName(uint16_t tag, IfdId ifdId)
+ {
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx != -1) return tagInfos_[ifdId][idx].name_;
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) return tagInfo->name_;
+ }
+ std::ostringstream os;
+ os << "0x" << std::setw(4) << std::setfill('0') << std::right
+ << std::hex << tag;
+ return os.str();
+ } // ExifTags::tagName
+
+ const char* ExifTags::tagDesc(uint16_t tag, IfdId ifdId)
+ {
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx == -1) return unknownTag.desc_;
+ return tagInfos_[ifdId][idx].desc_;
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) return tagInfo->desc_;
+ }
+ return "";
+ } // ExifTags::tagDesc
+
+ const char* ExifTags::sectionName(uint16_t tag, IfdId ifdId)
+ {
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx == -1) return sectionInfo_[unknownTag.sectionId_].name_;
+ const TagInfo* tagInfo = tagInfos_[ifdId];
+ return sectionInfo_[tagInfo[idx].sectionId_].name_;
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) return sectionInfo_[tagInfo->sectionId_].name_;
+ }
+ return "";
+ } // ExifTags::sectionName
+
+ const char* ExifTags::sectionDesc(uint16_t tag, IfdId ifdId)
+ {
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx == -1) return sectionInfo_[unknownTag.sectionId_].desc_;
+ const TagInfo* tagInfo = tagInfos_[ifdId];
+ return sectionInfo_[tagInfo[idx].sectionId_].desc_;
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) return sectionInfo_[tagInfo->sectionId_].desc_;
+ }
+ return "";
+ } // ExifTags::sectionDesc
+
+ uint16_t ExifTags::tag(const std::string& tagName, IfdId ifdId)
+ {
+ uint16_t tag = 0xffff;
+ if (isExifIfd(ifdId)) {
+ const TagInfo* tagInfo = tagInfos_[ifdId];
+ if (tagInfo) {
+ int idx;
+ for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) {
+ if (tagInfo[idx].name_ == tagName) break;
+ }
+ tag = tagInfo[idx].tag_;
+ }
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tagName, ifdId);
+ if (tagInfo != 0) tag = tagInfo->tag_;
+ }
+ if (tag == 0xffff) {
+ if (!isHex(tagName, 4, "0x")) throw Error(7, tagName, ifdId);
+ std::istringstream is(tagName);
+ is >> std::hex >> tag;
+ }
+ return tag;
+ } // ExifTags::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 IfdId(i);
+ }
+
+ const char* ExifTags::ifdName(IfdId ifdId)
+ {
+ return ifdInfo_[ifdId].name_;
+ }
+
+ const char* ExifTags::ifdItem(IfdId ifdId)
+ {
+ return ifdInfo_[ifdId].item_;
+ }
+
+ const char* ExifTags::sectionName(SectionId sectionId)
+ {
+ return sectionInfo_[sectionId].name_;
+ }
+
+ SectionId ExifTags::sectionId(const std::string& sectionName)
+ {
+ int i;
+ for (i = int(lastSectionId) - 1; i > 0; --i) {
+ if (sectionInfo_[i].name_ == sectionName) break;
+ }
+ return SectionId(i);
+ }
+
+ TypeId ExifTags::tagType(uint16_t tag, IfdId ifdId)
+ {
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx != -1) return tagInfos_[ifdId][idx].typeId_;
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) return tagInfo->typeId_;
+ }
+ return unknownTag.typeId_;
+ }
+
+ std::ostream& ExifTags::printTag(std::ostream& os,
+ uint16_t tag,
+ IfdId ifdId,
+ const Value& value)
+ {
+ PrintFct fct = printValue;
+ if (isExifIfd(ifdId)) {
+ int idx = tagInfoIdx(tag, ifdId);
+ if (idx != -1) {
+ fct = tagInfos_[ifdId][idx].printFct_;
+ }
+ }
+ if (isMakerIfd(ifdId)) {
+ const TagInfo* tagInfo = makerTagInfo(tag, ifdId);
+ if (tagInfo != 0) fct = tagInfo->printFct_;
+ }
+ return fct(os, value);
+ } // ExifTags::printTag
+
+ void ExifTags::taglist(std::ostream& os)
+ {
+ for (int i=0; ifdTagInfo[i].tag_ != 0xffff; ++i) {
+ os << ifdTagInfo[i] << "\n";
+ }
+ for (int i=0; exifTagInfo[i].tag_ != 0xffff; ++i) {
+ os << exifTagInfo[i] << "\n";
+ }
+ for (int i=0; iopTagInfo[i].tag_ != 0xffff; ++i) {
+ os << iopTagInfo[i] << "\n";
+ }
+ for (int i=0; gpsTagInfo[i].tag_ != 0xffff; ++i) {
+ os << gpsTagInfo[i] << "\n";
+ }
+ } // ExifTags::taglist
+
+ void ExifTags::makerTaglist(std::ostream& os, IfdId ifdId)
+ {
+ int i = 0;
+ for (; i < MAX_MAKER_TAG_INFOS && makerIfdIds_[i] != ifdId; ++i);
+ if (i != MAX_MAKER_TAG_INFOS) {
+ const TagInfo* mnTagInfo = makerTagInfos_[i];
+ for (int k=0; mnTagInfo[k].tag_ != 0xffff; ++k) {
+ os << mnTagInfo[k] << "\n";
+ }
+ }
+ } // ExifTags::makerTaglist
+
+ const char* ExifKey::familyName_ = "Exif";
+
+ ExifKey::ExifKey(const std::string& key)
+ : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""),
+ idx_(0), key_(key)
+ {
+ decomposeKey();
+ }
+
+ ExifKey::ExifKey(uint16_t tag, const std::string& ifdItem)
+ : tag_(0), ifdId_(ifdIdNotSet), ifdItem_(""),
+ idx_(0), key_("")
+ {
+ IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem);
+ if (ExifTags::isMakerIfd(ifdId)) {
+ MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId);
+ if (makerNote.get() == 0) throw Error(23, ifdId);
+ }
+ tag_ = tag;
+ ifdId_ = ifdId;
+ ifdItem_ = ifdItem;
+ makeKey();
+ }
+
+ ExifKey::ExifKey(const Entry& e)
+ : tag_(e.tag()), ifdId_(e.ifdId()),
+ ifdItem_(ExifTags::ifdItem(e.ifdId())),
+ idx_(e.idx()), key_("")
+ {
+ makeKey();
+ }
+
+ ExifKey::ExifKey(const ExifKey& rhs)
+ : tag_(rhs.tag_), ifdId_(rhs.ifdId_), ifdItem_(rhs.ifdItem_),
+ idx_(rhs.idx_), key_(rhs.key_)
+ {
+ }
+
+ ExifKey::~ExifKey()
+ {
+ }
+
+ ExifKey& ExifKey::operator=(const ExifKey& rhs)
+ {
+ if (this == &rhs) return *this;
+ Key::operator=(rhs);
+ tag_ = rhs.tag_;
+ ifdId_ = rhs.ifdId_;
+ ifdItem_ = rhs.ifdItem_;
+ idx_ = rhs.idx_;
+ key_ = rhs.key_;
+ return *this;
+ }
+
+ std::string ExifKey::tagName() const
+ {
+ return ExifTags::tagName(tag_, ifdId_);
+ }
+
+ ExifKey::AutoPtr ExifKey::clone() const
+ {
+ return AutoPtr(clone_());
+ }
+
+ ExifKey* ExifKey::clone_() const
+ {
+ return new ExifKey(*this);
+ }
+
+ std::string ExifKey::sectionName() const
+ {
+ return ExifTags::sectionName(tag(), ifdId());
+ }
+
+ void ExifKey::decomposeKey()
+ {
+ // Get the family name, IFD name and tag name parts of the key
+ std::string::size_type pos1 = key_.find('.');
+ if (pos1 == std::string::npos) throw Error(6, key_);
+ std::string familyName = key_.substr(0, pos1);
+ if (familyName != std::string(familyName_)) {
+ throw Error(6, key_);
+ }
+ std::string::size_type pos0 = pos1 + 1;
+ pos1 = key_.find('.', pos0);
+ if (pos1 == std::string::npos) throw Error(6, key_);
+ std::string ifdItem = key_.substr(pos0, pos1 - pos0);
+ if (ifdItem == "") throw Error(6, key_);
+ std::string tagName = key_.substr(pos1 + 1);
+ if (tagName == "") throw Error(6, key_);
+
+ // Find IfdId
+ IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem);
+ if (ifdId == ifdIdNotSet) throw Error(6, key_);
+ if (ExifTags::isMakerIfd(ifdId)) {
+ MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId);
+ if (makerNote.get() == 0) throw Error(6, key_);
+ }
+ // Convert tag
+ uint16_t tag = ExifTags::tag(tagName, ifdId);
+
+ // Translate hex tag name (0xabcd) to a real tag name if there is one
+ tagName = ExifTags::tagName(tag, ifdId);
+
+ tag_ = tag;
+ ifdId_ = ifdId;
+ ifdItem_ = ifdItem;
+ key_ = familyName + "." + ifdItem + "." + tagName;
+ }
+
+ void ExifKey::makeKey()
+ {
+ key_ = std::string(familyName_)
+ + "." + ifdItem_
+ + "." + ExifTags::tagName(tag_, ifdId_);
+ }
+
+ //
*************************************************************************
+ // free functions
+
+ bool isExifIfd(IfdId ifdId)
+ {
+ bool rc;
+ switch (ifdId) {
+ case ifd0Id: rc = true; break;
+ case exifIfdId: rc = true; break;
+ case gpsIfdId: rc = true; break;
+ case iopIfdId: rc = true; break;
+ case ifd1Id: rc = true; break;
+ default: rc = false; break;
+ }
+ return rc;
+ } // isExifIfd
+
+ 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_) << ", "
+ << exifKey.key() << ", "
+ << TypeInfo::typeName(
+ ExifTags::tagType(ti.tag_, ti.ifdId_)) << ", "
+ << ExifTags::tagDesc(ti.tag_, ti.ifdId_);
+ }
+
+ std::ostream& operator<<(std::ostream& os, const Rational& r)
+ {
+ return os << r.first << "/" << r.second;
+ }
+
+ std::istream& operator>>(std::istream& is, Rational& r)
+ {
+ int32_t nominator;
+ int32_t denominator;
+ char c;
+ is >> nominator >> c >> denominator;
+ if (is && c == '/') r = std::make_pair(nominator, denominator);
+ return is;
+ }
+
+ std::ostream& operator<<(std::ostream& os, const URational& r)
+ {
+ return os << r.first << "/" << r.second;
+ }
+
+ std::istream& operator>>(std::istream& is, URational& r)
+ {
+ uint32_t nominator;
+ uint32_t denominator;
+ char c;
+ is >> nominator >> c >> denominator;
+ if (is && c == '/') r = std::make_pair(nominator, denominator);
+ return is;
+ }
+
+ std::ostream& printValue(std::ostream& os, const Value& value)
+ {
+ return os << value;
+ }
+
+ std::ostream& printLong(std::ostream& os, const Value& value)
+ {
+ return os << value.toLong();
+ }
+
+ std::ostream& printFloat(std::ostream& os, const Value& value)
+ {
+ Rational r = value.toRational();
+ if (r.second != 0) return os << static_cast<float>(r.first) / r.second;
+ return os << "(" << value << ")";
+ } // printFloat
+
+ std::ostream& printUnit(std::ostream& os, const Value& value)
+ {
+ long unit = value.toLong();
+ switch (unit) {
+ case 2: os << "inch"; break;
+ case 3: os << "cm"; break;
+ default: os << "(" << unit << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x0103(std::ostream& os, const Value& value)
+ {
+ long compression = value.toLong();
+ switch (compression) {
+ case 1: os << "TIFF"; break;
+ case 6: os << "JPEG"; break;
+ default: os << "(" << compression << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x0106(std::ostream& os, const Value& value)
+ {
+ long photo = value.toLong();
+ switch (photo) {
+ case 2: os << "RGB"; break;
+ case 6: os << "YCbCr"; break;
+ default: os << "(" << photo << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x0112(std::ostream& os, const Value& value)
+ {
+ long orientation = value.toLong();
+ switch (orientation) {
+ case 1: os << "top, left"; break;
+ case 2: os << "top, right"; break;
+ case 3: os << "bottom, right"; break;
+ case 4: os << "bottom, left"; break;
+ case 5: os << "left, top"; break;
+ case 6: os << "right, top"; break;
+ case 7: os << "right, bottom"; break;
+ case 8: os << "left, bottom"; break;
+ default: os << "(" << orientation << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x0213(std::ostream& os, const Value& value)
+ {
+ long position = value.toLong();
+ switch (position) {
+ case 1: os << "Centered"; break;
+ case 2: os << "Co-sited"; break;
+ default: os << "(" << position << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x8298(std::ostream& os, const Value& value)
+ {
+ // Print the copyright information in the format Photographer, Editor
+ std::string val = value.toString();
+ std::string::size_type pos = val.find('\0');
+ if (pos != std::string::npos) {
+ std::string photographer(val, 0, pos);
+ if (photographer != " ") os << photographer;
+ std::string editor(val, pos + 1);
+ if (editor != "") {
+ if (photographer != " ") os << ", ";
+ os << editor;
+ }
+ }
+ else {
+ os << val;
+ }
+ return os;
+ }
+
+ std::ostream& print0x829a(std::ostream& os, const Value& value)
+ {
+ Rational t = value.toRational();
+ if (t.first > 1 && t.second > 1 && t.second >= t.first) {
+ t.second = static_cast<uint32_t>(
+ static_cast<float>(t.second) / t.first + 0.5);
+ t.first = 1;
+ }
+ if (t.second > 1 && t.second < t.first) {
+ t.first = static_cast<uint32_t>(
+ static_cast<float>(t.first) / t.second + 0.5);
+ t.second = 1;
+ }
+ if (t.second == 1) {
+ os << t.first << " s";
+ }
+ else {
+ os << t.first << "/" << t.second << " s";
+ }
+ return os;
+ }
+
+ std::ostream& print0x829d(std::ostream& os, const Value& value)
+ {
+ Rational fnumber = value.toRational();
+ if (fnumber.second != 0) {
+ os << "F" << (float)fnumber.first / fnumber.second;
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& print0x8822(std::ostream& os, const Value& value)
+ {
+ long program = value.toLong();
+ switch (program) {
+ case 0: os << "Not defined"; break;
+ case 1: os << "Manual"; break;
+ case 2: os << "Auto"; break;
+ case 3: os << "Aperture priority"; break;
+ case 4: os << "Shutter priority"; break;
+ case 5: os << "Creative program"; break;
+ case 6: os << "Action program"; break;
+ case 7: os << "Portrait mode"; break;
+ case 8: os << "Landscape mode"; break;
+ default: os << "(" << program << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x8827(std::ostream& os, const Value& value)
+ {
+ return os << value.toLong();
+ }
+
+ std::ostream& print0x9101(std::ostream& os, const Value& value)
+ {
+ for (long i = 0; i < value.count(); ++i) {
+ long l = value.toLong(i);
+ switch (l) {
+ case 0: break;
+ case 1: os << "Y"; break;
+ case 2: os << "Cb"; break;
+ case 3: os << "Cr"; break;
+ case 4: os << "R"; break;
+ case 5: os << "G"; break;
+ case 6: os << "B"; break;
+ default: os << "(" << l << ")"; break;
+ }
+ }
+ return os;
+ }
+
+ std::ostream& print0x9204(std::ostream& os, const Value& value)
+ {
+ Rational bias = value.toRational();
+ if (bias.second <= 0) {
+ os << "(" << bias.first << "/" << bias.second << ")";
+ }
+ else if (bias.first == 0) {
+ os << "0";
+ }
+ else {
+ long d = lgcd(labs(bias.first), bias.second);
+ long num = labs(bias.first) / d;
+ long den = bias.second / d;
+ os << (bias.first < 0 ? "-" : "+") << num;
+ if (den != 1) {
+ os << "/" << den;
+ }
+ }
+ return os;
+ }
+
+ std::ostream& print0x9206(std::ostream& os, const Value& value)
+ {
+ Rational distance = value.toRational();
+ if (distance.first == 0) {
+ os << "Unknown";
+ }
+ else if (static_cast<uint32_t>(distance.first) == 0xffffffff) {
+ os << "Infinity";
+ }
+ else if (distance.second != 0) {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(2)
+ << (float)distance.first / distance.second
+ << " m";
+ os.copyfmt(oss);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ std::ostream& print0x9207(std::ostream& os, const Value& value)
+ {
+ long mode = value.toLong();
+ switch (mode) {
+ case 0: os << "Unknown"; break;
+ case 1: os << "Average"; break;
+ case 2: os << "Center weighted"; break;
+ case 3: os << "Spot"; break;
+ case 4: os << "Multispot"; break;
+ case 5: os << "Matrix"; break;
+ case 6: os << "Partial"; break;
+ default: os << "(" << mode << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x9208(std::ostream& os, const Value& value)
+ {
+ long source = value.toLong();
+ switch (source) {
+ case 0: os << "Unknown"; break;
+ case 1: os << "Daylight"; break;
+ case 2: os << "Fluorescent"; break;
+ case 3: os << "Tungsten (incandescent light)"; break;
+ case 4: os << "Flash"; break;
+ case 9: os << "Fine weather"; break;
+ case 10: os << "Cloudy weather"; break;
+ case 11: os << "Shade"; break;
+ case 12: os << "Daylight fluorescent (D 5700 - 7100K)"; break;
+ case 13: os << "Day white fluorescent (N 4600 - 5400K)"; break;
+ case 14: os << "Cool white fluorescent (W 3900 - 4500K)"; break;
+ case 15: os << "White fluorescent (WW 3200 - 3700K)"; break;
+ case 17: os << "Standard light A"; break;
+ case 18: os << "Standard light B"; break;
+ case 19: os << "Standard light C"; break;
+ case 20: os << "D55"; break;
+ case 21: os << "D65"; break;
+ case 22: os << "D75"; break;
+ case 23: os << "D50"; break;
+ case 24: os << "ISO studio tungsten"; break;
+ case 255: os << "other light source"; break;
+ default: os << "(" << source << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x9209(std::ostream& os, const Value& value)
+ {
+ long flash = value.toLong();
+ switch (flash) {
+ case 0x00: os << "No"; break;
+ case 0x01: os << "Yes"; break;
+ case 0x05: os << "Strobe return light not detected"; break;
+ case 0x07: os << "Strobe return light detected"; break;
+ case 0x09: os << "Yes, compulsory"; break;
+ case 0x0d: os << "Yes, compulsory, return light not detected"; break;
+ case 0x0f: os << "Yes, compulsory, return light detected"; break;
+ case 0x10: os << "No, compulsory"; break;
+ case 0x18: os << "No, auto"; break;
+ case 0x19: os << "Yes, auto"; break;
+ case 0x1d: os << "Yes, auto, return light not detected"; break;
+ case 0x1f: os << "Yes, auto, return light detected"; break;
+ case 0x20: os << "No flash function"; break;
+ case 0x41: os << "Yes, red-eye reduction"; break;
+ case 0x45: os << "Yes, red-eye reduction, return light not detected";
break;
+ case 0x47: os << "Yes, red-eye reduction, return light detected";
break;
+ case 0x49: os << "Yes, compulsory, red-eye reduction"; break;
+ case 0x4d: os << "Yes, compulsory, red-eye reduction, return light not
detected"; break;
+ case 0x4f: os << "Yes, compulsory, red-eye reduction, return light
detected"; break;
+ case 0x59: os << "Yes, auto, red-eye reduction"; break;
+ case 0x5d: os << "Yes, auto, red-eye reduction, return light not
detected"; break;
+ case 0x5f: os << "Yes, auto, red-eye reduction, return light
detected"; break;
+ default: os << "(" << flash << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0x920a(std::ostream& os, const Value& value)
+ {
+ Rational length = value.toRational();
+ if (length.second != 0) {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(1)
+ << (float)length.first / length.second
+ << " mm";
+ os.copyfmt(oss);
+ }
+ else {
+ os << "(" << value << ")";
+ }
+ return os;
+ }
+
+ // Todo: Implement this properly
+ std::ostream& print0x9286(std::ostream& os, const Value& value)
+ {
+ if (value.size() > 8) {
+ DataBuf buf(value.size());
+ value.copy(buf.pData_, bigEndian);
+ // Hack: Skip the leading 8-Byte character code, truncate
+ // trailing '\0's and let the stream take care of the remainder
+ std::string userComment(reinterpret_cast<char*>(buf.pData_) + 8,
buf.size_ - 8);
+ std::string::size_type pos = userComment.find_last_not_of('\0');
+ os << userComment.substr(0, pos + 1);
+ }
+ return os;
+ }
+
+ std::ostream& print0xa001(std::ostream& os, const Value& value)
+ {
+ long space = value.toLong();
+ switch (space) {
+ case 1: os << "sRGB"; break;
+ case 0xffff: os << "Uncalibrated"; break;
+ default: os << "(" << space << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa217(std::ostream& os, const Value& value)
+ {
+ long method = value.toLong();
+ switch (method) {
+ case 1: os << "Not defined"; break;
+ case 2: os << "One-chip color area"; break;
+ case 3: os << "Two-chip color area"; break;
+ case 4: os << "Three-chip color area"; break;
+ case 5: os << "Color sequential area"; break;
+ case 7: os << "Trilinear sensor"; break;
+ case 8: os << "Color sequential linear"; break;
+ default: os << "(" << method << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa300(std::ostream& os, const Value& value)
+ {
+ long source = value.toLong();
+ switch (source) {
+ case 3: os << "Digital still camera"; break;
+ default: os << "(" << source << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa301(std::ostream& os, const Value& value)
+ {
+ long scene = value.toLong();
+ switch (scene) {
+ case 1: os << "Directly photographed"; break;
+ default: os << "(" << scene << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa402(std::ostream& os, const Value& value)
+ {
+ long mode = value.toLong();
+ switch (mode) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Manual"; break;
+ case 2: os << "Auto bracket"; break;
+ default: os << "(" << mode << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa403(std::ostream& os, const Value& value)
+ {
+ long wb = value.toLong();
+ switch (wb) {
+ case 0: os << "Auto"; break;
+ case 1: os << "Manual"; break;
+ default: os << "(" << wb << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa404(std::ostream& os, const Value& value)
+ {
+ Rational zoom = value.toRational();
+ if (zoom.second == 0) {
+ os << "Digital zoom not used";
+ }
+ else {
+ std::ostringstream oss;
+ oss.copyfmt(os);
+ os << std::fixed << std::setprecision(1)
+ << (float)zoom.first / zoom.second;
+ os.copyfmt(oss);
+ }
+ return os;
+ }
+
+ std::ostream& print0xa405(std::ostream& os, const Value& value)
+ {
+ long length = value.toLong();
+ if (length == 0) {
+ os << "Unknown";
+ }
+ else {
+ os << length << ".0 mm";
+ }
+ return os;
+ }
+
+ std::ostream& print0xa406(std::ostream& os, const Value& value)
+ {
+ long scene = value.toLong();
+ switch (scene) {
+ case 0: os << "Standard"; break;
+ case 1: os << "Landscape"; break;
+ case 2: os << "Portrait"; break;
+ case 3: os << "Night scene"; break;
+ default: os << "(" << scene << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa407(std::ostream& os, const Value& value)
+ {
+ long gain = value.toLong();
+ switch (gain) {
+ case 0: os << "None"; break;
+ case 1: os << "Low gain up"; break;
+ case 2: os << "High gain up"; break;
+ case 3: os << "Low gain down"; break;
+ case 4: os << "High gain down"; break;
+ default: os << "(" << gain << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa408(std::ostream& os, const Value& value)
+ {
+ long contrast = value.toLong();
+ switch (contrast) {
+ case 0: os << "Normal"; break;
+ case 1: os << "Soft"; break;
+ case 2: os << "Hard"; break;
+ default: os << "(" << contrast << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa409(std::ostream& os, const Value& value)
+ {
+ long saturation = value.toLong();
+ switch (saturation) {
+ case 0: os << "Normal"; break;
+ case 1: os << "Low"; break;
+ case 2: os << "High"; break;
+ default: os << "(" << saturation << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa40a(std::ostream& os, const Value& value)
+ {
+ long sharpness = value.toLong();
+ switch (sharpness) {
+ case 0: os << "Normal"; break;
+ case 1: os << "Soft"; break;
+ case 2: os << "Hard"; break;
+ default: os << "(" << sharpness << ")"; break;
+ }
+ return os;
+ }
+
+ std::ostream& print0xa40c(std::ostream& os, const Value& value)
+ {
+ long distance = value.toLong();
+ switch (distance) {
+ case 0: os << "Unknown"; break;
+ case 1: os << "Macro"; break;
+ case 2: os << "Close view"; break;
+ case 3: os << "Distant view"; break;
+ default: os << "(" << distance << ")"; break;
+ }
+ return os;
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/tags.hpp
===================================================================
--- Extractor/src/plugins/exiv2/tags.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/tags.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,444 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file tags.hpp
+ @brief Exif tag and type information
+ @version $Rev: 580 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 15-Jan-04, ahu: created<BR>
+ 11-Feb-04, ahu: isolated as a component
+ */
+#ifndef TAGS_HPP_
+#define TAGS_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "metadatum.hpp"
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <utility> // for std::pair
+#include <iosfwd>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class declarations
+ class Value;
+ class Entry;
+
+//
*****************************************************************************
+// type definitions
+
+ //! Type for a function pointer for functions interpreting the tag value
+ typedef std::ostream& (*PrintFct)(std::ostream&, const Value&);
+
+ /*!
+ @brief Section identifiers to logically group tags. A section consists
+ of nothing more than a name, based on the Exif standard.
+ */
+ enum SectionId { sectionIdNotSet,
+ imgStruct, recOffset, imgCharacter, otherTags,
exifFormat,
+ exifVersion, imgConfig, userInfo, relatedFile, dateTime,
+ captureCond, gpsTags, iopTags, makerTags,
+ lastSectionId };
+
+//
*****************************************************************************
+// class definitions
+
+ //! Contains information pertaining to one IFD
+ struct IfdInfo {
+ //! Constructor
+ IfdInfo(IfdId ifdId, const char* name, const char* item);
+ IfdId ifdId_; //!< IFD id
+ const char* name_; //!< IFD name
+ //! Related IFD item. This is also an IFD name, unique for each IFD.
+ const char* item_;
+ };
+
+ //! Contains information pertaining to one section
+ struct SectionInfo {
+ //! Constructor
+ SectionInfo(SectionId sectionId, const char* name, const char* desc);
+ SectionId sectionId_; //!< Section id
+ const char* name_; //!< Section name (one word)
+ const char* desc_; //!< Section description
+ };
+
+ //! Tag information
+ struct TagInfo {
+ //! Constructor
+ TagInfo(
+ uint16_t tag,
+ const char* name,
+ const char* desc,
+ IfdId ifdId,
+ SectionId sectionId,
+ TypeId typeId,
+ PrintFct printFct
+ );
+ uint16_t tag_; //!< Tag
+ const char* name_; //!< One word tag label
+ const char* desc_; //!< Short tag description
+ IfdId ifdId_; //!< Link to the (prefered) IFD
+ SectionId sectionId_; //!< Section id
+ TypeId typeId_; //!< Type id
+ PrintFct printFct_; //!< Pointer to tag print
function
+ }; // struct TagInfo
+
+ /*!
+ @brief Helper structure for lookup tables for translations of numeric
+ tag values to human readable labels.
+ */
+ struct TagDetails {
+ long val_; //!< Tag value
+ char* label_; //!< Translation of the tag
value
+ }; // struct TagDetails
+
+ /*!
+ @brief Translation from numeric values from a lookup list to human
+ readable labels
+ */
+ class TagTranslator {
+ public:
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ explicit TagTranslator(const TagDetails* pTagDetails)
+ : pTagDetails_(pTagDetails) {}
+ // No d'tor: Do not delete the list.
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Translate the tag value and write it out to the provided stream
+ std::ostream& print(std::ostream& os, const Value& value) const;
+ //@}
+ private:
+ const TagDetails* pTagDetails_;
+ }; // class TagTranslator
+
+ //! Container for Exif tag information. Implemented as a static class.
+ class ExifTags {
+ //! Prevent construction: not implemented.
+ ExifTags() {}
+ //! Prevent copy-construction: not implemented.
+ ExifTags(const ExifTags& rhs);
+ //! Prevent assignment: not implemented.
+ ExifTags& operator=(const ExifTags& rhs);
+
+ public:
+ /*!
+ @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 containing the hexadecimal
+ value of the tag in the form "0x01ff", if this is an unknown
+ tag.
+ */
+ static std::string tagName(uint16_t tag, IfdId ifdId);
+ /*!
+ @brief Return the description of the tag.
+ @param tag The tag
+ @param ifdId IFD id
+ @return The description of the tag or a string indicating that
+ the tag is unknown.
+ */
+ static const char* tagDesc(uint16_t tag, IfdId ifdId);
+ /*!
+ @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.
+
+ @throw Error if the tagname or ifdId is invalid
+ */
+ 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)
+ static const char* ifdItem(IfdId ifdId);
+ //! Return the name of the section
+ static const char* sectionName(SectionId sectionId);
+ /*!
+ @brief Return the name of the section for a combination of
+ tag and IFD id.
+ @param tag The tag
+ @param ifdId IFD id
+ @return The name of the section or a string indicating that the
+ section or the tag is unknown.
+ */
+ static const char* sectionName(uint16_t tag, IfdId ifdId);
+ /*!
+ @brief Return the description of the section for a combination of
+ tag and IFD id.
+ @param tag The tag
+ @param ifdId IFD id
+ @return The description of the section or a string indicating that
+ the section or the tag is unknown.
+ */
+ static const char* sectionDesc(uint16_t tag, IfdId ifdId);
+ //! Return the section id for a section name
+ static SectionId sectionId(const std::string& sectionName);
+ //! Return the type for tag and IFD id
+ static TypeId tagType(uint16_t tag, IfdId ifdId);
+ //! Interpret and print the value of an Exif tag
+ static std::ostream& printTag(std::ostream& os,
+ uint16_t tag,
+ IfdId ifdId,
+ const Value& value);
+ //! Print a list of all standard Exif tags to output stream
+ static void taglist(std::ostream& os);
+ //! Print a list of all tags related to one makernote %IfdId
+ static void makerTaglist(std::ostream& os, IfdId ifdId);
+ //! Register an %IfdId with the base IFD %TagInfo list for a makernote
+ static void registerBaseTagInfo(IfdId ifdId);
+ /*!
+ @brief Register an %IfdId and %TagInfo list for a makernote
+
+ @throw Error if the MakerTagInfo registry is full
+ */
+ static void registerMakerTagInfo(IfdId ifdId, const TagInfo* tagInfo);
+ /*!
+ @brief Return true if \em ifdId is an %Ifd Id which is registered
+ as a makernote %Ifd id. Note: Calling this function with
+ makerIfd returns false.
+ */
+ static bool isMakerIfd(IfdId ifdId);
+
+ private:
+ static int tagInfoIdx(uint16_t tag, IfdId ifdId);
+ static const TagInfo* makerTagInfo(uint16_t tag, IfdId ifdId);
+ static const TagInfo* makerTagInfo(const std::string& tagName,
+ IfdId ifdId);
+
+ static const IfdInfo ifdInfo_[];
+ static const SectionInfo sectionInfo_[];
+
+ static const TagInfo* tagInfos_[];
+
+ static const int MAX_MAKER_TAG_INFOS = 64;
+ static const TagInfo* makerTagInfos_[MAX_MAKER_TAG_INFOS];
+ static IfdId makerIfdIds_[MAX_MAKER_TAG_INFOS];
+
+ }; // class ExifTags
+
+ /*!
+ @brief Concrete keys for Exif metadata.
+ */
+ class ExifKey : public Key {
+ public:
+ //! Shortcut for an %ExifKey auto pointer.
+ typedef std::auto_ptr<ExifKey> AutoPtr;
+
+ //! @name Creators
+ //@{
+ /*!
+ @brief Constructor to create an Exif key from a key string.
+
+ @param key The key string.
+ @throw Error if the first part of the key is not '<b>Exif</b>' or
+ the remainin parts of the key cannot be parsed and
+ converted to an ifd-item and tag name.
+ */
+ 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 if the key cannot be constructed from the tag and IFD
+ item parameters.
+ */
+ ExifKey(uint16_t tag, const std::string& ifdItem);
+ //! Constructor to build an ExifKey from an IFD entry.
+ explicit ExifKey(const Entry& e);
+ //! Copy constructor
+ ExifKey(const ExifKey& rhs);
+ virtual ~ExifKey();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Assignment operator.
+ */
+ ExifKey& operator=(const ExifKey& rhs);
+ //@}
+
+ //! @name Accessors
+ //@{
+ virtual std::string key() const { return key_; }
+ virtual const char* familyName() const { return familyName_; }
+ /*!
+ @brief Return the name of the group (the second part of the key).
+ For Exif keys, the group name is the IFD item.
+ */
+ virtual std::string groupName() const { return ifdItem(); }
+ virtual std::string tagName() const;
+ virtual uint16_t tag() const { return tag_; }
+
+ AutoPtr clone() const;
+ //! Return the IFD id
+ IfdId ifdId() const { return ifdId_; }
+ //! Return the name of the IFD
+ const char* ifdName() const { return ExifTags::ifdName(ifdId()); }
+ //! Return the related image item
+ std::string ifdItem() const { return ifdItem_; }
+ //! Return the name of the Exif section (deprecated)
+ std::string sectionName() const;
+ //! Return the index (unique id of this key within the original IFD)
+ int idx() const { return idx_; }
+ //@}
+
+ protected:
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Set the key corresponding to the tag and IFD id.
+ The key is of the form '<b>Exif</b>.ifdItem.tagName'.
+ */
+ void makeKey();
+ /*!
+ @brief Parse and convert the key string into tag and IFD Id.
+ Updates data members if the string can be decomposed,
+ or throws \em Error .
+
+ @throw Error if the key cannot be decomposed.
+ */
+ void decomposeKey();
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual ExifKey* clone_() const;
+
+ // DATA
+ static const char* familyName_;
+
+ uint16_t tag_; //!< Tag value
+ IfdId ifdId_; //!< The IFD associated with this tag
+ std::string ifdItem_; //!< The IFD item
+ int idx_; //!< Unique id of an entry within one
IFD
+ std::string key_; //!< Key
+ }; // class ExifKey
+
+//
*****************************************************************************
+// free functions
+
+ /*!
+ @brief Return true if \em ifdId is an Exif %Ifd Id, i.e., one of
+ ifd0Id, exifIfdId, gpsIfdId, iopIfdId or ifd1Id, else false.
+ This is used to differentiate between standard Exif %Ifds
+ and %Ifds associated with the makernote.
+ */
+ bool isExifIfd(IfdId ifdId);
+
+ //! Output operator for TagInfo
+ std::ostream& operator<<(std::ostream& os, const TagInfo& ti);
+
+ //! @name Functions printing interpreted tag values
+ //@{
+ //! Default print function, using the Value output operator
+ std::ostream& printValue(std::ostream& os, const Value& value);
+ //! Print the value converted to a long
+ std::ostream& printLong(std::ostream& os, const Value& value);
+ //! Print a Rational or URational value in floating point format
+ std::ostream& printFloat(std::ostream& os, const Value& value);
+ //! Print the unit for measuring X and Y resolution
+ std::ostream& printUnit(std::ostream& os, const Value& value);
+
+ //! Print the compression scheme used for the image data
+ std::ostream& print0x0103(std::ostream& os, const Value& value);
+ //! Print the pixel composition
+ std::ostream& print0x0106(std::ostream& os, const Value& value);
+ //! Print the orientation
+ std::ostream& print0x0112(std::ostream& os, const Value& value);
+ //! Print the YCbCrPositioning
+ std::ostream& print0x0213(std::ostream& os, const Value& value);
+ //! Print the Copyright
+ std::ostream& print0x8298(std::ostream& os, const Value& value);
+ //! Print the Exposure time
+ std::ostream& print0x829a(std::ostream& os, const Value& value);
+ //! Print the F number
+ std::ostream& print0x829d(std::ostream& os, const Value& value);
+ //! Print the Exposure mode
+ std::ostream& print0x8822(std::ostream& os, const Value& value);
+ //! Print ISO speed ratings
+ std::ostream& print0x8827(std::ostream& os, const Value& value);
+ //! Print components configuration specific to compressed data
+ std::ostream& print0x9101(std::ostream& os, const Value& value);
+ //! Print the exposure bias value
+ std::ostream& print0x9204(std::ostream& os, const Value& value);
+ //! Print the subject distance
+ std::ostream& print0x9206(std::ostream& os, const Value& value);
+ //! Print the metering mode
+ std::ostream& print0x9207(std::ostream& os, const Value& value);
+ //! Print the light source
+ std::ostream& print0x9208(std::ostream& os, const Value& value);
+ //! Print the flash status
+ std::ostream& print0x9209(std::ostream& os, const Value& value);
+ //! Print the actual focal length of the lens
+ std::ostream& print0x920a(std::ostream& os, const Value& value);
+ //! Print the user comment
+ std::ostream& print0x9286(std::ostream& os, const Value& value);
+ //! Print color space information
+ std::ostream& print0xa001(std::ostream& os, const Value& value);
+ //! Print info on image sensor type on the camera or input device
+ std::ostream& print0xa217(std::ostream& os, const Value& value);
+ //! Print file source
+ std::ostream& print0xa300(std::ostream& os, const Value& value);
+ //! Print scene type
+ std::ostream& print0xa301(std::ostream& os, const Value& value);
+ //! Print the exposure mode
+ std::ostream& print0xa402(std::ostream& os, const Value& value);
+ //! Print white balance information
+ std::ostream& print0xa403(std::ostream& os, const Value& value);
+ //! Print digital zoom ratio
+ std::ostream& print0xa404(std::ostream& os, const Value& value);
+ //! Print 35mm equivalent focal length
+ std::ostream& print0xa405(std::ostream& os, const Value& value);
+ //! Print scene capture type
+ std::ostream& print0xa406(std::ostream& os, const Value& value);
+ //! Print overall image gain adjustment
+ std::ostream& print0xa407(std::ostream& os, const Value& value);
+ //! Print contract adjustment
+ std::ostream& print0xa408(std::ostream& os, const Value& value);
+ //! Print saturation adjustment
+ std::ostream& print0xa409(std::ostream& os, const Value& value);
+ //! Print sharpness adjustment
+ std::ostream& print0xa40a(std::ostream& os, const Value& value);
+ //! Print subject distance range
+ std::ostream& print0xa40c(std::ostream& os, const Value& value);
+ //@}
+} // namespace Exiv2
+
+#endif // #ifndef TAGS_HPP_
Added: Extractor/src/plugins/exiv2/types.cpp
===================================================================
--- Extractor/src/plugins/exiv2/types.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/types.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,343 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: types.cpp
+ Version: $Rev: 578 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: types.cpp 578 2005-06-07 15:01:11Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <utility>
+#include <cctype>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ TypeInfoTable::TypeInfoTable(TypeId typeId, const char* name, long size)
+ : typeId_(typeId), name_(name), size_(size)
+ {
+ }
+
+ //! Lookup list of supported IFD type information
+ const TypeInfoTable TypeInfo::typeInfoTable_[] = {
+ TypeInfoTable(invalidTypeId, "Invalid", 0),
+ TypeInfoTable(unsignedByte, "Byte", 1),
+ TypeInfoTable(asciiString, "Ascii", 1),
+ TypeInfoTable(unsignedShort, "Short", 2),
+ TypeInfoTable(unsignedLong, "Long", 4),
+ TypeInfoTable(unsignedRational, "Rational", 8),
+ TypeInfoTable(invalid6, "Invalid(6)", 1),
+ TypeInfoTable(undefined, "Undefined", 1),
+ TypeInfoTable(signedShort, "SShort", 2),
+ TypeInfoTable(signedLong, "SLong", 4),
+ TypeInfoTable(signedRational, "SRational", 8),
+ TypeInfoTable(string, "String", 1),
+ TypeInfoTable(date, "Date", 8),
+ TypeInfoTable(time, "Time", 11),
+ TypeInfoTable(comment, "Comment", 1),
+ // End of list marker
+ TypeInfoTable(lastTypeId, "(Unknown)", 0)
+ };
+
+ const char* TypeInfo::typeName(TypeId typeId)
+ {
+ return typeInfoTable_[ typeId < lastTypeId ? typeId : 0 ].name_;
+ }
+
+ TypeId TypeInfo::typeId(const std::string& typeName)
+ {
+ int i = 0;
+ for (; typeInfoTable_[i].typeId_ != lastTypeId
+ && typeInfoTable_[i].name_ != typeName; ++i) {}
+ return typeInfoTable_[i].typeId_ == lastTypeId ?
+ invalidTypeId : typeInfoTable_[i].typeId_;
+ }
+
+ long TypeInfo::typeSize(TypeId typeId)
+ {
+ return typeInfoTable_[ typeId < lastTypeId ? typeId : 0 ].size_;
+ }
+
+ DataBuf::DataBuf(DataBuf& rhs)
+ : pData_(rhs.pData_), size_(rhs.size_)
+ {
+ rhs.release();
+ }
+
+ DataBuf::DataBuf(byte* pData, long size)
+ : pData_(0), size_(0)
+ {
+ if (size > 0) {
+ pData_ = new byte[size];
+ memcpy(pData_, pData, size);
+ size_ = size;
+ }
+ }
+
+ DataBuf& DataBuf::operator=(DataBuf& rhs)
+ {
+ if (this == &rhs) return *this;
+ reset(rhs.release());
+ return *this;
+ }
+
+ void DataBuf::alloc(long size)
+ {
+ if (size > size_) {
+ delete[] pData_;
+ size_ = size;
+ pData_ = new byte[size];
+ }
+ }
+
+ std::pair<byte*, long> DataBuf::release()
+ {
+ std::pair<byte*, long> p = std::make_pair(pData_, size_);
+ pData_ = 0;
+ size_ = 0;
+ return p;
+ }
+
+ void DataBuf::reset(std::pair<byte*, long> p)
+ {
+ if (pData_ != p.first) {
+ delete[] pData_;
+ pData_ = p.first;
+ }
+ size_ = p.second;
+ }
+
+ //
*************************************************************************
+ // free functions
+
+ uint16_t getUShort(const byte* buf, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ return (byte)buf[1] << 8 | (byte)buf[0];
+ }
+ else {
+ return (byte)buf[0] << 8 | (byte)buf[1];
+ }
+ }
+
+ uint32_t getULong(const byte* buf, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ return (byte)buf[3] << 24 | (byte)buf[2] << 16
+ | (byte)buf[1] << 8 | (byte)buf[0];
+ }
+ else {
+ return (byte)buf[0] << 24 | (byte)buf[1] << 16
+ | (byte)buf[2] << 8 | (byte)buf[3];
+ }
+ }
+
+ URational getURational(const byte* buf, ByteOrder byteOrder)
+ {
+ uint32_t nominator = getULong(buf, byteOrder);
+ uint32_t denominator = getULong(buf + 4, byteOrder);
+ return std::make_pair(nominator, denominator);
+ }
+
+ int16_t getShort(const byte* buf, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ return (byte)buf[1] << 8 | (byte)buf[0];
+ }
+ else {
+ return (byte)buf[0] << 8 | (byte)buf[1];
+ }
+ }
+
+ int32_t getLong(const byte* buf, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ return (byte)buf[3] << 24 | (byte)buf[2] << 16
+ | (byte)buf[1] << 8 | (byte)buf[0];
+ }
+ else {
+ return (byte)buf[0] << 24 | (byte)buf[1] << 16
+ | (byte)buf[2] << 8 | (byte)buf[3];
+ }
+ }
+
+ Rational getRational(const byte* buf, ByteOrder byteOrder)
+ {
+ int32_t nominator = getLong(buf, byteOrder);
+ int32_t denominator = getLong(buf + 4, byteOrder);
+ return std::make_pair(nominator, denominator);
+ }
+
+ long us2Data(byte* buf, uint16_t s, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ buf[0] = (byte)(s & 0x00ff);
+ buf[1] = (byte)((s & 0xff00) >> 8);
+ }
+ else {
+ buf[0] = (byte)((s & 0xff00) >> 8);
+ buf[1] = (byte)(s & 0x00ff);
+ }
+ return 2;
+ }
+
+ long ul2Data(byte* buf, uint32_t l, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ buf[0] = (byte)(l & 0x000000ff);
+ buf[1] = (byte)((l & 0x0000ff00) >> 8);
+ buf[2] = (byte)((l & 0x00ff0000) >> 16);
+ buf[3] = (byte)((l & 0xff000000) >> 24);
+ }
+ else {
+ buf[0] = (byte)((l & 0xff000000) >> 24);
+ buf[1] = (byte)((l & 0x00ff0000) >> 16);
+ buf[2] = (byte)((l & 0x0000ff00) >> 8);
+ buf[3] = (byte)(l & 0x000000ff);
+ }
+ return 4;
+ }
+
+ long ur2Data(byte* buf, URational l, ByteOrder byteOrder)
+ {
+ long o = ul2Data(buf, l.first, byteOrder);
+ o += ul2Data(buf+o, l.second, byteOrder);
+ return o;
+ }
+
+ long s2Data(byte* buf, int16_t s, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ buf[0] = (byte)(s & 0x00ff);
+ buf[1] = (byte)((s & 0xff00) >> 8);
+ }
+ else {
+ buf[0] = (byte)((s & 0xff00) >> 8);
+ buf[1] = (byte)(s & 0x00ff);
+ }
+ return 2;
+ }
+
+ long l2Data(byte* buf, int32_t l, ByteOrder byteOrder)
+ {
+ if (byteOrder == littleEndian) {
+ buf[0] = (byte)(l & 0x000000ff);
+ buf[1] = (byte)((l & 0x0000ff00) >> 8);
+ buf[2] = (byte)((l & 0x00ff0000) >> 16);
+ buf[3] = (byte)((l & 0xff000000) >> 24);
+ }
+ else {
+ buf[0] = (byte)((l & 0xff000000) >> 24);
+ buf[1] = (byte)((l & 0x00ff0000) >> 16);
+ buf[2] = (byte)((l & 0x0000ff00) >> 8);
+ buf[3] = (byte)(l & 0x000000ff);
+ }
+ return 4;
+ }
+
+ long r2Data(byte* buf, Rational l, ByteOrder byteOrder)
+ {
+ long o = l2Data(buf, l.first, byteOrder);
+ o += l2Data(buf+o, l.second, byteOrder);
+ return o;
+ }
+
+ void hexdump(std::ostream& os, const byte* buf, long len, long offset)
+ {
+ const std::string::size_type pos = 8 + 16 * 3 + 2;
+ const std::string align(pos, ' ');
+
+ long i = 0;
+ while (i < len) {
+ os << " "
+ << std::setw(4) << std::setfill('0') << std::hex
+ << i + offset << " ";
+ std::ostringstream ss;
+ do {
+ byte c = buf[i];
+ os << std::setw(2) << std::setfill('0') << std::right
+ << std::hex << (int)c << " ";
+ ss << ((int)c >= 31 && (int)c < 127 ? char(buf[i]) : '.');
+ } while (++i < len && i%16 != 0);
+ std::string::size_type width = 9 + ((i-1)%16 + 1) * 3;
+ os << (width > pos ? "" : align.substr(width)) << ss.str() << "\n";
+ }
+ os << std::dec << std::setfill(' ');
+ } // hexdump
+
+ int gcd(int a, int b)
+ {
+ int temp;
+ if (a < b) {
+ temp = a;
+ a = b;
+ b = temp;
+ }
+ while ((temp = a % b) != 0) {
+ a = b;
+ b = temp;
+ }
+ return b;
+ } // gcd
+
+ long lgcd(long a, long b)
+ {
+ long temp;
+ if (a < b) {
+ temp = a;
+ a = b;
+ b = temp;
+ }
+ while ((temp = a % b) != 0) {
+ a = b;
+ b = temp;
+ }
+ return b;
+ } // lgcd
+
+ bool isHex(const std::string& str, size_t size, const std::string& prefix)
+ {
+ if ( str.size() <= prefix.size()
+ || str.substr(0, prefix.size()) != prefix) return false;
+ if ( size > 0
+ && str.size() != size + prefix.size()) return false;
+
+ for (size_t i = prefix.size(); i < str.size(); ++i) {
+ if (!isxdigit(str[i])) return false;
+ }
+ return true;
+ } // isHex
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/types.hpp
===================================================================
--- Extractor/src/plugins/exiv2/types.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/types.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,307 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file types.hpp
+ @brief Type definitions for %Exiv2 and related functionality
+ @version $Rev: 581 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created<BR>
+ 11-Feb-04, ahu: isolated as a component
+ 31-Jul-04, brad: added Time, Data and String values
+ */
+#ifndef TYPES_HPP_
+#define TYPES_HPP_
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+// + standard includes
+#include <string>
+#include <iosfwd>
+#include <utility>
+#include <sstream>
+#include <cstdio>
+#ifdef EXV_HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+// MSVC doesn't provide C99 types, but it has MS specific variants
+#ifdef _MSC_VER
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+#endif
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// type definitions
+
+ //! 1 byte unsigned integer type.
+ typedef uint8_t byte;
+
+ //! 8 byte unsigned rational type.
+ typedef std::pair<uint32_t, uint32_t> URational;
+ //! 8 byte signed rational type.
+ typedef std::pair<int32_t, int32_t> Rational;
+
+ //! Type to express the byte order (little or big endian)
+ enum ByteOrder { invalidByteOrder, littleEndian, bigEndian };
+
+ //! Type identifiers for IFD format types
+ enum TypeId { invalidTypeId, unsignedByte, asciiString, unsignedShort,
+ unsignedLong, unsignedRational, invalid6, undefined,
+ signedShort, signedLong, signedRational,
+ string, date, time,
+ comment,
+ lastTypeId };
+
+ // Todo: decentralize IfdId, so that new ids can be defined elsewhere
+ //! Type to specify the IFD to which a metadata belongs
+ enum IfdId { ifdIdNotSet,
+ ifd0Id, exifIfdId, gpsIfdId, iopIfdId, ifd1Id,
+ canonIfdId, canonCs1IfdId, canonCs2IfdId, canonCfIfdId,
+ fujiIfdId, nikon1IfdId, nikon2IfdId, nikon3IfdId,
+ olympusIfdId, panasonicIfdId, sigmaIfdId, sonyIfdId,
+ lastIfdId };
+
+//
*****************************************************************************
+// class definitions
+
+ //! Information pertaining to the defined types
+ struct TypeInfoTable {
+ //! Constructor
+ TypeInfoTable(TypeId typeId, const char* name, long size);
+ TypeId typeId_; //!< Type id
+ const char* name_; //!< Name of the type
+ long size_; //!< Bytes per data entry
+ }; // struct TypeInfoTable
+
+ //! Type information lookup functions. Implemented as a static class.
+ class TypeInfo {
+ //! Prevent construction: not implemented.
+ TypeInfo() {}
+ //! Prevent copy-construction: not implemented.
+ TypeInfo(const TypeInfo& rhs);
+ //! Prevent assignment: not implemented.
+ TypeInfo& operator=(const TypeInfo& rhs);
+
+ public:
+ //! Return the name of the type
+ static const char* typeName(TypeId typeId);
+ //! Return the type id for a type name
+ static TypeId typeId(const std::string& typeName);
+ //! Return the size in bytes of one element of this type
+ static long typeSize(TypeId typeId);
+
+ private:
+ static const TypeInfoTable typeInfoTable_[];
+ };
+
+ /*!
+ @brief Auxiliary type to enable copies and assignments, similar to
+ std::auto_ptr_ref. See
http://www.josuttis.com/libbook/auto_ptr.html
+ for a discussion.
+ */
+ struct DataBufRef {
+ //! Constructor
+ DataBufRef(std::pair<byte*, long> rhs) : p(rhs) {}
+ //! Pointer to a byte array and its size
+ std::pair<byte*, long> p;
+ };
+
+ /*!
+ @brief Utility class containing a character array. All it does is to take
+ care of memory allocation and deletion. Its primary use is meant
to
+ be as a stack variable in functions that need a temporary data
+ buffer. Todo: this should be some sort of smart pointer,
+ essentially an std::auto_ptr for a character array. But it
isn't...
+ */
+ class DataBuf {
+ public:
+ //! @name Creators
+ //@{
+ //! Default constructor
+ DataBuf() : pData_(0), size_(0) {}
+ //! Constructor with an initial buffer size
+ explicit DataBuf(long size) : pData_(new byte[size]), size_(size) {}
+ //! Constructor, copies an existing buffer
+ DataBuf(byte* pData, long size);
+ /*!
+ @brief Copy constructor. Transfers the buffer to the newly created
+ object similar to std::auto_ptr, i.e., the original object is
+ modified.
+ */
+ DataBuf(DataBuf& rhs);
+ //! Destructor, deletes the allocated buffer
+ ~DataBuf() { delete[] pData_; }
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Assignment operator. Transfers the buffer and releases the
+ buffer at the original object similar to std::auto_ptr, i.e.,
+ the original object is modified.
+ */
+ DataBuf& operator=(DataBuf& rhs);
+ //! Allocate a data buffer of the given size
+ void alloc(long size);
+ /*!
+ @brief Release ownership of the buffer to the caller. Returns the
+ buffer as a data pointer and size pair, resets the internal
+ buffer.
+ */
+ std::pair<byte*, long> release();
+ //! Reset value
+ void reset(std::pair<byte*, long> =std::make_pair(0,0));
+ //@}
+
+ /*!
+ @name Conversions
+
+ Special conversions with auxiliary type to enable copies
+ and assignments, similar to those used for std::auto_ptr.
+ See http://www.josuttis.com/libbook/auto_ptr.html for a discussion.
+ */
+ //@{
+ DataBuf(DataBufRef rhs) : pData_(rhs.p.first), size_(rhs.p.second) {}
+ DataBuf& operator=(DataBufRef rhs) { reset(rhs.p); return *this; }
+ operator DataBufRef() { return DataBufRef(release()); }
+ //@}
+
+ // DATA
+ //! Pointer to the buffer, 0 if none has been allocated
+ byte* pData_;
+ //! The current size of the buffer
+ long size_;
+ }; // class DataBuf
+
+
+//
*****************************************************************************
+// free functions
+
+ //! Read a 2 byte unsigned short value from the data buffer
+ uint16_t getUShort(const byte* buf, ByteOrder byteOrder);
+ //! Read a 4 byte unsigned long value from the data buffer
+ uint32_t getULong(const byte* buf, ByteOrder byteOrder);
+ //! Read an 8 byte unsigned rational value from the data buffer
+ URational getURational(const byte* buf, ByteOrder byteOrder);
+ //! Read a 2 byte signed short value from the data buffer
+ int16_t getShort(const byte* buf, ByteOrder byteOrder);
+ //! Read a 4 byte signed long value from the data buffer
+ int32_t getLong(const byte* buf, ByteOrder byteOrder);
+ //! Read an 8 byte signed rational value from the data buffer
+ Rational getRational(const byte* buf, ByteOrder byteOrder);
+
+ //! Output operator for our fake rational
+ std::ostream& operator<<(std::ostream& os, const Rational& r);
+ //! Input operator for our fake rational
+ std::istream& operator>>(std::istream& is, Rational& r);
+ //! Output operator for our fake unsigned rational
+ std::ostream& operator<<(std::ostream& os, const URational& r);
+ //! Input operator for our fake unsigned rational
+ std::istream& operator>>(std::istream& is, URational& r);
+
+ /*!
+ @brief Convert an unsigned short to data, write the data to the buffer,
+ return number of bytes written.
+ */
+ long us2Data(byte* buf, uint16_t s, ByteOrder byteOrder);
+ /*!
+ @brief Convert an unsigned long to data, write the data to the buffer,
+ return number of bytes written.
+ */
+ long ul2Data(byte* buf, uint32_t l, ByteOrder byteOrder);
+ /*!
+ @brief Convert an unsigned rational to data, write the data to the
buffer,
+ return number of bytes written.
+ */
+ long ur2Data(byte* buf, URational l, ByteOrder byteOrder);
+ /*!
+ @brief Convert a signed short to data, write the data to the buffer,
+ return number of bytes written.
+ */
+ long s2Data(byte* buf, int16_t s, ByteOrder byteOrder);
+ /*!
+ @brief Convert a signed long to data, write the data to the buffer,
+ return number of bytes written.
+ */
+ long l2Data(byte* buf, int32_t l, ByteOrder byteOrder);
+ /*!
+ @brief Convert a signed rational to data, write the data to the buffer,
+ return number of bytes written.
+ */
+ long r2Data(byte* buf, Rational l, ByteOrder byteOrder);
+
+ /*!
+ @brief Print len bytes from buf in hex and ASCII format to the given
+ stream, prefixed with the position in the buffer adjusted by
+ offset.
+ */
+ void hexdump(std::ostream& os, const byte* buf, long len, long offset =0);
+
+ /*!
+ @brief Return the greatest common denominator of integers a and b.
+ Both parameters must be greater than 0.
+ */
+ int gcd(int a, int b);
+
+ /*!
+ @brief Return the greatest common denominator of long values a and b.
+ Both parameters must be greater than 0.
+ */
+ long lgcd(long a, long b);
+
+ /*!
+ @brief Return true if str is a hex number starting with prefix followed
+ by size hex digits, false otherwise. If size is 0, any number of
+ digits is allowed and all are checked.
+ */
+ bool isHex(const std::string& str,
+ size_t size =0,
+ const std::string& prefix ="");
+
+//
*****************************************************************************
+// template and inline definitions
+
+ //! Utility function to convert the argument of any type to a string
+ template<typename T>
+ std::string toString(const T& arg)
+ {
+ std::ostringstream os;
+ os << arg;
+ return os.str();
+ }
+
+} // namespace Exiv2
+
+#endif // #ifndef TYPES_HPP_
Added: Extractor/src/plugins/exiv2/utils.cpp
===================================================================
--- Extractor/src/plugins/exiv2/utils.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/utils.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,141 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: utils.cpp
+ Version: $Rev: 560 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 08-Dec-03, ahu: created
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: utils.cpp 560 2005-04-17 11:51:32Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#ifdef _MSC_VER
+# include "exv_msvc.h"
+#else
+# include "exv_conf.h"
+#endif
+
+#include "utils.hpp"
+
+// + standard includes
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _MSC_VER
+# include "getopt_win32.h"
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifdef EXV_HAVE_UNISTD_H
+# include <unistd.h> // for getopt(), stat()
+#endif
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+namespace Util {
+
+//
*****************************************************************************
+// class Getopt
+int Getopt::getopt(int argc, char* const argv[], const std::string& optstring)
+{
+ progname_ = Util::basename(argv[0]);
+
+ for (;;) {
+ int c = ::getopt(argc, argv, optstring.c_str());
+ if (c == -1) break;
+ errcnt_ += option(c, ::optarg == 0 ? "" : ::optarg, ::optopt);
+ }
+ for (int i = ::optind; i < argc; i++) {
+ errcnt_ += nonoption(argv[i]);
+ }
+ return errcnt_;
+}
+
+//
*****************************************************************************
+// free functions
+
+ std::string dirname(const std::string& path)
+ {
+ if (path == "") return ".";
+ // Strip trailing slashes or backslashes
+ std::string p = path;
+ while ( p.length() > 1
+ && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) {
+ p = p.substr(0, p.length()-1);
+ }
+ if (p == "\\" || p == "/") return p;
+ if (p.length() == 2 && p[1] == ':') return p; // For Windows paths
+ std::string::size_type idx = p.find_last_of("\\/");
+ if (idx == std::string::npos) return ".";
+ if (idx == 1 && p[0] == '\\' && p[1] == '\\') return p; // For Windows
paths
+ p = p.substr(0, idx == 0 ? 1 : idx);
+ while ( p.length() > 1
+ && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) {
+ p = p.substr(0, p.length()-1);
+ }
+ return p;
+ }
+
+ std::string basename(const std::string& path, bool delsuffix)
+ {
+ if (path == "") return ".";
+ // Strip trailing slashes or backslashes
+ std::string p = path;
+ while ( p.length() > 1
+ && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) {
+ p = p.substr(0, p.length()-1);
+ }
+ if (p.length() == 2 && p[1] == ':') return ""; // For Windows paths
+ std::string::size_type idx = p.find_last_of("\\/");
+ if (idx == 1 && p[0] == '\\' && p[1] == '\\') return ""; // For
Windows paths
+ if (idx != std::string::npos) p = p.substr(idx+1);
+ if (delsuffix) p = p.substr(0, p.length() - suffix(p).length());
+ return p;
+ }
+
+ std::string suffix(const std::string& path)
+ {
+ std::string b = basename(path);
+ std::string::size_type idx = b.rfind('.');
+ if (idx == std::string::npos || idx == 0 || idx == b.length()-1) {
+ return "";
+ }
+ return b.substr(idx);
+ }
+
+ bool strtol(const char* nptr, long& n)
+ {
+ if (!nptr || *nptr == '\0') return false;
+ char* endptr = 0;
+ long tmp = ::strtol(nptr, &endptr, 10);
+ if (*endptr != '\0') return false;
+ if (tmp == LONG_MAX || tmp == LONG_MIN) return false;
+ n = tmp;
+ return true;
+ }
+
+} // namespace Util
Added: Extractor/src/plugins/exiv2/utils.hpp
===================================================================
--- Extractor/src/plugins/exiv2/utils.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/utils.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,165 @@
+// ********************************************************* -*- C++ -*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file utils.hpp
+ @brief A collection of utility functions
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 12-Dec-03, ahu: created
+ */
+#ifndef UTILS_HPP_
+#define UTILS_HPP_
+
+// *********************************************************************
+// included header files
+// + standard includes
+#include <string>
+
+// *********************************************************************
+// namespace extensions
+/*!
+ @brief Contains utility classes and functions. Most of these are
+ wrappers for common C functions that do not require pointers
+ and memory considerations.
+*/
+namespace Util {
+
+// *********************************************************************
+// class definitions
+
+/*!
+ @brief Parse the command line options of a program.
+
+ A wrapper around the POSIX %getopt(3) function. Parses the command line
+ options and passes each option to virtual option(). A derived class
+ implements this method to handle options as needed. Similarly,
+ remaining non-option parameters are passed to the virtual nonoption()
+ method.
+ */
+class Getopt {
+public:
+ //! Default constructor.
+ Getopt() : errcnt_(0) {}
+
+ //! Destructor.
+ virtual ~Getopt() {}
+
+ /*!
+ @brief Parse command line arguments.
+
+ Parses the command line arguments. Calls option() with the
+ character value of the option and its argument (if any) for each
+ recognized option and with ':' or '?' for unrecognized options.
+ See the manual pages for %getopt(3) for details. In addition,
+ nonoption() is invoked for each remaining non-option parameter on
+ the command line.
+
+ @param argc Argument count as passed to main() on program invocation.
+ @param argv Argument array as passed to main() on program invocation.
+ @param optstring String containing the legitimate option characters.
+
+ @return Number of errors (the sum of the return values from option()
+ and nonoption()).
+ */
+ int getopt(int argc, char* const argv[], const std::string& optstring);
+
+ /*!
+ @brief Callback used by getopt() to pass on each option and its
+ argument (if any).
+
+ Implement this method in a derived class to handle the options as
+ needed. See the manual pages for %getopt(3) for further details, in
+ particular, the semantics of optarg and optopt.
+
+ @param opt Value of the option character as returned by %getopt(3).
+ @param optarg The corresponding option argument.
+ @param optopt The actual option character in case of an unrecognized
+ option or a missing option argument (opt is '?' or ':').
+
+ @return 0 if successful, 1 in case of an error.
+ */
+ virtual int option(int opt, const std::string& optarg, int optopt) = 0;
+
+ /*!
+ @brief Callback used by getopt() to pass on each non-option parameter
+ found on the command line.
+
+ Implement this method in a derived class to handle the non-option
+ parameters as needed. The default implementation ignores all non-option
+ parameters.
+
+ @param argv The non-option parameter from the command line.
+
+ @return 0 if successful, 1 in case of an error.
+ */
+ virtual int nonoption(const std::string& argv) { return 0; }
+
+ //! Program name (argv[0])
+ const std::string& progname() const { return progname_; }
+
+ //! Total number of errors returned by calls to option()
+ int errcnt() const { return errcnt_; }
+
+private:
+ std::string progname_;
+ int errcnt_;
+};
+
+// *********************************************************************
+// free functions
+
+ /*!
+ @brief Get the directory component from the \em path string.
+ See %dirname(3).
+
+ This function can handle Windows paths to some extent: c:\\bar should
+ be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work.
+ */
+ std::string dirname(const std::string& path);
+
+ /*!
+ @brief Get the filename component from the \em path string.
+ See %basename(3). If the \em delsuffix parameter is true,
+ the suffix will be removed.
+
+ This function can handle Windows paths to some extent: c:\\bar should
+ be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work.
+ */
+ std::string basename(const std::string& path, bool delsuffix =false);
+
+ /*!
+ @brief Get the suffix from the path string. Normally, the suffix
+ is the substring of the basename of path from the last '.'
+ to the end of the string.
+ */
+ std::string suffix(const std::string& path);
+
+ /*!
+ @brief Convert a C string to a long value, which is returned in n.
+ Returns true if the conversion is successful, else false.
+ n is not modified if the conversion is unsuccessful. See
strtol(2).
+ */
+ bool strtol(const char* nptr, long& n);
+
+} // namespace Util
+
+#endif // #ifndef UTILS_HPP_
Added: Extractor/src/plugins/exiv2/value.cpp
===================================================================
--- Extractor/src/plugins/exiv2/value.cpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/value.cpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,557 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ File: value.cpp
+ Version: $Rev: 560 $
+ Author(s): Andreas Huggel (ahu) <address@hidden>
+ History: 26-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ 31-Jul-04, brad: added Time, Date and String values
+ */
+//
*****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Id: value.cpp 560 2005-04-17 11:51:32Z ahuggel $");
+
+//
*****************************************************************************
+// included header files
+#include "value.hpp"
+#include "types.hpp"
+#include "error.hpp"
+
+// + standard includes
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <cassert>
+#include <ctime>
+
+//
*****************************************************************************
+// class member definitions
+namespace Exiv2 {
+
+ Value& Value::operator=(const Value& rhs)
+ {
+ if (this == &rhs) return *this;
+ type_ = rhs.type_;
+ return *this;
+ }
+
+ Value::AutoPtr Value::create(TypeId typeId)
+ {
+ AutoPtr value;
+ switch (typeId) {
+ case invalidTypeId:
+ value = AutoPtr(new DataValue(invalidTypeId));
+ break;
+ case unsignedByte:
+ value = AutoPtr(new DataValue(unsignedByte));
+ break;
+ case asciiString:
+ value = AutoPtr(new AsciiValue);
+ break;
+ case unsignedShort:
+ value = AutoPtr(new ValueType<uint16_t>);
+ break;
+ case unsignedLong:
+ value = AutoPtr(new ValueType<uint32_t>);
+ break;
+ case unsignedRational:
+ value = AutoPtr(new ValueType<URational>);
+ break;
+ case invalid6:
+ value = AutoPtr(new DataValue(invalid6));
+ break;
+ case undefined:
+ value = AutoPtr(new DataValue);
+ break;
+ case signedShort:
+ value = AutoPtr(new ValueType<int16_t>);
+ break;
+ case signedLong:
+ value = AutoPtr(new ValueType<int32_t>);
+ break;
+ case signedRational:
+ value = AutoPtr(new ValueType<Rational>);
+ break;
+ case string:
+ value = AutoPtr(new StringValue);
+ break;
+ case date:
+ value = AutoPtr(new DateValue);
+ break;
+ case time:
+ value = AutoPtr(new TimeValue);
+ break;
+ case comment:
+ value = AutoPtr(new CommentValue);
+ break;
+ default:
+ value = AutoPtr(new DataValue(typeId));
+ break;
+ }
+ return value;
+ } // Value::create
+
+ std::string Value::toString() const
+ {
+ std::ostringstream os;
+ write(os);
+ return os.str();
+ }
+
+ DataValue& DataValue::operator=(const DataValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ Value::operator=(rhs);
+ value_ = rhs.value_;
+ return *this;
+ }
+
+ void DataValue::read(const byte* buf, long len, ByteOrder byteOrder)
+ {
+ // byteOrder not needed
+ value_.assign(buf, buf + len);
+ }
+
+ void DataValue::read(const std::string& buf)
+ {
+ std::istringstream is(buf);
+ int tmp;
+ value_.clear();
+ while (is >> tmp) {
+ value_.push_back(static_cast<byte>(tmp));
+ }
+ }
+
+ long DataValue::copy(byte* buf, ByteOrder byteOrder) const
+ {
+ // byteOrder not needed
+ return static_cast<long>(
+ std::copy(value_.begin(), value_.end(), buf) - buf
+ );
+ }
+
+ long DataValue::size() const
+ {
+ return static_cast<long>(value_.size());
+ }
+
+ DataValue* DataValue::clone_() const
+ {
+ return new DataValue(*this);
+ }
+
+ std::ostream& DataValue::write(std::ostream& os) const
+ {
+ std::vector<byte>::size_type end = value_.size();
+ for (std::vector<byte>::size_type i = 0; i != end; ++i) {
+ os << static_cast<int>(value_[i]) << " ";
+ }
+ return os;
+ }
+
+ StringValueBase& StringValueBase::operator=(const StringValueBase& rhs)
+ {
+ if (this == &rhs) return *this;
+ Value::operator=(rhs);
+ value_ = rhs.value_;
+ return *this;
+ }
+
+ void StringValueBase::read(const std::string& buf)
+ {
+ value_ = buf;
+ }
+
+ void StringValueBase::read(const byte* buf, long len, ByteOrder byteOrder)
+ {
+ // byteOrder not needed
+ value_ = std::string(reinterpret_cast<const char*>(buf), len);
+ }
+
+ long StringValueBase::copy(byte* buf, ByteOrder byteOrder) const
+ {
+ // byteOrder not needed
+ return static_cast<long>(
+ value_.copy(reinterpret_cast<char*>(buf), value_.size())
+ );
+ }
+
+ long StringValueBase::size() const
+ {
+ return static_cast<long>(value_.size());
+ }
+
+ std::ostream& StringValueBase::write(std::ostream& os) const
+ {
+ return os << value_;
+ }
+
+ StringValue& StringValue::operator=(const StringValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ StringValueBase::operator=(rhs);
+ return *this;
+ }
+
+ StringValue* StringValue::clone_() const
+ {
+ return new StringValue(*this);
+ }
+
+ AsciiValue& AsciiValue::operator=(const AsciiValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ StringValueBase::operator=(rhs);
+ return *this;
+ }
+
+ void AsciiValue::read(const std::string& buf)
+ {
+ value_ = buf;
+ if (value_[value_.size()-1] != '\0') value_ += '\0';
+ }
+
+ AsciiValue* AsciiValue::clone_() const
+ {
+ return new AsciiValue(*this);
+ }
+
+ std::ostream& AsciiValue::write(std::ostream& os) const
+ {
+ // Strip all trailing '\0's (if any)
+ std::string::size_type pos = value_.find_last_not_of('\0');
+ return os << value_.substr(0, pos + 1);
+ }
+
+ CommentValue::CharsetTable::CharsetTable(CharsetId charsetId,
+ const char* name,
+ const char* code)
+ : charsetId_(charsetId), name_(name), code_(code)
+ {
+ }
+
+ //! Lookup list of supported IFD type information
+ const CommentValue::CharsetTable
CommentValue::CharsetInfo::charsetTable_[] = {
+ CharsetTable(ascii, "Ascii", "ASCII\0\0\0"),
+ CharsetTable(jis, "Jis", "JIS\0\0\0\0\0"),
+ CharsetTable(unicode, "Unicode", "UNICODE\0"),
+ CharsetTable(undefined, "Undefined", "\0\0\0\0\0\0\0\0"),
+ CharsetTable(invalidCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0"),
+ CharsetTable(lastCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0")
+ };
+
+ const char* CommentValue::CharsetInfo::name(CharsetId charsetId)
+ {
+ return charsetTable_[ charsetId < lastCharsetId ? charsetId :
undefined ].name_;
+ }
+
+ const char* CommentValue::CharsetInfo::code(CharsetId charsetId)
+ {
+ return charsetTable_[ charsetId < lastCharsetId ? charsetId :
undefined ].code_;
+ }
+
+ CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByName(
+ const std::string& name)
+ {
+ int i = 0;
+ for (; charsetTable_[i].charsetId_ != lastCharsetId
+ && charsetTable_[i].name_ != name; ++i) {}
+ return charsetTable_[i].charsetId_ == lastCharsetId ?
+ invalidCharsetId : charsetTable_[i].charsetId_;
+ }
+
+ CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByCode(
+ const std::string& code)
+ {
+ int i = 0;
+ for (; charsetTable_[i].charsetId_ != lastCharsetId
+ && std::string(charsetTable_[i].code_, 8) != code; ++i) {}
+ return charsetTable_[i].charsetId_ == lastCharsetId ?
+ invalidCharsetId : charsetTable_[i].charsetId_;
+ }
+
+ CommentValue::CommentValue(const std::string& comment)
+ : StringValueBase(Exiv2::undefined)
+ {
+ read(comment);
+ }
+
+ CommentValue& CommentValue::operator=(const CommentValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ StringValueBase::operator=(rhs);
+ return *this;
+ }
+
+ void CommentValue::read(const std::string& comment)
+ {
+ std::string c = comment;
+ CharsetId charsetId = undefined;
+ if (comment.length() > 8 && comment.substr(0, 8) == "charset=") {
+ std::string::size_type pos = comment.find_first_of(' ');
+ std::string name = comment.substr(8, pos-8);
+ // Strip quotes (so you can also to specify the charset without
quotes)
+ if (name[0] == '"') name = name.substr(1);
+ if (name[name.length()-1] == '"') name = name.substr(0,
name.length()-1);
+ charsetId = CharsetInfo::charsetIdByName(name);
+ if (charsetId == invalidCharsetId) throw Error(28, name);
+ c.clear();
+ if (pos != std::string::npos) c = comment.substr(pos+1);
+ }
+ const std::string code(CharsetInfo::code(charsetId), 8);
+ StringValueBase::read(code + c);
+ }
+
+ std::ostream& CommentValue::write(std::ostream& os) const
+ {
+ CharsetId charsetId = this->charsetId();
+ if (charsetId != undefined) {
+ os << "charset=\"" << CharsetInfo::name(charsetId) << "\" ";
+ }
+ return os << comment();
+ }
+
+ std::string CommentValue::comment() const
+ {
+ if (value_.length() >= 8) return value_.substr(8);
+ return "";
+ }
+
+ CommentValue::CharsetId CommentValue::charsetId() const
+ {
+ CharsetId charsetId = undefined;
+ if (value_.length() >= 8) {
+ const std::string code = value_.substr(0, 8);
+ charsetId = CharsetInfo::charsetIdByCode(code);
+ }
+ return charsetId;
+ }
+
+ CommentValue* CommentValue::clone_() const
+ {
+ return new CommentValue(*this);
+ }
+
+ DateValue::DateValue(int year, int month, int day)
+ : Value(date)
+ {
+ date_.year = year;
+ date_.month = month;
+ date_.day = day;
+ }
+
+ DateValue& DateValue::operator=(const DateValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ Value::operator=(rhs);
+ date_.year = rhs.date_.year;
+ date_.month = rhs.date_.month;
+ date_.day = rhs.date_.day;
+ return *this;
+ }
+
+ void DateValue::read(const byte* buf, long len, ByteOrder byteOrder)
+ {
+ // byteOrder not needed
+ // Hard coded to read Iptc style dates
+ if (len != 8) throw Error(29);
+ int scanned = sscanf(reinterpret_cast<const char*>(buf),
+ "%4d%2d%2d",
+ &date_.year, &date_.month, &date_.day);
+ if (scanned != 3) throw Error(29);
+ }
+
+ void DateValue::read(const std::string& buf)
+ {
+ // byteOrder not needed
+ // Hard coded to read Iptc style dates
+ if (buf.length() < 8) throw Error(29);
+ int scanned = sscanf(buf.data(),
+ "%4d-%d-%d",
+ &date_.year, &date_.month, &date_.day);
+ if (scanned != 3) throw Error(29);
+ }
+
+ void DateValue::setDate( const Date& src )
+ {
+ date_.year = src.year;
+ date_.month = src.month;
+ date_.day = src.day;
+ }
+
+ long DateValue::copy(byte* buf, ByteOrder byteOrder) const
+ {
+ // byteOrder not needed
+ // sprintf wants to add the null terminator, so use oversized buffer
+ char temp[9];
+
+ int wrote = sprintf( temp, "%04d%02d%02d",
+ date_.year, date_.month, date_.day);
+ assert(wrote == 8);
+ memcpy(buf, temp, 8);
+ return 8;
+ }
+
+ long DateValue::size() const
+ {
+ return 8;
+ }
+
+ DateValue* DateValue::clone_() const
+ {
+ return new DateValue(*this);
+ }
+
+ std::ostream& DateValue::write(std::ostream& os) const
+ {
+ return os << date_.year << '-' << std::right
+ << std::setw(2) << std::setfill('0') << date_.month << '-'
+ << std::setw(2) << std::setfill('0') << date_.day;
+ }
+
+ long DateValue::toLong(long n) const
+ {
+ // Range of tm struct is limited to about 1970 to 2038
+ // This will return -1 if outside that range
+ std::tm tms;
+ memset(&tms, 0, sizeof(tms));
+ tms.tm_mday = date_.day;
+ tms.tm_mon = date_.month - 1;
+ tms.tm_year = date_.year - 1900;
+ return static_cast<long>(std::mktime(&tms));
+ }
+
+ TimeValue::TimeValue(int hour, int minute,
+ int second, int tzHour,
+ int tzMinute)
+ : Value(date)
+ {
+ time_.hour=hour;
+ time_.minute=minute;
+ time_.second=second;
+ time_.tzHour=tzHour;
+ time_.tzMinute=tzMinute;
+ }
+
+ TimeValue& TimeValue::operator=(const TimeValue& rhs)
+ {
+ if (this == &rhs) return *this;
+ Value::operator=(rhs);
+ memcpy(&time_, &rhs.time_, sizeof(time_));
+ return *this;
+ }
+
+ void TimeValue::read(const byte* buf, long len, ByteOrder byteOrder)
+ {
+ // byteOrder not needed
+ // Hard coded to read Iptc style times
+ if (len != 11) throw Error(30);
+ char plusMinus;
+ int scanned = sscanf(reinterpret_cast<const char*>(buf),
+ "%2d%2d%2d%1c%2d%2d",
+ &time_.hour, &time_.minute, &time_.second,
+ &plusMinus, &time_.tzHour, &time_.tzMinute );
+
+ if (scanned != 6) throw Error(30);
+ if (plusMinus == '-') {
+ time_.tzHour *= -1;
+ time_.tzMinute *= -1;
+ }
+ }
+
+ void TimeValue::read(const std::string& buf)
+ {
+ // byteOrder not needed
+ // Hard coded to read Iptc style times
+ if (buf.length() < 9) throw Error(30);
+ char plusMinus;
+ int scanned = sscanf(buf.data(),
+ "%d:%d:%d%1c%d:%d",
+ &time_.hour, &time_.minute, &time_.second,
+ &plusMinus, &time_.tzHour, &time_.tzMinute );
+
+ if (scanned != 6) throw Error(30);
+ if (plusMinus == '-') {
+ time_.tzHour *= -1;
+ time_.tzMinute *= -1;
+ }
+ }
+
+ void TimeValue::setTime( const Time& src )
+ {
+ memcpy(&time_, &src, sizeof(time_));
+ }
+
+ long TimeValue::copy(byte* buf, ByteOrder byteOrder) const
+ {
+ // byteOrder not needed
+ // sprintf wants to add the null terminator, so use oversized buffer
+ char temp[12];
+ char plusMinus = '+';
+ if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-';
+
+ int wrote = sprintf(temp,
+ "%02d%02d%02d%1c%02d%02d",
+ time_.hour, time_.minute, time_.second,
+ plusMinus, abs(time_.tzHour), abs(time_.tzMinute));
+
+ assert(wrote == 11);
+ memcpy(buf, temp, 11);
+ return 11;
+ }
+
+ long TimeValue::size() const
+ {
+ return 11;
+ }
+
+ TimeValue* TimeValue::clone_() const
+ {
+ return new TimeValue(*this);
+ }
+
+ std::ostream& TimeValue::write(std::ostream& os) const
+ {
+ char plusMinus = '+';
+ if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-';
+
+ return os << std::right
+ << std::setw(2) << std::setfill('0') << time_.hour << ':'
+ << std::setw(2) << std::setfill('0') << time_.minute << ':'
+ << std::setw(2) << std::setfill('0') << time_.second << plusMinus
+ << std::setw(2) << std::setfill('0') << abs(time_.tzHour) << ':'
+ << std::setw(2) << std::setfill('0') << abs(time_.tzMinute);
+ }
+
+ long TimeValue::toLong(long n) const
+ {
+ // Returns number of seconds in the day in UTC.
+ long result = (time_.hour - time_.tzHour) * 60 * 60;
+ result += (time_.minute - time_.tzMinute) * 60;
+ result += time_.second;
+ if (result < 0) {
+ result += 86400;
+ }
+ return result;
+ }
+
+} // namespace Exiv2
Added: Extractor/src/plugins/exiv2/value.hpp
===================================================================
--- Extractor/src/plugins/exiv2/value.hpp 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2/value.hpp 2005-07-03 19:43:52 UTC (rev
1228)
@@ -0,0 +1,1225 @@
+// ***************************************************************** -*- C++
-*-
+/*
+ * Copyright (C) 2004, 2005 Andreas Huggel <address@hidden>
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*!
+ @file value.hpp
+ @brief Value interface and concrete subclasses
+ @version $Rev: 560 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:address@hidden">address@hidden</a>
+ @date 09-Jan-04, ahu: created
+ 11-Feb-04, ahu: isolated as a component
+ 31-Jul-04, brad: added Time, Data and String values
+ */
+#ifndef VALUE_HPP_
+#define VALUE_HPP_
+
+//
*****************************************************************************
+// included header files
+#include "types.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <memory>
+
+//
*****************************************************************************
+// namespace extensions
+namespace Exiv2 {
+
+//
*****************************************************************************
+// class definitions
+
+ /*!
+ @brief Common interface for all types of values used with metadata.
+
+ The interface provides a uniform way to access values independent from
+ their actual C++ type for simple tasks like reading the values from a
+ string or data buffer. For other tasks, like modifying values you may
+ need to downcast it to the actual subclass of %Value so that you can
+ access the subclass specific interface.
+ */
+ class Value {
+ public:
+ //! Shortcut for a %Value auto pointer.
+ typedef std::auto_ptr<Value> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Constructor, taking a type id to initialize the base class with
+ explicit Value(TypeId typeId)
+ : type_(typeId) {}
+ //! Copy constructor
+ Value(const Value& rhs)
+ : type_(rhs.type_) {}
+ //! Virtual destructor.
+ virtual ~Value() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ /*!
+ @brief Read the value from a character buffer.
+
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @param byteOrder Applicable byte order (little or big endian).
+ */
+ virtual void read(const byte* buf, long len, ByteOrder byteOrder) =0;
+ /*!
+ @brief Set the value from a string buffer. The format of the string
+ corresponds to that of the write() method, i.e., a string
+ obtained through the write() method can be read by this
+ function.
+
+ @param buf The string to read from.
+ */
+ virtual void read(const std::string& buf) =0;
+ /*!
+ @brief Set the data area, if the value has one by copying (cloning)
+ the buffer pointed to by buf.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to set such
+ a data area.
+
+ @param buf Pointer to the source data area
+ @param len Size of the data area
+ @return Return -1 if the value has no data area, else 0.
+ */
+ virtual int setDataArea(const byte* buf, long len) { return -1; }
+ //@}
+
+ //! @name Accessors
+ //@{
+ //! Return the type identifier (Exif data format type).
+ TypeId typeId() const { return type_; }
+ /*!
+ @brief Return the value as a string. Implemented in terms of
+ write(std::ostream& os) const of the concrete class.
+ */
+ std::string toString() const;
+ /*!
+ @brief Return an auto-pointer to a copy of itself (deep copy).
+ The caller owns this copy and the auto-pointer ensures that
+ it will be deleted.
+ */
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write value to a data buffer.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return Number of bytes written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder) const =0;
+ //! Return the number of components of the value
+ virtual long count() const =0;
+ //! Return the size of the value in bytes
+ virtual long size() const =0;
+ /*!
+ @brief Write the value to an output stream. You do not usually have
+ to use this function; it is used for the implementation of
+ the output operator for %Value,
+ operator<<(std::ostream &os, const Value &value).
+ */
+ virtual std::ostream& write(std::ostream& os) const =0;
+ /*!
+ @brief Convert the n-th component of the value to a long. The
+ behaviour of this method may be undefined if there is no
+ n-th component.
+
+ @return The converted value.
+ */
+ virtual long toLong(long n =0) const =0;
+ /*!
+ @brief Convert the n-th component of the value to a float. The
+ behaviour of this method may be undefined if there is no
+ n-th component.
+
+ @return The converted value.
+ */
+ virtual float toFloat(long n =0) const =0;
+ /*!
+ @brief Convert the n-th component of the value to a Rational. The
+ behaviour of this method may be undefined if there is no
+ n-th component.
+
+ @return The converted value.
+ */
+ virtual Rational toRational(long n =0) const =0;
+ //! Return the size of the data area, 0 if there is none.
+ virtual long sizeDataArea() const { return 0; }
+ /*!
+ @brief Return a copy of the data area if the value has one. The
+ caller owns this copy and DataBuf ensures that it will be
+ deleted.
+
+ Values may have a data area, which can contain additional
+ information besides the actual value. This method is used to access
+ such a data area.
+
+ @return A DataBuf containing a copy of the data area or an empty
+ DataBuf if the value does not have a data area assigned.
+ */
+ virtual DataBuf dataArea() const { return DataBuf(0, 0); };
+ //@}
+
+ /*!
+ @brief A (simple) factory to create a Value type.
+
+ The following Value subclasses are created depending on
typeId:<BR><BR>
+ <TABLE>
+ <TR><TD class="indexkey"><B>typeId</B></TD><TD
class="indexvalue"><B>%Value subclass</B></TD></TR>
+ <TR><TD class="indexkey">invalidTypeId</TD><TD
class="indexvalue">%DataValue(invalidTypeId)</TD></TR>
+ <TR><TD class="indexkey">unsignedByte</TD><TD
class="indexvalue">%DataValue(unsignedByte)</TD></TR>
+ <TR><TD class="indexkey">asciiString</TD><TD
class="indexvalue">%AsciiValue</TD></TR>
+ <TR><TD class="indexkey">string</TD><TD
class="indexvalue">%StringValue</TD></TR>
+ <TR><TD class="indexkey">unsignedShort</TD><TD
class="indexvalue">%ValueType < uint16_t ></TD></TR>
+ <TR><TD class="indexkey">unsignedLong</TD><TD
class="indexvalue">%ValueType < uint32_t ></TD></TR>
+ <TR><TD class="indexkey">unsignedRational</TD><TD
class="indexvalue">%ValueType < URational ></TD></TR>
+ <TR><TD class="indexkey">invalid6</TD><TD
class="indexvalue">%DataValue(invalid6)</TD></TR>
+ <TR><TD class="indexkey">undefined</TD><TD
class="indexvalue">%DataValue</TD></TR>
+ <TR><TD class="indexkey">signedShort</TD><TD
class="indexvalue">%ValueType < int16_t ></TD></TR>
+ <TR><TD class="indexkey">signedLong</TD><TD
class="indexvalue">%ValueType < int32_t ></TD></TR>
+ <TR><TD class="indexkey">signedRational</TD><TD
class="indexvalue">%ValueType < Rational ></TD></TR>
+ <TR><TD class="indexkey">date</TD><TD
class="indexvalue">%DateValue</TD></TR>
+ <TR><TD class="indexkey">time</TD><TD
class="indexvalue">%TimeValue</TD></TR>
+ <TR><TD class="indexkey">comment</TD><TD
class="indexvalue">%CommentValue</TD></TR>
+ <TR><TD class="indexkey"><EM>default:</EM></TD><TD
class="indexvalue">%DataValue(typeId)</TD></TR>
+ </TABLE>
+
+ @param typeId Type of the value.
+ @return Auto-pointer to the newly created Value. The caller owns this
+ copy and the auto-pointer ensures that it will be deleted.
+ */
+ static AutoPtr create(TypeId typeId);
+
+ protected:
+ /*!
+ @brief Assignment operator. Protected so that it can only be used
+ by subclasses but not directly.
+ */
+ Value& operator=(const Value& rhs);
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual Value* clone_() const =0;
+ // DATA
+ TypeId type_; //!< Type of the data
+
+ }; // class Value
+
+ //! Output operator for Value types
+ inline std::ostream& operator<<(std::ostream& os, const Value& value)
+ {
+ return value.write(os);
+ }
+
+ //! %Value for an undefined data type.
+ class DataValue : public Value {
+ public:
+ //! Shortcut for a %DataValue auto pointer.
+ typedef std::auto_ptr<DataValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ DataValue(TypeId typeId =undefined) : Value(typeId) {}
+ //! Constructor
+ DataValue(const byte* buf,
+ long len, ByteOrder byteOrder =invalidByteOrder,
+ TypeId typeId =undefined)
+ : Value(typeId) { read(buf, len, byteOrder); }
+ //! Virtual destructor.
+ virtual ~DataValue() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ DataValue& operator=(const DataValue& rhs);
+ /*!
+ @brief Read the value from a character buffer.
+
+ @note The byte order is required by the interface but not
+ used by this method, so just use the default.
+
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @param byteOrder Byte order. Not needed.
+ */
+ virtual void read(const byte* buf,
+ long len,
+ ByteOrder byteOrder =invalidByteOrder);
+ //! Set the data from a string of integer values (e.g., "0 1 2 3")
+ virtual void read(const std::string& buf);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write value to a character data buffer.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Byte order. Not needed.
+ @return Number of characters written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder)
const;
+ virtual long count() const { return size(); }
+ virtual long size() const;
+ virtual std::ostream& write(std::ostream& os) const;
+ virtual long toLong(long n =0) const { return value_[n]; }
+ virtual float toFloat(long n =0) const { return value_[n]; }
+ virtual Rational toRational(long n =0) const
+ { return Rational(value_[n], 1); }
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual DataValue* clone_() const;
+ // DATA
+ std::vector<byte> value_;
+
+ }; // class DataValue
+
+ /*!
+ @brief Abstract base class for a string based %Value type.
+
+ Uses a std::string to store the value and implements defaults for
+ most operations.
+ */
+ class StringValueBase : public Value {
+ public:
+ //! Shortcut for a %StringValueBase auto pointer.
+ typedef std::auto_ptr<StringValueBase> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Constructor for subclasses
+ StringValueBase(TypeId typeId)
+ : Value(typeId) {}
+ //! Constructor for subclasses
+ StringValueBase(TypeId typeId, const std::string& buf)
+ : Value(typeId) { read(buf); }
+ //! Copy constructor
+ StringValueBase(const StringValueBase& rhs)
+ : Value(rhs), value_(rhs.value_) {}
+
+ //! Virtual destructor.
+ virtual ~StringValueBase() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ StringValueBase& operator=(const StringValueBase& rhs);
+ //! Read the value from buf. This default implementation uses buf as
it is.
+ virtual void read(const std::string& buf);
+ /*!
+ @brief Read the value from a character buffer.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @param byteOrder Byte order. Not needed.
+ */
+ virtual void read(const byte* buf,
+ long len,
+ ByteOrder byteOrder =invalidByteOrder);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write value to a character data buffer.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Byte order. Not used.
+ @return Number of characters written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder)
const;
+ virtual long count() const { return size(); }
+ virtual long size() const;
+ virtual long toLong(long n =0) const { return value_[n]; }
+ virtual float toFloat(long n =0) const { return value_[n]; }
+ virtual Rational toRational(long n =0) const
+ { return Rational(value_[n], 1); }
+ virtual std::ostream& write(std::ostream& os) const;
+ //@}
+
+ protected:
+ //! Internal virtual copy constructor.
+ virtual StringValueBase* clone_() const =0;
+ // DATA
+ std::string value_; //!< Stores the string value.
+
+ }; // class StringValueBase
+
+ /*!
+ @brief %Value for string type.
+
+ This can be a plain Ascii string or a multipe byte encoded string. It is
+ left to caller to decode and encode the string to and from readable
+ text if that is required.
+ */
+ class StringValue : public StringValueBase {
+ public:
+ //! Shortcut for a %StringValue auto pointer.
+ typedef std::auto_ptr<StringValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ StringValue()
+ : StringValueBase(string) {}
+ //! Constructor
+ StringValue(const std::string& buf)
+ : StringValueBase(string, buf) {}
+ //! Copy constructor
+ StringValue(const StringValue& rhs)
+ : StringValueBase(rhs) {}
+ //! Virtual destructor.
+ virtual ~StringValue() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ StringValue& operator=(const StringValue& rhs);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual StringValue* clone_() const;
+
+ }; // class StringValue
+
+ /*!
+ @brief %Value for an Ascii string type.
+
+ This class is for null terminated single byte Ascii strings.
+ This class also ensures that the string is null terminated.
+ */
+ class AsciiValue : public StringValueBase {
+ public:
+ //! Shortcut for a %AsciiValue auto pointer.
+ typedef std::auto_ptr<AsciiValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ AsciiValue()
+ : StringValueBase(asciiString) {}
+ //! Constructor
+ AsciiValue(const std::string &buf)
+ : StringValueBase(asciiString, buf) {}
+ //! Copy constructor
+ AsciiValue(const AsciiValue& rhs)
+ : StringValueBase(rhs) {}
+ //! Virtual destructor.
+ virtual ~AsciiValue() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator
+ AsciiValue& operator=(const AsciiValue& rhs);
+ /*!
+ @brief Set the value to that of the string buf. Overrides base class
+ to append a terminating '\\0' character if buf doesn't end
+ with '\\0'.
+ */
+ virtual void read(const std::string& buf);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write the value to an output stream. Any trailing '\\0'
+ characters of the ASCII value are stripped and not written to
+ the output stream.
+ */
+ virtual std::ostream& write(std::ostream& os) const;
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual AsciiValue* clone_() const;
+
+ }; // class AsciiValue
+
+ /*!
+ @brief %Value for an Exif comment.
+
+ This can be a plain Ascii string or a multipe byte encoded string. The
+ comment is expected to be encoded in the character set indicated (default
+ undefined), but this is not checked. It is left to caller to decode and
+ encode the string to and from readable text if that is required.
+ */
+ class CommentValue : public StringValueBase {
+ public:
+ //! Character set identifiers for the character sets defined by %Exif
+ enum CharsetId { ascii, jis, unicode, undefined,
+ invalidCharsetId, lastCharsetId };
+ //! Information pertaining to the defined character sets
+ struct CharsetTable {
+ //! Constructor
+ CharsetTable(CharsetId charsetId,
+ const char* name,
+ const char* code);
+ CharsetId charsetId_; //!< Charset id
+ const char* name_; //!< Name of the charset
+ const char* code_; //!< Code of the charset
+ }; // struct CharsetTable
+ //! Charset information lookup functions. Implemented as a static
class.
+ class CharsetInfo {
+ //! Prevent construction: not implemented.
+ CharsetInfo() {}
+ //! Prevent copy-construction: not implemented.
+ CharsetInfo(const CharsetInfo&);
+ //! Prevent assignment: not implemented.
+ CharsetInfo& operator=(const CharsetInfo&);
+
+ public:
+ //! Return the name for a charset id
+ static const char* name(CharsetId charsetId);
+ //! Return the code for a charset id
+ static const char* code(CharsetId charsetId);
+ //! Return the charset id for a name
+ static CharsetId charsetIdByName(const std::string& name);
+ //! Return the charset id for a code
+ static CharsetId charsetIdByCode(const std::string& code);
+
+ private:
+ static const CharsetTable charsetTable_[];
+ }; // class CharsetInfo
+
+ //! Shortcut for a %CommentValue auto pointer.
+ typedef std::auto_ptr<CommentValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ CommentValue()
+ : StringValueBase(Exiv2::undefined) {}
+ //! Constructor, uses read(const std::string& comment)
+ CommentValue(const std::string& comment);
+ //! Copy constructor
+ CommentValue(const CommentValue& rhs)
+ : StringValueBase(rhs) {}
+ //! Virtual destructor.
+ virtual ~CommentValue() {}
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ CommentValue& operator=(const CommentValue& rhs);
+ /*!
+ @brief Read the value from a comment
+
+ The format of \em comment is:
+ <BR>
+ <CODE>[charset=["]Ascii|Jis|Unicode|Undefined["] ]comment</CODE>
+ <BR>
+ The default charset is Undefined.
+
+ @throw Error if an invalid character set is encountered
+ */
+ void read(const std::string& comment);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write the comment in a format which can be read by
+ read(const std::string& comment).
+ */
+ std::ostream& write(std::ostream& os) const;
+ //! Return the comment (without a charset="..." prefix)
+ std::string comment() const;
+ //! Return the charset id of the comment
+ CharsetId charsetId() const;
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual CommentValue* clone_() const;
+
+ }; // class CommentValue
+
+ /*!
+ @brief %Value for simple ISO 8601 dates
+
+ This class is limited to parsing simple date strings in the ISO 8601
+ format CCYYMMDD (century, year, month, day).
+ */
+ class DateValue : public Value {
+ public:
+ //! Shortcut for a %DateValue auto pointer.
+ typedef std::auto_ptr<DateValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ DateValue() : Value(date) { memset(&date_, 0, sizeof(date_)); }
+ //! Constructor
+ DateValue(int year, int month, int day);
+ //! Virtual destructor.
+ virtual ~DateValue() {}
+ //@}
+
+ //! Simple Date helper structure
+ struct Date
+ {
+ int year; //!< Year
+ int month; //!< Month
+ int day; //!< Day
+ };
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ DateValue& operator=(const DateValue& rhs);
+ /*!
+ @brief Read the value from a character buffer.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @param byteOrder Byte order. Not needed.
+
+ @throw Error in case of an unsupported date format
+ */
+ virtual void read(const byte* buf,
+ long len,
+ ByteOrder byteOrder =invalidByteOrder);
+ /*!
+ @brief Set the value to that of the string buf.
+
+ @param buf String containing the date
+
+ @throw Error in case of an unsupported date format
+ */
+ virtual void read(const std::string& buf);
+ //! Set the date
+ void setDate(const Date& src);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write value to a character data buffer.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Byte order. Not used.
+ @return Number of characters written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder)
const;
+ //! Return date struct containing date information
+ virtual const Date& getDate() const { return date_; }
+ virtual long count() const { return size(); }
+ virtual long size() const;
+ /*!
+ @brief Write the value to an output stream. .
+ */
+ virtual std::ostream& write(std::ostream& os) const;
+ virtual long toLong(long n =0) const;
+ virtual float toFloat(long n =0) const
+ { return static_cast<float>(toLong(n)); }
+ virtual Rational toRational(long n =0) const
+ { return Rational(toLong(n), 1); }
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual DateValue* clone_() const;
+ // DATA
+ Date date_;
+
+ }; // class DateValue
+
+ /*!
+ @brief %Value for simple ISO 8601 times.
+
+ This class is limited to handling simple time strings in the ISO 8601
+ format HHMMSS�HHMM where HHMMSS refers to local hour, minute and
+ seconds and �HHMM refers to hours and minutes ahead or behind
+ Universal Coordinated Time.
+ */
+ class TimeValue : public Value {
+ public:
+ //! Shortcut for a %TimeValue auto pointer.
+ typedef std::auto_ptr<TimeValue> AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ TimeValue() : Value(time) { memset(&time_, 0, sizeof(time_)); }
+ //! Constructor
+ TimeValue(int hour, int minute, int second =0,
+ int tzHour =0, int tzMinute =0);
+
+ //! Virtual destructor.
+ virtual ~TimeValue() {}
+ //@}
+
+ //! Simple Time helper structure
+ struct Time
+ {
+ int hour; //!< Hour
+ int minute; //!< Minute
+ int second; //!< Second
+ int tzHour; //!< Hours ahead or behind UTC
+ int tzMinute; //!< Minutes ahead or behind
UTC
+ };
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ TimeValue& operator=(const TimeValue& rhs);
+ /*!
+ @brief Read the value from a character buffer.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Pointer to the data buffer to read from
+ @param len Number of bytes in the data buffer
+ @param byteOrder Byte order. Not needed.
+
+ @throw Error in case of an unsupported time format
+ */
+ virtual void read(const byte* buf,
+ long len,
+ ByteOrder byteOrder =invalidByteOrder);
+ /*!
+ @brief Set the value to that of the string buf.
+
+ @param buf String containing the time.
+
+ @throw Error in case of an unsupported time format
+ */
+ virtual void read(const std::string& buf);
+ //! Set the time
+ void setTime(const Time& src);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ /*!
+ @brief Write value to a character data buffer.
+
+ The user must ensure that the buffer has enough memory. Otherwise
+ the call results in undefined behaviour.
+
+ @note The byte order is required by the interface but not used by
this
+ method, so just use the default.
+
+ @param buf Data buffer to write to.
+ @param byteOrder Byte order. Not used.
+ @return Number of characters written.
+ */
+ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder)
const;
+ //! Return time struct containing time information
+ virtual const Time& getTime() const { return time_; }
+ virtual long count() const { return size(); }
+ virtual long size() const;
+ /*!
+ @brief Write the value to an output stream. .
+ */
+ virtual std::ostream& write(std::ostream& os) const;
+ virtual long toLong(long n =0) const;
+ virtual float toFloat(long n =0) const
+ { return static_cast<float>(toLong(n)); }
+ virtual Rational toRational(long n =0) const
+ { return Rational(toLong(n), 1); }
+ //@}
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual TimeValue* clone_() const;
+ // DATA
+ Time time_;
+
+ }; // class TimeValue
+ //! Template to determine the TypeId for a type T
+ template<typename T> TypeId getType();
+
+ //! Specialization for an unsigned short
+ template<> inline TypeId getType<uint16_t>() { return unsignedShort; }
+ //! Specialization for an unsigned long
+ template<> inline TypeId getType<uint32_t>() { return unsignedLong; }
+ //! Specialization for an unsigned rational
+ template<> inline TypeId getType<URational>() { return unsignedRational; }
+ //! Specialization for a signed short
+ template<> inline TypeId getType<int16_t>() { return signedShort; }
+ //! Specialization for a signed long
+ template<> inline TypeId getType<int32_t>() { return signedLong; }
+ //! Specialization for a signed rational
+ template<> inline TypeId getType<Rational>() { return signedRational; }
+
+ // No default implementation: let the compiler/linker complain
+// template<typename T> inline TypeId getType() { return invalid; }
+
+ /*!
+ @brief Template for a %Value of a basic type. This is used for unsigned
+ and signed short, long and rationals.
+ */
+ template<typename T>
+ class ValueType : public Value {
+ public:
+ //! Shortcut for a %ValueType\<T\> auto pointer.
+ typedef std::auto_ptr<ValueType<T> > AutoPtr;
+
+ //! @name Creators
+ //@{
+ //! Default constructor.
+ ValueType() : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0) {}
+ //! Constructor
+ ValueType(const byte* buf, long len, ByteOrder byteOrder);
+ //! Constructor
+ ValueType(const T& val, ByteOrder byteOrder =littleEndian);
+ //! Copy constructor
+ ValueType(const ValueType<T>& rhs);
+ //! Virtual destructor.
+ virtual ~ValueType();
+ //@}
+
+ //! @name Manipulators
+ //@{
+ //! Assignment operator.
+ ValueType<T>& operator=(const ValueType<T>& rhs);
+ virtual void read(const byte* buf, long len, ByteOrder byteOrder);
+ /*!
+ @brief Set the data from a string of values of type T (e.g.,
+ "0 1 2 3" or "1/2 1/3 1/4" depending on what T is).
+ Generally, the accepted input format is the same as that
+ produced by the write() method.
+ */
+ virtual void read(const std::string& buf);
+ /*!
+ @brief Set the data area. This method copies (clones) the buffer
+ pointed to by buf.
+ */
+ virtual int setDataArea(const byte* buf, long len);
+ //@}
+
+ //! @name Accessors
+ //@{
+ AutoPtr clone() const { return AutoPtr(clone_()); }
+ virtual long copy(byte* buf, ByteOrder byteOrder) const;
+ virtual long count() const { return static_cast<long>(value_.size()); }
+ virtual long size() const;
+ virtual std::ostream& write(std::ostream& os) const;
+ virtual long toLong(long n =0) const;
+ virtual float toFloat(long n =0) const;
+ virtual Rational toRational(long n =0) const;
+ //! Return the size of the data area.
+ virtual long sizeDataArea() const { return sizeDataArea_; }
+ /*!
+ @brief Return a copy of the data area in a DataBuf. The caller owns
+ this copy and DataBuf ensures that it will be deleted.
+ */
+ virtual DataBuf dataArea() const;
+ //@}
+
+ //! Container for values
+ typedef std::vector<T> ValueList;
+ //! Iterator type defined for convenience.
+ typedef typename std::vector<T>::iterator iterator;
+ //! Const iterator type defined for convenience.
+ typedef typename std::vector<T>::const_iterator const_iterator;
+
+ // DATA
+ /*!
+ @brief The container for all values. In your application, if you
know
+ what subclass of Value you're dealing with (and possibly the
T)
+ then you can access this STL container through the usual
+ standard library functions.
+ */
+ ValueList value_;
+
+ private:
+ //! Internal virtual copy constructor.
+ virtual ValueType<T>* clone_() const;
+
+ // DATA
+ //! Pointer to the buffer, 0 if none has been allocated
+ byte* pDataArea_;
+ //! The current size of the buffer
+ long sizeDataArea_;
+ }; // class ValueType
+
+ //! Unsigned short value type
+ typedef ValueType<uint16_t> UShortValue;
+ //! Unsigned long value type
+ typedef ValueType<uint32_t> ULongValue;
+ //! Unsigned rational value type
+ typedef ValueType<URational> URationalValue;
+ //! Signed short value type
+ typedef ValueType<int16_t> ShortValue;
+ //! Signed long value type
+ typedef ValueType<int32_t> LongValue;
+ //! Signed rational value type
+ typedef ValueType<Rational> RationalValue;
+
+//
*****************************************************************************
+// template and inline definitions
+
+ /*!
+ @brief Read a value of type T from the data buffer.
+
+ We need this template function for the ValueType template classes.
+ There are only specializations of this function available; no default
+ implementation is provided.
+
+ @param buf Pointer to the data buffer to read from.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return A value of type T.
+ */
+ template<typename T> T getValue(const byte* buf, ByteOrder byteOrder);
+ // Specialization for a 2 byte unsigned short value.
+ template<>
+ inline uint16_t getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getUShort(buf, byteOrder);
+ }
+ // Specialization for a 4 byte unsigned long value.
+ template<>
+ inline uint32_t getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getULong(buf, byteOrder);
+ }
+ // Specialization for an 8 byte unsigned rational value.
+ template<>
+ inline URational getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getURational(buf, byteOrder);
+ }
+ // Specialization for a 2 byte signed short value.
+ template<>
+ inline int16_t getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getShort(buf, byteOrder);
+ }
+ // Specialization for a 4 byte signed long value.
+ template<>
+ inline int32_t getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getLong(buf, byteOrder);
+ }
+ // Specialization for an 8 byte signed rational value.
+ template<>
+ inline Rational getValue(const byte* buf, ByteOrder byteOrder)
+ {
+ return getRational(buf, byteOrder);
+ }
+
+ /*!
+ @brief Convert a value of type T to data, write the data to the data
buffer.
+
+ We need this template function for the ValueType template classes.
+ There are only specializations of this function available; no default
+ implementation is provided.
+
+ @param buf Pointer to the data buffer to write to.
+ @param t Value to be converted.
+ @param byteOrder Applicable byte order (little or big endian).
+ @return The number of bytes written to the buffer.
+ */
+ template<typename T> long toData(byte* buf, T t, ByteOrder byteOrder);
+ /*!
+ @brief Specialization to write an unsigned short to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, uint16_t t, ByteOrder byteOrder)
+ {
+ return us2Data(buf, t, byteOrder);
+ }
+ /*!
+ @brief Specialization to write an unsigned long to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, uint32_t t, ByteOrder byteOrder)
+ {
+ return ul2Data(buf, t, byteOrder);
+ }
+ /*!
+ @brief Specialization to write an unsigned rational to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, URational t, ByteOrder byteOrder)
+ {
+ return ur2Data(buf, t, byteOrder);
+ }
+ /*!
+ @brief Specialization to write a signed short to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, int16_t t, ByteOrder byteOrder)
+ {
+ return s2Data(buf, t, byteOrder);
+ }
+ /*!
+ @brief Specialization to write a signed long to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, int32_t t, ByteOrder byteOrder)
+ {
+ return l2Data(buf, t, byteOrder);
+ }
+ /*!
+ @brief Specialization to write a signed rational to the data buffer.
+ Return the number of bytes written.
+ */
+ template<>
+ inline long toData(byte* buf, Rational t, ByteOrder byteOrder)
+ {
+ return r2Data(buf, t, byteOrder);
+ }
+
+ template<typename T>
+ ValueType<T>::ValueType(const byte* buf, long len, ByteOrder byteOrder)
+ : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0)
+ {
+ read(buf, len, byteOrder);
+ }
+
+ template<typename T>
+ ValueType<T>::ValueType(const T& val, ByteOrder byteOrder)
+ : Value(getType<T>()), pDataArea_(0), sizeDataArea_(0)
+ {
+ read(reinterpret_cast<const byte*>(&val),
+ TypeInfo::typeSize(typeId()),
+ byteOrder);
+ }
+
+ template<typename T>
+ ValueType<T>::ValueType(const ValueType<T>& rhs)
+ : Value(rhs), value_(rhs.value_), pDataArea_(0), sizeDataArea_(0)
+ {
+ if (rhs.sizeDataArea_ > 0) {
+ pDataArea_ = new byte[rhs.sizeDataArea_];
+ memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea_);
+ sizeDataArea_ = rhs.sizeDataArea_;
+ }
+ }
+
+ template<typename T>
+ ValueType<T>::~ValueType()
+ {
+ delete[] pDataArea_;
+ }
+
+ template<typename T>
+ ValueType<T>& ValueType<T>::operator=(const ValueType<T>& rhs)
+ {
+ if (this == &rhs) return *this;
+ Value::operator=(rhs);
+ value_ = rhs.value_;
+
+ byte* tmp = 0;
+ if (rhs.sizeDataArea_ > 0) {
+ tmp = new byte[rhs.sizeDataArea_];
+ memcpy(tmp, rhs.pDataArea_, rhs.sizeDataArea_);
+ }
+ delete[] pDataArea_;
+ pDataArea_ = tmp;
+ sizeDataArea_ = rhs.sizeDataArea_;
+
+ return *this;
+ }
+
+ template<typename T>
+ void ValueType<T>::read(const byte* buf, long len, ByteOrder byteOrder)
+ {
+ value_.clear();
+ for (long i = 0; i < len; i += TypeInfo::typeSize(typeId())) {
+ value_.push_back(getValue<T>(buf + i, byteOrder));
+ }
+ }
+
+ template<typename T>
+ void ValueType<T>::read(const std::string& buf)
+ {
+ std::istringstream is(buf);
+ T tmp;
+ value_.clear();
+ while (is >> tmp) {
+ value_.push_back(tmp);
+ }
+ }
+
+ template<typename T>
+ long ValueType<T>::copy(byte* buf, ByteOrder byteOrder) const
+ {
+ long offset = 0;
+ typename ValueList::const_iterator end = value_.end();
+ for (typename ValueList::const_iterator i = value_.begin(); i != end;
++i) {
+ offset += toData(buf + offset, *i, byteOrder);
+ }
+ return offset;
+ }
+
+ template<typename T>
+ long ValueType<T>::size() const
+ {
+ return static_cast<long>(TypeInfo::typeSize(typeId()) * value_.size());
+ }
+
+ template<typename T>
+ ValueType<T>* ValueType<T>::clone_() const
+ {
+ return new ValueType<T>(*this);
+ }
+
+ template<typename T>
+ std::ostream& ValueType<T>::write(std::ostream& os) const
+ {
+ typename ValueList::const_iterator end = value_.end();
+ typename ValueList::const_iterator i = value_.begin();
+ while (i != end) {
+ os << *i;
+ if (++i != end) os << " ";
+ }
+ return os;
+ }
+ // Default implementation
+ template<typename T>
+ inline long ValueType<T>::toLong(long n) const
+ {
+ return value_[n];
+ }
+ // Specialization for rational
+ template<>
+ inline long ValueType<Rational>::toLong(long n) const
+ {
+ return value_[n].first / value_[n].second;
+ }
+ // Specialization for unsigned rational
+ template<>
+ inline long ValueType<URational>::toLong(long n) const
+ {
+ return value_[n].first / value_[n].second;
+ }
+ // Default implementation
+ template<typename T>
+ inline float ValueType<T>::toFloat(long n) const
+ {
+ return static_cast<float>(value_[n]);
+ }
+ // Specialization for rational
+ template<>
+ inline float ValueType<Rational>::toFloat(long n) const
+ {
+ return static_cast<float>(value_[n].first) / value_[n].second;
+ }
+ // Specialization for unsigned rational
+ template<>
+ inline float ValueType<URational>::toFloat(long n) const
+ {
+ return static_cast<float>(value_[n].first) / value_[n].second;
+ }
+ // Default implementation
+ template<typename T>
+ inline Rational ValueType<T>::toRational(long n) const
+ {
+ return Rational(value_[n], 1);
+ }
+ // Specialization for rational
+ template<>
+ inline Rational ValueType<Rational>::toRational(long n) const
+ {
+ return Rational(value_[n].first, value_[n].second);
+ }
+ // Specialization for unsigned rational
+ template<>
+ inline Rational ValueType<URational>::toRational(long n) const
+ {
+ return Rational(value_[n].first, value_[n].second);
+ }
+
+ template<typename T>
+ inline DataBuf ValueType<T>::dataArea() const
+ {
+ return DataBuf(pDataArea_, sizeDataArea_);
+ }
+
+ template<typename T>
+ inline int ValueType<T>::setDataArea(const byte* buf, long len)
+ {
+ byte* tmp = 0;
+ if (len > 0) {
+ tmp = new byte[len];
+ memcpy(tmp, buf, len);
+ }
+ delete[] pDataArea_;
+ pDataArea_ = tmp;
+ sizeDataArea_ = len;
+ return 0;
+ }
+
+} // namespace Exiv2
+
+#endif // #ifndef VALUE_HPP_
Deleted: Extractor/src/plugins/exiv2extractor.cc
===================================================================
--- Extractor/src/plugins/exiv2extractor.cc 2005-07-03 19:32:53 UTC (rev
1227)
+++ Extractor/src/plugins/exiv2extractor.cc 2005-07-03 19:43:52 UTC (rev
1228)
@@ -1,432 +0,0 @@
-// ***************************************************************** -*- C++
-*-
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-/*!
- @file exiv2extractor.cc
- @brief Prototype libextractor plugin for Exif using exiv2
- @version $Rev$
- @author Andreas Huggel (ahu)
- <a href="mailto:address@hidden">address@hidden</a>
- @date 30-Jun-05, ahu: created
-*/
-
-#include "platform.h"
-#include "extractor.h"
-#include "convert.h"
-
-#include "exiv2/exif.hpp"
-#include "exiv2/image.hpp"
-#include "exiv2/futils.hpp"
-
-#include <iostream>
-#include <iomanip>
-#include <cassert>
-#include <cstring>
-#include <sys/types.h> // for stat()
-#include <sys/stat.h> // for stat()
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> // for stat()
-#endif
-
-extern "C" {
-
- static struct EXTRACTOR_Keywords * addKeyword(EXTRACTOR_KeywordType type,
- char * keyword,
- struct EXTRACTOR_Keywords *
next)
- {
- EXTRACTOR_KeywordList * result;
-
- if (keyword == NULL)
- return next;
- result = (EXTRACTOR_KeywordList*)
malloc(sizeof(EXTRACTOR_KeywordList));
- result->next = next;
- result->keyword = keyword;
- result->keywordType = type;
- return result;
- }
-
-}
-
-struct EXTRACTOR_Keywords * addExiv2Tag(const Exiv2::ExifData& exifData,
- const std::string& key,
- EXTRACTOR_KeywordType type,
- struct EXTRACTOR_Keywords * result)
-{
- Exiv2::ExifKey ek(key);
- Exiv2::ExifData::const_iterator md = exifData.findKey(ek);
- if (md != exifData.end()) {
- result = addKeyword(type,
- strdup(Exiv2::toString(*md).c_str()),
- result);
- }
- return result;
-}
-
-extern "C" {
-
- struct EXTRACTOR_Keywords * libextractor_exiv2_extract(char * filename,
- unsigned char *
data,
- size_t size,
- struct
EXTRACTOR_Keywords * prev)
- {
- struct EXTRACTOR_Keywords * result = 0;
-
- try {
- if (!Exiv2::fileExists(filename, true)) return result;
-
- // Filename
- result = addKeyword(EXTRACTOR_FILENAME, strdup(filename), result);
-
- // Filesize
- struct stat buf;
- if (0 == stat(filename, &buf)) {
- result = addKeyword(EXTRACTOR_FILESIZE,
-
strdup(Exiv2::toString(buf.st_size).c_str()),
- result);
- }
-
- Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename);
- assert(image.get() != 0);
- image->readMetadata();
- Exiv2::ExifData &exifData = image->exifData();
- if (exifData.empty()) return result;
-
- // Camera make
- result = addExiv2Tag(exifData,
- "Exif.Image.Make",
- EXTRACTOR_CAMERA_MAKE,
- result);
-
- // Camera model
- result = addExiv2Tag(exifData,
- "Exif.Image.Model",
- EXTRACTOR_CAMERA_MODEL,
- result);
-
- // Camera model
- result = addExiv2Tag(exifData,
- "Exif.Image.Orientation",
- EXTRACTOR_ORIENTATION,
- result);
-
- // Image Timestamp
- result = addExiv2Tag(exifData,
- "Exif.Photo.DateTimeOriginal",
- EXTRACTOR_DATE,
- result);
-
- // Exposure time
- // From ExposureTime, failing that, try ShutterSpeedValue
- struct EXTRACTOR_Keywords * newResult;
- newResult = addExiv2Tag(exifData,
- "Exif.Photo.ExposureTime",
- EXTRACTOR_EXPOSURE,
- result);
- Exiv2::ExifData::const_iterator md;
- if (newResult == result) {
- md =
exifData.findKey(Exiv2::ExifKey("Exif.Photo.ShutterSpeedValue"));
- if (md != exifData.end()) {
- double tmp = exp(log(2.0) * md->toFloat()) + 0.5;
- std::ostringstream os;
- if (tmp > 1) {
- os << "1/" << static_cast<long>(tmp) << " s";
- }
- else {
- os << static_cast<long>(1/tmp) << " s";
- }
- newResult = addKeyword(EXTRACTOR_EXPOSURE,
- strdup(os.str().c_str()),
- result);
- }
- }
- result = newResult;
-
- // Aperture
- // Get if from FNumber and, failing that, try ApertureValue
- newResult = addExiv2Tag(exifData,
- "Exif.Photo.FNumber",
- EXTRACTOR_APERTURE,
- result);
- if (newResult == result) {
- md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ApertureValue"));
- if (md != exifData.end()) {
- std::ostringstream os;
- os << std::fixed << std::setprecision(1)
- << "F" << exp(log(2.0) * md->toFloat() / 2);
- newResult = addKeyword(EXTRACTOR_APERTURE,
- strdup(os.str().c_str()),
- result);
- }
- }
- result = newResult;
-
- // Exposure bias
- result = addExiv2Tag(exifData,
- "Exif.Photo.ExposureBiasValue",
- EXTRACTOR_EXPOSURE_BIAS,
- result);
-
- // Flash
- result = addExiv2Tag(exifData,
- "Exif.Photo.Flash",
- EXTRACTOR_FLASH,
- result);
-
- // Flash bias
- // Todo: Implement this for other cameras
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs2.FlashBias",
- EXTRACTOR_FLASH_BIAS,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Panasonic.FlashBias",
- EXTRACTOR_FLASH_BIAS,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Olympus.FlashBias",
- EXTRACTOR_FLASH_BIAS,
- result);
- }
- result = newResult;
-
- // Actual focal length and 35 mm equivalent
- // Todo: Calculate 35 mm equivalent a la jhead
- result = addExiv2Tag(exifData,
- "Exif.Photo.FocalLength",
- EXTRACTOR_FOCAL_LENGTH,
- result);
-
- result = addExiv2Tag(exifData,
- "Exif.Photo.FocalLengthIn35mmFilm",
- EXTRACTOR_FOCAL_LENGTH_35MM,
- result);
-
- // ISO speed
- // from ISOSpeedRatings or the Makernote
- newResult = addExiv2Tag(exifData,
- "Exif.Photo.ISOSpeedRatings",
- EXTRACTOR_ISO_SPEED,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs1.ISOSpeed",
- EXTRACTOR_ISO_SPEED,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon1.ISOSpeed",
- EXTRACTOR_ISO_SPEED,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon2.ISOSpeed",
- EXTRACTOR_ISO_SPEED,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon3.ISOSpeed",
- EXTRACTOR_ISO_SPEED,
- result);
- }
- result = newResult;
-
- // Exposure mode
- // From ExposureProgram or Canon Makernote
- newResult = addExiv2Tag(exifData,
- "Exif.Photo.ExposureProgram",
- EXTRACTOR_EXPOSURE_MODE,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs1.ExposureProgram",
- EXTRACTOR_EXPOSURE_MODE,
- result);
- }
-
- // Metering mode
- result = addExiv2Tag(exifData,
- "Exif.Photo.MeteringMode",
- EXTRACTOR_METERING_MODE,
- result);
-
- // Macro mode
- // Todo: Implement this for other cameras
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs1.Macro",
- EXTRACTOR_MACRO_MODE,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Fujifilm.Macro",
- EXTRACTOR_MACRO_MODE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Olympus.Macro",
- EXTRACTOR_MACRO_MODE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Panasonic.Macro",
- EXTRACTOR_MACRO_MODE,
- result);
- }
- result = newResult;
-
- // Image quality setting (compression)
- // Todo: Implement this for other cameras
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs1.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Fujifilm.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Sigma.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon1.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon2.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon3.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Olympus.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Panasonic.Quality",
- EXTRACTOR_IMAGE_QUALITY,
- result);
- }
- result = newResult;
-
- // Exif Resolution
- long xdim = 0;
- long ydim = 0;
- md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
- if (md != exifData.end()) xdim = md->toLong();
- md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
- if (md != exifData.end()) ydim = md->toLong();
- if (xdim != 0 && ydim != 0) {
- std::ostringstream os;
- os << xdim << "x" << ydim;
- result = addKeyword(EXTRACTOR_SIZE,
- strdup(os.str().c_str()),
- result);
- }
-
- // White balance
- // Todo: Implement this for other cameras
-
- newResult = addExiv2Tag(exifData,
- "Exif.CanonCs2.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Fujifilm.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Sigma.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon1.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon2.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Nikon3.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Olympus.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- if (newResult == result) {
- newResult = addExiv2Tag(exifData,
- "Exif.Panasonic.WhiteBalance",
- EXTRACTOR_WHITE_BALANCE,
- result);
- }
- result = newResult;
-
- // Copyright
- result = addExiv2Tag(exifData,
- "Exif.Image.Copyright",
- EXTRACTOR_COPYRIGHT,
- result);
-
- // Exif Comment
- result = addExiv2Tag(exifData,
- "Exif.Photo.UserComment",
- EXTRACTOR_COMMENT,
- result);
- }
- catch (const Exiv2::AnyError& e) {
- std::cout << "Caught Exiv2 exception '" << e << "'\n";
- }
-
- return result;
- }
-
-}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r1228 - in Extractor: . src/plugins src/plugins/exiv2,
grothoff <=