[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