[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a
Maximiliano Curia
maxy at moszumanska.debian.org
Thu Jul 13 17:36:01 UTC 2017
Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=3408dec
The following commit has been merged in the master branch:
commit 3408dec8057fce595da92481d65332e259421abd
Author: Andreas Huggel <ahuggel at gmx.net>
Date: Tue Feb 10 02:40:51 2004 +0000
Added Exiv2, the application, with print, rename and adjust actions
---
src/actions.cpp | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/actions.hpp | 187 +++++++++++++++++++++++++
src/exiv2.cpp | 285 ++++++++++++++++++++++++++++++++++++++
src/exiv2.hpp | 157 +++++++++++++++++++++
4 files changed, 1052 insertions(+)
diff --git a/src/actions.cpp b/src/actions.cpp
new file mode 100644
index 0000000..87a1dec
--- /dev/null
+++ b/src/actions.cpp
@@ -0,0 +1,423 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ * Copyright (C) 2004 Andreas Huggel <ahuggel at gmx.net>
+ *
+ * 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: $Name: $ $Revision: 1.1 $
+ Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
+ History: 08-Dec-03, ahu: created
+ */
+// *****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Name: $ $Revision: 1.1 $ $RCSfile: actions.cpp,v $")
+
+// *****************************************************************************
+// included header files
+
+#include "actions.hpp"
+#include "exiv2.hpp"
+#include "utils.hpp"
+#include "exif.hpp"
+
+// + standard includes
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+#include <cstring>
+#include <cstdio>
+#include <ctime>
+
+// *****************************************************************************
+// 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 time type, -1 on error
+ time_t str2Time(const std::string& timeStr);
+
+ // Convert a time type to a string "YYYY:MM:DD HH:MI:SS", "" on error
+ std::string time2Str(time_t time);
+
+ // Return an error message for the return code of Exif::ExifData::read
+ std::string exifReadError(int rc, const std::string& path);
+
+ // Return an error message for the return code of Exif::ExifData::write
+ std::string exifWriteError(int rc, const std::string& path);
+
+}
+
+// *****************************************************************************
+// 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));
+ } // 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 {
+ Exif::ExifData exifData;
+ int rc = exifData.read(path);
+ if (rc) {
+ std::cerr << exifReadError(rc, path) << "
";
+ return rc;
+ }
+ Exif::ExifData::const_iterator md;
+ for (md = exifData.begin(); md != exifData.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->ifdItem() << " "
+ << std::setw(27) << std::setfill(' ') << std::left
+ << md->tagName() << " "
+ << std::dec << md->value() << "
";
+ }
+ return 0;
+ }
+ catch(const Exif::Error& e)
+ {
+ std::cerr << "Exif exception in print action for file "
+ << path << ":
" << e << "
";
+ return 1;
+ } // Print::run
+
+ Print::AutoPtr Print::clone() const
+ {
+ return AutoPtr(dynamic_cast<Print*>(clone_()));
+ }
+
+ Task* Print::clone_() const
+ {
+ return new Print(*this);
+ }
+
+ int Rename::run(const std::string& path)
+ try {
+ Exif::ExifData exifData;
+ int rc = exifData.read(path);
+ if (rc) {
+ std::cerr << exifReadError(rc, path) << "
";
+ return rc;
+ }
+ std::string key = "Image.DateTime.DateTimeOriginal";
+ Exif::ExifData::iterator md = exifData.findKey(key);
+ if (md == exifData.end()) {
+ std::cerr << "Metadatum with key `" << key << "' "
+ << "not found in the file " << path << "
";
+ 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 << "
";
+ 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 << "
";
+ 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 << "
";
+ return 1;
+ }
+ std::string newPath
+ = Util::dirname(path) + "/" + 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
";
+ }
+ return 0;
+ }
+ if (Params::instance().verbose_) {
+ std::cout << "Renaming file to " << newPath << "
";
+ }
+ if (!Params::instance().force_ && Util::fileExists(newPath)) {
+ std::cout << Params::instance().progname()
+ << ": Overwrite `" << newPath << "'? ";
+ std::string s;
+ std::cin >> s;
+ if (s[0] != 'y' && s[0] != 'Y') return 0;
+ }
+ if (::rename(path.c_str(), newPath.c_str()) == -1) {
+ std::cerr << Params::instance().progname()
+ << ": Failed to rename "
+ << path << " to " << newPath << ": "
+ << Util::strError() << "
";
+ return 1;
+ }
+ return 0;
+ }
+ catch(const Exif::Error& e)
+ {
+ std::cerr << "Exif exception in rename action for file " << path
+ << ":
" << e << "
";
+ return 1;
+ } // Rename::run
+
+ Rename::AutoPtr Rename::clone() const
+ {
+ return AutoPtr(dynamic_cast<Rename*>(clone_()));
+ }
+
+ Task* Rename::clone_() const
+ {
+ return new Rename(*this);
+ }
+
+ int Adjust::run(const std::string& path)
+ try {
+ adjustment_ = Params::instance().adjustment_;
+
+ Exif::ExifData exifData;
+ int rc = exifData.read(path);
+ if (rc) {
+ std::cerr << exifReadError(rc, path) << "
";
+ return rc;
+ }
+ rc = adjustDateTime(exifData, "Image.OtherTags.DateTime", path);
+ rc += adjustDateTime(exifData, "Image.DateTime.DateTimeOriginal", path);
+ rc += adjustDateTime(exifData, "Image.DateTime.DateTimeDigitized", path);
+ if (rc) return 1;
+ rc = exifData.write(path);
+ if (rc) {
+ std::cerr << exifWriteError(rc, path) << "
";
+ }
+ return rc;
+ }
+ catch(const Exif::Error& e)
+ {
+ std::cerr << "Exif exception in adjust action for file " << path
+ << ":
" << e << "
";
+ return 1;
+ } // Adjust::run
+
+ Adjust::AutoPtr Adjust::clone() const
+ {
+ return AutoPtr(dynamic_cast<Adjust*>(clone_()));
+ }
+
+ Task* Adjust::clone_() const
+ {
+ return new Adjust(*this);
+ }
+
+ int Adjust::adjustDateTime(Exif::ExifData& exifData,
+ const std::string& key,
+ const std::string& path) const
+ {
+ Exif::ExifData::iterator md = exifData.findKey(key);
+ 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 `"
+ << key << "' not set
";
+ return 1;
+ }
+ time_t time = str2Time(timeStr);
+ if (time == (time_t)-1) {
+ std::cerr << path << ": Failed to parse or convert timestamp `"
+ << timeStr << "'
";
+ return 1;
+ }
+ if (Params::instance().verbose_) {
+ std::cout << path << ": Adjusting timestamp by"
+ << (adjustment_ < 0 ? " " : " +")
+ << adjustment_ << " seconds to ";
+ }
+ time += adjustment_;
+ timeStr = time2Str(time);
+ if (Params::instance().verbose_) {
+ std::cout << timeStr << "
";
+ }
+ 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;
+ return ::mktime(&tm);
+ }
+
+ std::string time2Str(time_t time)
+ {
+ struct tm tm;
+ ::memset(&tm, 0x0, sizeof(struct tm));
+
+ if (0 == ::localtime_r(&time, &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
+
+ std::string exifReadError(int rc, const std::string& path)
+ {
+ std::string error;
+ switch (rc) {
+ case -1:
+ error = "Couldn't open file `" + path + "'";
+ break;
+ case 1:
+ error = "Couldn't read from the input stream";
+ break;
+ case 2:
+ error = "This does not look like a JPEG image";
+ break;
+ case 3:
+ error = "No Exif data found in the file";
+ break;
+ case -99:
+ error = "Unsupported Exif or GPS data found in IFD 1";
+ break;
+ default:
+ error = "Reading Exif data failed, rc = " + Exif::toString(rc);
+ break;
+ }
+ return error;
+ } // exifReadError
+
+ std::string exifWriteError(int rc, const std::string& path)
+ {
+ std::string error;
+ switch (rc) {
+ case -1:
+ error = "Couldn't open file `" + path + "'";
+ break;
+ case -2:
+ error = "Couldn't open temporary file";
+ break;
+ case -3:
+ error = "Renaming temporary file failed";
+ break;
+ case 1:
+ error = "Couldn't read from the input stream";
+ break;
+ case 2:
+ error = "This does not look like a JPEG image";
+ break;
+ case 3:
+ error = "No JFIF APP0 or Exif APP1 segment found in the file";
+ break;
+ case 4:
+ error = "Writing to the output stream failed";
+ break;
+ default:
+ error = "Reading Exif data failed, rc = " + Exif::toString(rc);
+ break;
+ }
+ return error;
+ } // exifWriteError
+
+}
diff --git a/src/actions.hpp b/src/actions.hpp
new file mode 100644
index 0000000..146b2ae
--- /dev/null
+++ b/src/actions.hpp
@@ -0,0 +1,187 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ * Copyright (C) 2004 Andreas Huggel <ahuggel at gmx.net>
+ *
+ * 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 $Name: $ $Revision: 1.1 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:ahuggel at gmx.net">ahuggel at gmx.net</a>
+ @date 11-Dec-03, ahu: created
+ */
+#ifndef ACTIONS_HPP_
+#define ACTIONS_HPP_
+
+// *****************************************************************************
+// included header files
+
+// + standard includes
+#include <string>
+#include <map>
+
+// *****************************************************************************
+// class declarations
+
+namespace Exif {
+ class ExifData;
+}
+
+// *****************************************************************************
+// namespace extensions
+/*!
+ @brief Contains all action classes (task subclasses).
+ */
+namespace Action {
+
+ //! Enumerates all tasks
+ enum TaskType { none, adjust, print, rename };
+
+// *****************************************************************************
+// class definitions
+
+ /*!
+ @brief 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 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;
+
+ };
+
+ /*!
+ @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 int run(const std::string& path);
+ typedef std::auto_ptr<Print> AutoPtr;
+ AutoPtr clone() const;
+
+ private:
+ virtual Task* clone_() const;
+ };
+
+ /*!
+ @brief %Rename a file to its metadate creation timestamp,
+ in the specified format.
+ */
+ class Rename : public Task {
+ public:
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Rename> AutoPtr;
+ AutoPtr clone() const;
+
+ private:
+ virtual Task* clone_() const;
+ };
+
+ //! %Adjust the %Exif (or other metadata) timestamps
+ class Adjust : public Task {
+ public:
+ virtual int run(const std::string& path);
+ typedef std::auto_ptr<Adjust> AutoPtr;
+ AutoPtr clone() const;
+
+ private:
+ virtual Task* clone_() const;
+ int adjustDateTime(Exif::ExifData& exifData,
+ const std::string& key,
+ const std::string& path) const;
+
+ long adjustment_;
+ };
+
+} // namespace Action
+
+#endif // #ifndef ACTIONS_HPP_
diff --git a/src/exiv2.cpp b/src/exiv2.cpp
new file mode 100644
index 0000000..cfb79f1
--- /dev/null
+++ b/src/exiv2.cpp
@@ -0,0 +1,285 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ * Copyright (C) 2004 Andreas Huggel <ahuggel at gmx.net>
+ *
+ * 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: $Name: $ $Revision: 1.1 $
+ Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
+ History: 10-Dec-03, ahu: created
+ */
+// *****************************************************************************
+#include "rcsid.hpp"
+EXIV2_RCSID("@(#) $Name: $ $Revision: 1.1 $ $RCSfile: exiv2.cpp,v $")
+
+// *****************************************************************************
+// included header files
+#include "exiv2.hpp"
+#include "actions.hpp"
+#include "utils.hpp"
+
+#include <string>
+#include <iostream>
+#include <iomanip>
+
+#include <cstring>
+#include <assert.h>
+
+// *********************************************************************
+// local declarations
+namespace {
+
+ // 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);
+}
+
+// *****************************************************************************
+// 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 = 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 << "
";
+ }
+ 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 << "Exiv2 version 0.3, "
+ << "Copyright (C) 2004 Andreas Huggel.
"
+ << "This is free software; see the source for copying conditions. "
+ << "There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR "
+ << "A PARTICULAR PURPOSE.
";
+}
+
+void Params::usage(std::ostream& os) const
+{
+ os << "Usage: " << progname()
+ << " [ -hVvf ][ -a time ][ -r format ] action file ...
"
+ << "Manipulate the Exif metadata of images.
";
+}
+
+void Params::help(std::ostream& os) const
+{
+ usage(os);
+ os << "
Options:
"
+ << " -h Display this help and exit.
"
+ << " -V Show the program version and exit.
"
+ << " -v Be more verbose during the program run.
"
+ << " -f Do not prompt before overwriting existing files (force).
"
+ << " -a time Time adjustment in the format [-]HH[:MM[:SS]]. This option
"
+ << " is only used with the `adjust' action.
"
+ << " -r fmt Filename format for the `rename' action. The format string
"
+ << " follows strftime(3). Default filename format is "
+ << format_ << ".
"
+ << "Actions:
"
+ << " adjust Adjust the metadata timestamp by the given time. This action
"
+ << " requires the option -a time.
"
+ << " print Print the Exif (or other) image metadata.
"
+ << " rename Rename files according to the metadata create timestamp. The
"
+ << " filename format can be set with the option -r format.
";
+} // 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;
+ break;
+
+ case 'a':
+ adjust_ = parseTime(optarg, adjustment_);
+ if (!adjust_) {
+ std::cerr << progname() << ": Error parsing -a option argument `"
+ << optarg << "'
";
+ rc = 1;
+ }
+ break;
+
+ case 'r':
+ format_ = optarg;
+ break;
+
+ case ':':
+ std::cerr << progname() << ": Option -" << static_cast<char>(optopt)
+ << " requires an argument
";
+ rc = 1;
+ break;
+
+ case '?':
+ std::cerr << progname() << ": Unrecognized option -"
+ << static_cast<char>(optopt) << "
";
+ rc = 1;
+ break;
+
+ default:
+ std::cerr << progname()
+ << ": getopt returned unexpected character code "
+ << std::hex << opt << "
";
+ rc = 1;
+ }
+
+ return rc;
+} // Params::option
+
+int Params::nonoption(const std::string& argv)
+{
+ int rc = 0;
+ if (first_) {
+ // The first non-option argument must be the action
+ first_ = false;
+ if (argv == "adjust") action_ = Action::adjust;
+ if (argv == "print") action_ = Action::print;
+ if (argv == "rename") action_ = Action::rename;
+ if (action_ == Action::none) {
+ std::cerr << progname() << ": Unrecognized action `"
+ << argv << "'
";
+ rc = 1;
+ }
+ }
+ else {
+ 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) {
+ std::cerr << progname() << ": An action must be specified
";
+ rc = 1;
+ }
+ if (action_ == Action::adjust && !adjust_) {
+ std::cerr << progname()
+ << ": Adjust action requires option -a time
";
+ rc = 1;
+ }
+ if (0 == files_.size()) {
+ std::cerr << progname() << ": At least one file is required
";
+ 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
+
+}
diff --git a/src/exiv2.hpp b/src/exiv2.hpp
new file mode 100644
index 0000000..8623717
--- /dev/null
+++ b/src/exiv2.hpp
@@ -0,0 +1,157 @@
+// ***************************************************************** -*- C++ -*-
+/*
+ * Copyright (C) 2004 Andreas Huggel <ahuggel at gmx.net>
+ *
+ * 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 $Name: $ $Revision: 1.1 $
+ @author Andreas Huggel (ahu)
+ <a href="mailto:ahuggel at gmx.net">ahuggel at gmx.net</a>
+ @date 08-Dec-03, ahu: created
+ */
+#ifndef EXIV2_HPP_
+#define EXIV2_HPP_
+
+// *****************************************************************************
+// included header files
+#include "utils.hpp"
+
+// + standard includes
+#include <string>
+#include <vector>
+#include <iostream>
+
+// *****************************************************************************
+// class definitions
+/*!
+ @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:
+ /*!
+ @brief Controls all access to the global Params instance.
+ @return Reference to the global Params instance.
+ */
+ static Params& instance();
+
+ bool help_; //!< Help option flag.
+ bool version_; //!< Version option flag.
+ bool verbose_; //!< Verbose (talkative) option flag.
+ bool force_; //!< Force overwrites flag.
+ bool adjust_; //!< Adjustment flag.
+ //! %Action (integer rather than TaskType to avoid dependency).
+ int action_;
+
+ long adjustment_; //!< Adjustment in seconds.
+ std::string format_; //!< Filename format (-r option arg).
+
+ //! Container to store filenames.
+ typedef std::vector<std::string> Files;
+
+ Files files_; //!< List of non-option arguments.
+
+private:
+ /*!
+ @brief Default constructor. Note that optstring_ is initialized here.
+ Private to force instantiation through instance().
+ */
+ Params() : optstring_(":hVvfa:r:"),
+ help_(false),
+ version_(false),
+ verbose_(false),
+ force_(false),
+ adjust_(false),
+ action_(0),
+ adjustment_(0),
+ format_("%Y%m%d_%H%M%S"),
+ first_(true) {}
+
+ //! Prevent copy-construction: not implemented.
+ Params(const Params& rhs);
+
+ //! 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_
--
exiv2 packaging
More information about the pkg-kde-commits
mailing list