Blame samples/geotag.cpp

Packit 01d647
// ***************************************************************** -*- C++ -*-
Packit 01d647
// geotag.cpp
Packit 01d647
// Sample program to read gpx files and update images with GPS tags
Packit 01d647
Packit 01d647
// g++ geotag.cpp -o geotag -lexiv2 -lexpat
Packit 01d647
Packit 01d647
#include <exiv2/exiv2.hpp>
Packit 01d647
#include "unused.h"
Packit 01d647
Packit 01d647
#include <iostream>
Packit 01d647
#include <iomanip>
Packit 01d647
#include <cassert>
Packit 01d647
#include <algorithm>
Packit 01d647
Packit 01d647
#include <stdio.h>
Packit 01d647
#include <cstdlib>
Packit 01d647
#include <time.h>
Packit 01d647
#include <string.h>
Packit 01d647
#include <sys/stat.h>
Packit 01d647
#include <sys/types.h>
Packit 01d647
Packit 01d647
#include <expat.h>
Packit 01d647
Packit 01d647
#include <vector>
Packit 01d647
#include <string>
Packit 01d647
Packit 01d647
#if defined(__MINGW32__) || defined(__MINGW64__)
Packit 01d647
# ifndef  __MINGW__
Packit 01d647
#  define __MINGW__
Packit 01d647
# endif
Packit 01d647
#endif
Packit 01d647
Packit 01d647
using namespace std;
Packit 01d647
Packit 01d647
#ifndef  lengthof
Packit 01d647
#define  lengthof(x) (sizeof(*x)/sizeof(x))
Packit 01d647
#endif
Packit 01d647
Packit 01d647
#if defined(_MSC_VER) || defined(__MINGW__)
Packit 01d647
#include <windows.h>
Packit 01d647
char*    realpath(const char* file,char* path);
Packit 01d647
#define  lstat _stat
Packit 01d647
#define  stat  _stat
Packit 01d647
#if      _MSC_VER < 1400
Packit 01d647
#define strcpy_s(d,l,s) strcpy(d,s)
Packit 01d647
#define strcat_s(d,l,s) strcat(d,s)
Packit 01d647
#endif
Packit 01d647
#endif
Packit 01d647
Packit 01d647
#if ! defined(_MSC_VER)
Packit 01d647
#include <dirent.h>
Packit 01d647
#include <unistd.h>
Packit 01d647
#include <sys/param.h>
Packit 01d647
#define  stricmp strcasecmp
Packit 01d647
#endif
Packit 01d647
Packit 01d647
#ifndef _MAX_PATH
Packit 01d647
#define _MAX_PATH 1024
Packit 01d647
#endif
Packit 01d647
Packit 01d647
// prototypes
Packit 01d647
class Options;
Packit 01d647
int getFileType(const char* path ,Options& options);
Packit 01d647
int getFileType(std::string& path,Options& options);
Packit 01d647
Packit 01d647
string getExifTime(const time_t t);
Packit 01d647
time_t parseTime(const char* ,bool bAdjust=false);
Packit 01d647
int    timeZoneAdjust();
Packit 01d647
Packit 01d647
// platform specific code
Packit 01d647
#if defined(_MSC_VER) || defined(__MINGW__)
Packit 01d647
char* realpath(const char* file,char* path)
Packit 01d647
{
Packit 01d647
    char* result = (char*) malloc(_MAX_PATH);
Packit 01d647
    if   (result) GetFullPathName(file,_MAX_PATH,result,NULL);
Packit 01d647
    return result ;
Packit 01d647
    UNUSED(path);
Packit 01d647
}
Packit 01d647
#endif
Packit 01d647
Packit 01d647
// Command-line parser
Packit 01d647
class Options  {
Packit 01d647
public:
Packit 01d647
    bool        verbose;
Packit 01d647
    bool        help;
Packit 01d647
    bool        version;
Packit 01d647
    bool        dst;
Packit 01d647
    bool        dryrun;
Packit 01d647
    bool        ascii;
Packit 01d647
Packit 01d647
    Options()
Packit 01d647
    {
Packit 01d647
        verbose     = false;
Packit 01d647
        help        = false;
Packit 01d647
        version     = false;
Packit 01d647
        dst         = false;
Packit 01d647
        dryrun      = false;
Packit 01d647
        ascii       = false;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    virtual ~Options() {} ;
Packit 01d647
} ;
Packit 01d647
Packit 01d647
enum
Packit 01d647
{   resultOK=0
Packit 01d647
,   resultSyntaxError
Packit 01d647
,   resultSelectFailed
Packit 01d647
};
Packit 01d647
Packit 01d647
enum                        // keyword indices
Packit 01d647
{   kwHELP = 0
Packit 01d647
,   kwVERSION
Packit 01d647
,   kwDST
Packit 01d647
,   kwDRYRUN
Packit 01d647
,   kwASCII
Packit 01d647
,   kwVERBOSE
Packit 01d647
,   kwADJUST
Packit 01d647
,   kwTZ
Packit 01d647
,   kwDELTA
Packit 01d647
,   kwMAX                   // manages keyword array
Packit 01d647
,   kwNEEDVALUE             // bogus keywords for error reporting
Packit 01d647
,   kwSYNTAX                // -- ditto --
Packit 01d647
,   kwNOVALUE = -kwVERBOSE  // keywords <= kwNOVALUE are flags (no value needed)
Packit 01d647
};
Packit 01d647
Packit 01d647
// file types supported
Packit 01d647
enum
Packit 01d647
{   typeUnknown   = 0
Packit 01d647
,   typeDirectory = 1
Packit 01d647
,   typeImage     = 2
Packit 01d647
,   typeXML       = 3
Packit 01d647
,   typeFile      = 4
Packit 01d647
,   typeDoc       = 5
Packit 01d647
,   typeCode      = 6
Packit 01d647
,   typeMax       = 7
Packit 01d647
};
Packit 01d647
Packit 01d647
// forward declaration
Packit 01d647
class Position;
Packit 01d647
Packit 01d647
// globals
Packit 01d647
typedef std::map<time_t,Position>           TimeDict_t;
Packit 01d647
typedef std::map<time_t,Position>::iterator TimeDict_i;
Packit 01d647
typedef std::vector<std::string>            strings_t;
Packit 01d647
const char*  gDeg = NULL ; // string "°" or "deg"
Packit 01d647
TimeDict_t   gTimeDict   ;
Packit 01d647
strings_t    gFiles;
Packit 01d647
Packit 01d647
// Position (from gpx file)
Packit 01d647
class Position
Packit 01d647
{
Packit 01d647
public:
Packit 01d647
    Position(time_t time, double lat, double lon, double ele) :
Packit 01d647
        time_(time)
Packit 01d647
      , lon_(lon)
Packit 01d647
      , lat_(lat)
Packit 01d647
      , ele_(ele)
Packit 01d647
      , delta_(0)
Packit 01d647
    {}
Packit 01d647
Packit 01d647
    Position():
Packit 01d647
        time_(0)
Packit 01d647
      , lon_(0.0)
Packit 01d647
      , lat_(0.0)
Packit 01d647
      , ele_(0.0)
Packit 01d647
      , delta_(0)
Packit 01d647
    { }
Packit 01d647
Packit 01d647
    virtual ~Position() {}
Packit 01d647
//  copy constructor
Packit 01d647
    Position(const Position& o) :
Packit 01d647
        time_(o.time_)
Packit 01d647
      , lon_(o.lon_)
Packit 01d647
      , lat_(o.lat_)
Packit 01d647
      , ele_(o.ele_)
Packit 01d647
      , delta_(o.delta_)
Packit 01d647
    {}
Packit 01d647
Packit 01d647
//  instance methods
Packit 01d647
    bool good()                 { return time_ || lon_ || lat_ || ele_ ; }
Packit 01d647
    std::string getTimeString() { if ( times_.empty() ) times_ = getExifTime(time_) ;  return times_; }
Packit 01d647
    time_t      getTime()       { return time_ ; }
Packit 01d647
    std::string toString();
Packit 01d647
Packit 01d647
//  getters/setters
Packit 01d647
    double lat()            {return lat_   ;}
Packit 01d647
    double lon()            {return lon_   ;}
Packit 01d647
    double ele()            {return ele_   ;}
Packit 01d647
    int    delta()          {return delta_ ;}
Packit 01d647
    void   delta(int delta) {delta_=delta  ;}
Packit 01d647
Packit 01d647
//  data
Packit 01d647
private:
Packit 01d647
    time_t      time_;
Packit 01d647
    double      lon_ ;
Packit 01d647
    double      lat_ ;
Packit 01d647
    double      ele_ ;
Packit 01d647
    std::string times_;
Packit 01d647
    int         delta_;
Packit 01d647
Packit 01d647
// public static data
Packit 01d647
public:
Packit 01d647
    static int    adjust_  ;
Packit 01d647
    static int    tz_      ;
Packit 01d647
    static int    dst_     ;
Packit 01d647
    static time_t deltaMax_;
Packit 01d647
Packit 01d647
// public static member functions
Packit 01d647
public:
Packit 01d647
    static int    Adjust() {return Position::adjust_ + Position::tz_ + Position::dst_ ;}
Packit 01d647
    static int    tz()     {return tz_    ;}
Packit 01d647
    static int    dst()    {return dst_   ;}
Packit 01d647
    static int    adjust() {return adjust_;}
Packit 01d647
Packit 01d647
    static std::string toExifString(double d,bool bRational,bool bLat);
Packit 01d647
    static std::string toExifString(double d);
Packit 01d647
    static std::string toExifTimeStamp(std::string& t);
Packit 01d647
};
Packit 01d647
Packit 01d647
std::string Position::toExifTimeStamp(std::string& t)
Packit 01d647
{
Packit 01d647
    char        result[200];
Packit 01d647
    const char* arg = t.c_str();
Packit 01d647
    int HH = 0 ;
Packit 01d647
    int mm = 0 ;
Packit 01d647
    int SS = 0 ;
Packit 01d647
    if ( strstr(arg,":") || strstr(arg,"-") ) {
Packit 01d647
        int  YY,MM,DD    ;
Packit 01d647
        char a,b,c,d,e   ;
Packit 01d647
        sscanf(arg,"%d%c%d%c%d%c%d%c%d%c%d",&YY,&a,&MM,&b,&DD,&c,&HH,&d,&mm,&e,&SS;;
Packit 01d647
    }
Packit 01d647
    sprintf(result,"%d/1 %d/1 %d/1",HH,mm,SS);
Packit 01d647
    return std::string(result);
Packit 01d647
}
Packit 01d647
Packit 01d647
std::string Position::toExifString(double d)
Packit 01d647
{
Packit 01d647
    char result[200];
Packit 01d647
    d *= 100;
Packit 01d647
    sprintf(result,"%d/100",abs((int)d));
Packit 01d647
    return std::string(result);
Packit 01d647
}
Packit 01d647
Packit 01d647
std::string Position::toExifString(double d,bool bRational,bool bLat)
Packit 01d647
{
Packit 01d647
    const char* NS   = d>=0.0?"N":"S";
Packit 01d647
    const char* EW   = d>=0.0?"E":"W";
Packit 01d647
    const char* NSEW = bLat  ? NS: EW;
Packit 01d647
    if ( d < 0 ) d = -d;
Packit 01d647
    int deg = (int) d;
Packit 01d647
        d  -= deg;
Packit 01d647
        d  *= 60;
Packit 01d647
    int min = (int) d ;
Packit 01d647
        d  -= min;
Packit 01d647
        d  *= 60;
Packit 01d647
    int sec = (int)d;
Packit 01d647
    char result[200];
Packit 01d647
    if ( bRational )
Packit 01d647
        sprintf(result,"%d/1 %d/1 %d/1" ,deg,min,sec);
Packit 01d647
    else
Packit 01d647
        sprintf(result,"%03d%s%02d'%02d\"%s" ,deg,gDeg,min,sec,NSEW);
Packit 01d647
    return std::string(result);
Packit 01d647
}
Packit 01d647
Packit 01d647
std::string Position::toString()
Packit 01d647
{
Packit 01d647
    char result[200];
Packit 01d647
    std::string sLat = Position::toExifString(lat_,false,true );
Packit 01d647
    std::string sLon = Position::toExifString(lon_,false,false);
Packit 01d647
    sprintf(result,"%s %s %-8.3f",sLon.c_str(),sLat.c_str(),ele_);
Packit 01d647
    return std::string(result);
Packit 01d647
}
Packit 01d647
Packit 01d647
// defaults
Packit 01d647
int    Position::adjust_   = 0;
Packit 01d647
int    Position::tz_       = timeZoneAdjust();
Packit 01d647
int    Position::dst_      = 0;
Packit 01d647
time_t Position::deltaMax_ = 60 ;
Packit 01d647
Packit 01d647
///////////////////////////////////////////////////////////
Packit 01d647
// UserData - used by XML Parser
Packit 01d647
class UserData
Packit 01d647
{
Packit 01d647
public:
Packit 01d647
    explicit UserData(Options& options):
Packit 01d647
        indent(0)
Packit 01d647
      , count(0)
Packit 01d647
      , nTrkpt(0)
Packit 01d647
      , bTime(false)
Packit 01d647
      , bEle(false)
Packit 01d647
      , ele(0.0)
Packit 01d647
      , lat(0.0)
Packit 01d647
      , lon(0.0)
Packit 01d647
      , options_(options)
Packit 01d647
    {}
Packit 01d647
    virtual ~UserData() {}
Packit 01d647
Packit 01d647
//  public data members
Packit 01d647
    int         indent;
Packit 01d647
    size_t      count ;
Packit 01d647
    Position    now ;
Packit 01d647
    Position    prev;
Packit 01d647
    int         nTrkpt;
Packit 01d647
    bool        bTime ;
Packit 01d647
    bool        bEle  ;
Packit 01d647
    double      ele;
Packit 01d647
    double      lat;
Packit 01d647
    double      lon;
Packit 01d647
    std::string xmlt;
Packit 01d647
    std::string exift;
Packit 01d647
    time_t      time;
Packit 01d647
    Options&    options_;
Packit 01d647
// static public data memembers
Packit 01d647
};
Packit 01d647
Packit 01d647
// XML Parser Callbacks
Packit 01d647
static void startElement(void* userData, const char* name, const char** atts )
Packit 01d647
{
Packit 01d647
    UserData* me = (UserData*) userData;
Packit 01d647
    //for ( int i = 0 ; i < me->indent ; i++ ) printf(" ");
Packit 01d647
    //printf("begin %s\n",name);
Packit 01d647
    me->bTime = strcmp(name,"time")==0;
Packit 01d647
    me->bEle  = strcmp(name,"ele")==0;
Packit 01d647
Packit 01d647
    if ( strcmp(name,"trkpt")==0 ) {
Packit 01d647
        me->nTrkpt++;
Packit 01d647
        while ( *atts ) {
Packit 01d647
            const char* a=atts[0];
Packit 01d647
            const char* v=atts[1];
Packit 01d647
            if ( !strcmp(a,"lat") ) me->lat = atof(v);
Packit 01d647
            if ( !strcmp(a,"lon") ) me->lon = atof(v);
Packit 01d647
            atts += 2 ;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
    me->count++  ;
Packit 01d647
    me->indent++ ;
Packit 01d647
}
Packit 01d647
Packit 01d647
static void endElement(void* userData, const char* name)
Packit 01d647
{
Packit 01d647
    UserData* me = (UserData*) userData;
Packit 01d647
    me->indent-- ;
Packit 01d647
    if ( strcmp(name,"trkpt")==0 ) {
Packit 01d647
Packit 01d647
        me->nTrkpt--;
Packit 01d647
        me->now = Position(me->time,me->lat,me->lon,me->ele) ;
Packit 01d647
Packit 01d647
        if ( !me->prev.good() && me->options_.verbose ) {
Packit 01d647
            printf("trkseg %s begin ",me->now.getTimeString().c_str());
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // remember our location and put it in gTimeDict
Packit 01d647
        gTimeDict[me->time] = me->now ;
Packit 01d647
        me->prev = me->now ;
Packit 01d647
    }
Packit 01d647
    if ( strcmp(name,"trkseg")==0 && me->options_.verbose ) {
Packit 01d647
        printf("%s end\n",me->now.getTimeString().c_str());
Packit 01d647
    }
Packit 01d647
}
Packit 01d647
Packit 01d647
void charHandler(void* userData,const char* s,int len)
Packit 01d647
{
Packit 01d647
    UserData* me = (UserData*) userData;
Packit 01d647
Packit 01d647
    if ( me->nTrkpt == 1 ) {
Packit 01d647
        char buffer[100];
Packit 01d647
        int  l_max = 98 ; // lengthof(buffer) -2 ;
Packit 01d647
Packit 01d647
        if ( me->bTime && len > 5 ) {
Packit 01d647
            if ( len < l_max ) {
Packit 01d647
                memcpy(buffer,s,len);
Packit 01d647
                buffer[len]=0;
Packit 01d647
                char* b = buffer ;
Packit 01d647
                while ( *b == ' ' && b < buffer+len ) b++ ;
Packit 01d647
                me->xmlt  = b ;
Packit 01d647
                me->time  = parseTime(me->xmlt.c_str());
Packit 01d647
                me->exift = getExifTime(me->time);
Packit 01d647
            }
Packit 01d647
            me->bTime=false;
Packit 01d647
        }
Packit 01d647
        if ( me->bEle && len > 2 ) {
Packit 01d647
            if ( len < l_max ) {
Packit 01d647
                memcpy(buffer,s,len);
Packit 01d647
                buffer[len]=0;
Packit 01d647
                char* b = buffer ;
Packit 01d647
                while ( *b == ' ' && b < buffer+len ) b++ ;
Packit 01d647
                me->ele = atof(b);
Packit 01d647
            }
Packit 01d647
            me->bEle=false;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
}
Packit 01d647
Packit 01d647
///////////////////////////////////////////////////////////
Packit 01d647
// Time Functions
Packit 01d647
time_t parseTime(const char* arg,bool bAdjust)
Packit 01d647
{
Packit 01d647
    time_t result = 0 ;
Packit 01d647
    try {
Packit 01d647
        //559 rmills@rmills-imac:~/bin $ exiv2 -pa ~/R.jpg | grep -i date
Packit 01d647
        //Exif.Image.DateTime                          Ascii      20  2009:08:03 08:58:57
Packit 01d647
        //Exif.Photo.DateTimeOriginal                  Ascii      20  2009:08:03 08:58:57
Packit 01d647
        //Exif.Photo.DateTimeDigitized                 Ascii      20  2009:08:03 08:58:57
Packit 01d647
        //Exif.GPSInfo.GPSDateStamp                    Ascii      21  2009-08-03T15:58:57Z
Packit 01d647
Packit 01d647
        // <time>2012-07-14T17:33:16Z</time>
Packit 01d647
Packit 01d647
        if ( strstr(arg,":") || strstr(arg,"-") ) {
Packit 01d647
            int  YY,MM,DD,HH,mm,SS ;
Packit 01d647
            char a,b,c,d,e   ;
Packit 01d647
            sscanf(arg,"%d%c%d%c%d%c%d%c%d%c%d",&YY,&a,&MM,&b,&DD,&c,&HH,&d,&mm,&e,&SS;;
Packit 01d647
Packit 01d647
            struct tm T;
Packit 01d647
            memset(&T,0,sizeof(T));
Packit 01d647
            T.tm_min  = mm  ;
Packit 01d647
            T.tm_hour = HH  ;
Packit 01d647
            T.tm_sec  = SS  ;
Packit 01d647
            if ( bAdjust ) T.tm_sec -= Position::Adjust();
Packit 01d647
            T.tm_year = YY -1900 ;
Packit 01d647
            T.tm_mon  = MM -1    ;
Packit 01d647
            T.tm_mday = DD  ;
Packit 01d647
            T.tm_isdst = -1 ; // determine value automatically (otherwise hour may shift)
Packit 01d647
            result = mktime(&T);
Packit 01d647
        }
Packit 01d647
    } catch ( ... ) {};
Packit 01d647
    return result ;
Packit 01d647
}
Packit 01d647
Packit 01d647
// West of GMT is negative (PDT = Pacific Daylight = -07:00 == -25200 seconds
Packit 01d647
int timeZoneAdjust()
Packit 01d647
{
Packit 01d647
    time_t    now   = time(NULL);
Packit 01d647
    int       offset;
Packit 01d647
Packit 01d647
#if   defined(_MSC_VER) || defined(__MINGW__)
Packit 01d647
    TIME_ZONE_INFORMATION TimeZoneInfo;
Packit 01d647
    GetTimeZoneInformation( &TimeZoneInfo );
Packit 01d647
    offset = - (((int)TimeZoneInfo.Bias + (int)TimeZoneInfo.DaylightBias) * 60);
Packit 01d647
    UNUSED(now);
Packit 01d647
#elif defined(__CYGWIN__)
Packit 01d647
    struct tm lcopy = *localtime(&now;;
Packit 01d647
    time_t    gmt   =  timegm(&lcopy) ; // timegm modifies lcopy
Packit 01d647
    offset          = (int) ( ((long signed int) gmt) - ((long signed int) now) ) ;
Packit 01d647
#elif defined(OS_SOLARIS)
Packit 01d647
    struct tm local = *localtime(&now) ;
Packit 01d647
    time_t local_tt = (int) mktime(&local);
Packit 01d647
    time_t time_gmt = (int) mktime(gmtime(&now));
Packit 01d647
    offset          = time_gmt - local_tt;
Packit 01d647
#else
Packit 01d647
    struct tm local = *localtime(&now) ;
Packit 01d647
    offset          = local.tm_gmtoff ;
Packit 01d647
Packit 01d647
#if EXIV2_DEBUG_MESSAGES
Packit 01d647
    struct tm utc = *gmtime(&now;;
Packit 01d647
    printf("utc  :  offset = %6d dst = %d time = %s", 0     ,utc  .tm_isdst, asctime(&utc  ));
Packit 01d647
    printf("local:  offset = %6d dst = %d time = %s", offset,local.tm_isdst, asctime(&local));
Packit 01d647
    printf("timeZoneAdjust = %6d\n",offset);
Packit 01d647
#endif
Packit 01d647
#endif
Packit 01d647
    return offset ;
Packit 01d647
}
Packit 01d647
Packit 01d647
string getExifTime(const time_t t)
Packit 01d647
{
Packit 01d647
    static char result[100];
Packit 01d647
    strftime(result,sizeof(result),"%Y-%m-%d %H:%M:%S",localtime(&t);;
Packit 01d647
    return result ;
Packit 01d647
}
Packit 01d647
Packit 01d647
std::string makePath(const std::string& dir, const std::string& file)
Packit 01d647
{
Packit 01d647
    return dir + std::string(EXV_SEPARATOR_STR) + file ;
Packit 01d647
}
Packit 01d647
Packit 01d647
const char* makePath(const char* dir,const char* file)
Packit 01d647
{
Packit 01d647
    static char result[_MAX_PATH] ;
Packit 01d647
    std::string r = makePath(std::string(dir),std::string(file));
Packit 01d647
    strcpy(result,r.c_str());
Packit 01d647
    return result;
Packit 01d647
}
Packit 01d647
Packit 01d647
// file utilities
Packit 01d647
bool readDir(const char* path,Options& options)
Packit 01d647
{
Packit 01d647
    bool bResult = false;
Packit 01d647
Packit 01d647
#ifdef _MSC_VER
Packit 01d647
    DWORD attrs    =  GetFileAttributes(path);
Packit 01d647
    bool  bOKAttrs =  attrs != INVALID_FILE_ATTRIBUTES;
Packit 01d647
    bool  bIsDir   = (attrs  & FILE_ATTRIBUTE_DIRECTORY) ? true : false ;
Packit 01d647
Packit 01d647
    if( bOKAttrs && bIsDir ) {
Packit 01d647
        bResult = true ;
Packit 01d647
Packit 01d647
        char     search[_MAX_PATH+10];
Packit 01d647
        strcpy_s(search,_MAX_PATH,path);
Packit 01d647
        strcat_s(search,_MAX_PATH,"\\*");
Packit 01d647
Packit 01d647
        WIN32_FIND_DATA ffd;
Packit 01d647
        HANDLE  hFind = FindFirstFile(search, &ffd;;
Packit 01d647
        BOOL    bGo = hFind != INVALID_HANDLE_VALUE;
Packit 01d647
Packit 01d647
        if ( bGo ) {
Packit 01d647
            while ( bGo ) {
Packit 01d647
                if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
Packit 01d647
                {
Packit 01d647
                    // _tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);
Packit 01d647
                }
Packit 01d647
                else
Packit 01d647
                {
Packit 01d647
                    std::string pathName = makePath(path,std::string(ffd.cFileName));
Packit 01d647
                    if ( getFileType(pathName,options) == typeImage ) {
Packit 01d647
                        gFiles.push_back( pathName );
Packit 01d647
                    }
Packit 01d647
                }
Packit 01d647
                bGo = FindNextFile(hFind, &ffd) != 0;
Packit 01d647
            }
Packit 01d647
            // CloseHandle(hFind);
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
#else
Packit 01d647
    DIR*    dir = opendir (path);
Packit 01d647
    if (dir != NULL)
Packit 01d647
    {
Packit 01d647
        bResult = true;
Packit 01d647
        struct dirent*  ent;
Packit 01d647
Packit 01d647
        // print all the files and directories within directory
Packit 01d647
        while ((ent = readdir (dir)) != NULL)
Packit 01d647
        {
Packit 01d647
            std::string pathName = makePath(path,ent->d_name);
Packit 01d647
            struct stat  buf     ;
Packit 01d647
            lstat(path, &buf );
Packit 01d647
            if ( ent->d_name[0] != '.' ) {
Packit 01d647
Packit 01d647
                // printf("reading %s => %s\n",ent->d_name,pathName.c_str());
Packit 01d647
                if ( getFileType(pathName,options) == typeImage ) {
Packit 01d647
                    gFiles.push_back( pathName );
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        closedir (dir);
Packit 01d647
    }
Packit 01d647
#endif
Packit 01d647
    return bResult ;
Packit 01d647
}
Packit 01d647
Packit 01d647
inline size_t sip(FILE* f,char* buffer,size_t max_len,size_t len)
Packit 01d647
{
Packit 01d647
    while ( !feof(f) && len < max_len && buffer[len-1] != '>')
Packit 01d647
        buffer[len++] = fgetc(f);
Packit 01d647
    return len;
Packit 01d647
}
Packit 01d647
Packit 01d647
bool readXML(const char* path,Options& options)
Packit 01d647
{
Packit 01d647
    FILE*       f       = fopen(path,"r");
Packit 01d647
    XML_Parser  parser  = XML_ParserCreate(NULL);
Packit 01d647
    bool bResult        = f && parser ;
Packit 01d647
    if ( bResult ) {
Packit 01d647
        char   buffer[8*1024];
Packit 01d647
        UserData me(options) ;
Packit 01d647
Packit 01d647
        XML_SetUserData            (parser, &me);
Packit 01d647
        XML_SetElementHandler      (parser, startElement, endElement);
Packit 01d647
        XML_SetCharacterDataHandler(parser,charHandler);
Packit 01d647
Packit 01d647
        // a little sip at the data
Packit 01d647
        size_t len = fread(buffer,1,sizeof(buffer)-100,f);
Packit 01d647
        const char* lead   = "
Packit 01d647
        bResult = strncmp(lead,buffer,strlen(lead))==0;
Packit 01d647
Packit 01d647
        // swallow it
Packit 01d647
        if ( bResult ) {
Packit 01d647
            len = sip(f,buffer,sizeof buffer,len);
Packit 01d647
            bResult = XML_Parse(parser, buffer,(int)len, len == 0 ) == XML_STATUS_OK;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // drink the rest of the file
Packit 01d647
        while ( bResult && len != 0 ) {
Packit 01d647
            len = fread(buffer,1,sizeof(buffer)-100,f);
Packit 01d647
            len = sip(f,buffer,sizeof buffer,len);
Packit 01d647
            bResult = XML_Parse(parser, buffer,(int)len, len == 0 ) == XML_STATUS_OK;
Packit 01d647
        };
Packit 01d647
    }
Packit 01d647
Packit 01d647
    if ( f      ) fclose(f);
Packit 01d647
    if ( parser ) XML_ParserFree(parser);
Packit 01d647
Packit 01d647
    return bResult ;
Packit 01d647
}
Packit 01d647
Packit 01d647
bool readImage(const char* path,Options& /* options */)
Packit 01d647
{
Packit 01d647
    using namespace Exiv2;
Packit 01d647
    bool bResult = false ;
Packit 01d647
Packit 01d647
    try {
Packit 01d647
        Image::AutoPtr image = ImageFactory::open(path);
Packit 01d647
        if ( image.get() ) {
Packit 01d647
            image->readMetadata();
Packit 01d647
            ExifData &exifData = image->exifData();
Packit 01d647
            bResult = !exifData.empty();
Packit 01d647
        }
Packit 01d647
    } catch ( ... ) {};
Packit 01d647
    return bResult ;
Packit 01d647
}
Packit 01d647
Packit 01d647
time_t readImageTime(const std::string& path,std::string* pS=NULL)
Packit 01d647
{
Packit 01d647
    using namespace Exiv2;
Packit 01d647
Packit 01d647
    time_t       result       = 0 ;
Packit 01d647
Packit 01d647
    const char* dateStrings[] =
Packit 01d647
    { "Exif.Photo.DateTimeOriginal"
Packit 01d647
    , "Exif.Photo.DateTimeDigitized"
Packit 01d647
    , "Exif.Image.DateTime"
Packit 01d647
    , NULL
Packit 01d647
    };
Packit 01d647
    const char* dateString = dateStrings[0] ;
Packit 01d647
Packit 01d647
    do {
Packit 01d647
        try {
Packit 01d647
            Image::AutoPtr image = ImageFactory::open(path);
Packit 01d647
            if ( image.get() ) {
Packit 01d647
                image->readMetadata();
Packit 01d647
                ExifData &exifData = image->exifData();
Packit 01d647
            //  printf("%s => %s\n",dateString, exifData[dateString].toString().c_str());
Packit 01d647
                result = parseTime(exifData[dateString].toString().c_str(),true);
Packit 01d647
                if ( result && pS ) *pS = exifData[dateString].toString();
Packit 01d647
            }
Packit 01d647
        } catch ( ... ) {};
Packit 01d647
    } while ( !result && ++dateString );
Packit 01d647
Packit 01d647
    return result ;
Packit 01d647
}
Packit 01d647
Packit 01d647
bool sina(const char* s,const char** a)
Packit 01d647
{
Packit 01d647
    bool bResult = false ;
Packit 01d647
    int i = 0 ;
Packit 01d647
    while ( *s == '-' ) s++;
Packit 01d647
    while ( !bResult && a[i]) {
Packit 01d647
        const char* A = a[i] ;
Packit 01d647
        while ( *A == '-' ) A++ ;
Packit 01d647
        bResult = stricmp(s,A)==0;
Packit 01d647
        i++;
Packit 01d647
    }
Packit 01d647
    return bResult;
Packit 01d647
}
Packit 01d647
Packit 01d647
int readFile(const char* path,Options /* options */)
Packit 01d647
{
Packit 01d647
    FILE* f     = fopen(path,"r");
Packit 01d647
    int nResult = f ? typeFile : typeUnknown;
Packit 01d647
    if (  f ) {
Packit 01d647
        const char*  ext   = strstr(path,".");
Packit 01d647
        if  ( ext ) {
Packit 01d647
            const char* docs[] = { ".doc",".txt", NULL };
Packit 01d647
            const char* code[] = { ".cpp",".h"  ,".pl" ,".py" ,".pyc", NULL };
Packit 01d647
            if ( sina(ext,docs) )
Packit 01d647
                nResult = typeDoc;
Packit 01d647
            if ( sina(ext,code) )
Packit 01d647
                nResult = typeCode;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
    if ( f ) fclose(f) ;
Packit 01d647
Packit 01d647
    return nResult ;
Packit 01d647
}
Packit 01d647
Packit 01d647
Position* searchTimeDict(TimeDict_t& td, const time_t& time,long long delta)
Packit 01d647
{
Packit 01d647
    Position* result = NULL;
Packit 01d647
    for ( int t = 0 ; !result && t < delta ; t++ ) {
Packit 01d647
        for ( int x = 0 ; !result && x < 2 ; x++ ) {
Packit 01d647
            int T = t * ((x==0)?-1:1);
Packit 01d647
            if ( td.count(time+T) ) {
Packit 01d647
                result = &td[time+T];
Packit 01d647
                result->delta(T);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
    return result;
Packit 01d647
}
Packit 01d647
Packit 01d647
int getFileType(std::string& path,Options& options) { return getFileType(path.c_str(),options); }
Packit 01d647
int getFileType(const char* path,Options& options)
Packit 01d647
{
Packit 01d647
    return readXML  (path,options) ? typeXML
Packit 01d647
        :  readDir  (path,options) ? typeDirectory
Packit 01d647
        :  readImage(path,options) ? typeImage
Packit 01d647
        :  readFile (path,options)
Packit 01d647
        ;
Packit 01d647
}
Packit 01d647
Packit 01d647
int version(const char* program)
Packit 01d647
{
Packit 01d647
    printf("%s: %s %s\n",program,__DATE__,__TIME__);
Packit 01d647
    return 0;
Packit 01d647
}
Packit 01d647
Packit 01d647
int help(const char* program,char const* words[],int nWords,bool /*bVerbose*/)
Packit 01d647
{
Packit 01d647
    printf("usage: %s ",program);
Packit 01d647
    for ( int i = 0 ; i < nWords ; i++ ) {
Packit 01d647
        if ( words[i] )
Packit 01d647
            printf("%c-%s%s",i?'|':'{',words[i],i>(-kwNOVALUE)?" value":"");
Packit 01d647
    }
Packit 01d647
    printf("}+ path+\n");
Packit 01d647
    return 0;
Packit 01d647
}
Packit 01d647
Packit 01d647
int compare(const char* a,const char* b)
Packit 01d647
{
Packit 01d647
    int result=*a && *b;
Packit 01d647
    while ( result && *a && *b) {
Packit 01d647
        char A=*a++;
Packit 01d647
        char B=*b++;
Packit 01d647
        result=tolower(A)==tolower(B);
Packit 01d647
    }
Packit 01d647
    return result;
Packit 01d647
}
Packit 01d647
Packit 01d647
int find(const char* arg,char const* words[],int nWords)
Packit 01d647
{
Packit 01d647
    if ( arg[0] != '-' ) return kwSYNTAX;
Packit 01d647
Packit 01d647
    int result=0;
Packit 01d647
    int count =0;
Packit 01d647
Packit 01d647
    for ( int i = 0 ; i < nWords ; i++) {
Packit 01d647
        int j = 0 ;
Packit 01d647
        while ( arg[j] == '-' ) j++;
Packit 01d647
        if ( ::compare(arg+j,words[i]) ) {
Packit 01d647
            result = i ;
Packit 01d647
            count++;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    return count==1?result:kwSYNTAX;
Packit 01d647
}
Packit 01d647
Packit 01d647
int parseTZ(const char* adjust)
Packit 01d647
{
Packit 01d647
    int   h=0;
Packit 01d647
    int   m=0;
Packit 01d647
    char  c  ;
Packit 01d647
    try {
Packit 01d647
        sscanf(adjust,"%d%c%d",&h,&c,&m);
Packit 01d647
    } catch ( ... ) {} ;
Packit 01d647
Packit 01d647
    return (3600*h)+(60*m);
Packit 01d647
}
Packit 01d647
Packit 01d647
bool mySort(const std::string& a, const std::string& b)
Packit 01d647
{
Packit 01d647
    time_t A = readImageTime(a);
Packit 01d647
    time_t B = readImageTime(b);
Packit 01d647
    return (A
Packit 01d647
}
Packit 01d647
Packit 01d647
int main(int argc,const char* argv[])
Packit 01d647
{
Packit 01d647
    int result=0;
Packit 01d647
    const char* program = argv[0];
Packit 01d647
Packit 01d647
    const char* types[typeMax];
Packit 01d647
    types[typeUnknown  ] = "unknown";
Packit 01d647
    types[typeDirectory] = "directory";
Packit 01d647
    types[typeImage    ] = "image";
Packit 01d647
    types[typeXML      ] = "xml";
Packit 01d647
    types[typeDoc      ] = "doc";
Packit 01d647
    types[typeCode     ] = "code";
Packit 01d647
    types[typeFile     ] = "file";
Packit 01d647
Packit 01d647
    char const* keywords[kwMAX];
Packit 01d647
    memset(keywords,0,sizeof(keywords));
Packit 01d647
    keywords[kwHELP    ] = "help";
Packit 01d647
    keywords[kwVERSION ] = "version";
Packit 01d647
    keywords[kwVERBOSE ] = "verbose";
Packit 01d647
    keywords[kwDRYRUN  ] = "dryrun";
Packit 01d647
    keywords[kwASCII   ] = "ascii";
Packit 01d647
    keywords[kwDST     ] = "dst";
Packit 01d647
    keywords[kwADJUST  ] = "adjust";
Packit 01d647
    keywords[kwTZ      ] = "tz";
Packit 01d647
    keywords[kwDELTA   ] = "delta";
Packit 01d647
Packit 01d647
    map<std::string,string> shorts;
Packit 01d647
    shorts["-?"] = "-help";
Packit 01d647
    shorts["-h"] = "-help";
Packit 01d647
    shorts["-v"] = "-verbose";
Packit 01d647
    shorts["-V"] = "-version";
Packit 01d647
    shorts["-d"] = "-dst";
Packit 01d647
    shorts["-a"] = "-adjust";
Packit 01d647
    shorts["-t"] = "-tz";
Packit 01d647
    shorts["-D"] = "-delta";
Packit 01d647
    shorts["-s"] = "-delta";
Packit 01d647
    shorts["-X"] = "-dryrun";
Packit 01d647
    shorts["-a"] = "-ascii";
Packit 01d647
Packit 01d647
    Options options ;
Packit 01d647
    options.help    = sina(keywords[kwHELP   ],argv) || argc < 2;
Packit 01d647
    options.verbose = sina(keywords[kwVERBOSE],argv);
Packit 01d647
    options.dryrun  = sina(keywords[kwDRYRUN ],argv);
Packit 01d647
    options.version = sina(keywords[kwVERSION],argv);
Packit 01d647
    options.dst     = sina(keywords[kwDST    ],argv);
Packit 01d647
    options.ascii   = sina(keywords[kwASCII  ],argv);
Packit 01d647
Packit 01d647
    for ( int i = 1 ; !result && i < argc ; i++ ) {
Packit 01d647
        const char* arg   = argv[i++];
Packit 01d647
        if ( shorts.count(arg) ) arg = shorts[arg].c_str();
Packit 01d647
Packit 01d647
        const char* value = argv[i  ];
Packit 01d647
        int        ivalue = ::atoi(value?value:"0");
Packit 01d647
        int         key   = ::find(arg,keywords,kwMAX);
Packit 01d647
        int         needv = key < kwMAX && key > (-kwNOVALUE);
Packit 01d647
Packit 01d647
        if (!needv ) i--;
Packit 01d647
        if ( needv && !value) key = kwNEEDVALUE;
Packit 01d647
Packit 01d647
        switch ( key ) {
Packit 01d647
            case kwDST      : options.dst         = true ; break;
Packit 01d647
            case kwHELP     : options.help        = true ; break;
Packit 01d647
            case kwVERSION  : options.version     = true ; break;
Packit 01d647
            case kwDRYRUN   : options.dryrun      = true ; break;
Packit 01d647
            case kwVERBOSE  : options.verbose     = true ; break;
Packit 01d647
            case kwASCII    : options.ascii       = true ; break;
Packit 01d647
            case kwTZ       : Position::tz_       = parseTZ(value);break;
Packit 01d647
            case kwADJUST   : Position::adjust_   = ivalue;break;
Packit 01d647
            case kwDELTA    : Position::deltaMax_ = ivalue;break;
Packit 01d647
            case kwNEEDVALUE: fprintf(stderr,"error: %s requires a value\n",arg); result = resultSyntaxError ; break ;
Packit 01d647
            case kwSYNTAX   : default:
Packit 01d647
            {
Packit 01d647
                int  type   = getFileType(arg,options) ;
Packit 01d647
                if ( options.verbose ) printf("%s %s ",arg,types[type]) ;
Packit 01d647
                if ( type == typeImage ) {
Packit 01d647
                    time_t t    = readImageTime(std::string(arg)) ;
Packit 01d647
#ifdef __APPLE__
Packit 01d647
                    char   buffer[1024];
Packit 01d647
#else
Packit 01d647
                    char*  buffer = NULL;
Packit 01d647
#endif
Packit 01d647
                    char*  path = realpath(arg,buffer);
Packit 01d647
                    if  ( t && path ) {
Packit 01d647
                        if ( options.verbose) printf("%s %ld %s",path,(long int)t,asctime(localtime(&t)));
Packit 01d647
                        gFiles.push_back(path);
Packit 01d647
                    }
Packit 01d647
                    if ( path && path != buffer ) ::free((void*) path);
Packit 01d647
                }
Packit 01d647
                if ( type == typeUnknown ) {
Packit 01d647
                    fprintf(stderr,"error: illegal syntax %s\n",arg);
Packit 01d647
                    result = resultSyntaxError ;
Packit 01d647
                }
Packit 01d647
            } break;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    if ( options.help    ) ::help(program,keywords,kwMAX,options.verbose);
Packit 01d647
    if ( options.version ) ::version(program);
Packit 01d647
    gDeg = options.ascii ? "deg" : "°";
Packit 01d647
Packit 01d647
    if ( !result ) {
Packit 01d647
        sort(gFiles.begin(),gFiles.end(),mySort);
Packit 01d647
        if ( options.dst ) Position::dst_ = 3600;
Packit 01d647
        if ( options.verbose ) {
Packit 01d647
            int t = Position::tz();
Packit 01d647
            int d = Position::dst();
Packit 01d647
            int a = Position::adjust();
Packit 01d647
            int A = Position::Adjust();
Packit 01d647
            int s = A     ;
Packit 01d647
            int h = s/3600;
Packit 01d647
                s-= h*3600;
Packit 01d647
                s = abs(s);
Packit 01d647
            int m = s/60  ;
Packit 01d647
                s-= m*60  ;
Packit 01d647
            printf("tz,dst,adjust = %d,%d,%d total = %dsecs (= %d:%d:%d)\n",t,d,a,A,h,m,s);
Packit 01d647
        }
Packit 01d647
/*
Packit 01d647
        if ( options.verbose ) {
Packit 01d647
            printf("Time Dictionary\n");
Packit 01d647
            for ( TimeDict_i it = gTimeDict.begin() ;  it != gTimeDict.end() ; it++ ) {
Packit 01d647
                std::string sTime = getExifTime(it->first);
Packit 01d647
                Position*   pPos  = &it->second;
Packit 01d647
                std::string sPos  = Position::toExifString(pPos->lat(),false,true)
Packit 01d647
                                  + " "
Packit 01d647
                                  + Position::toExifString(pPos->lon(),false,true)
Packit 01d647
                                  ;
Packit 01d647
                printf("%s %s\n",sTime.c_str(), sPos.c_str());
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
*/
Packit 01d647
        for ( size_t p = 0 ; p < gFiles.size() ; p++ ) {
Packit 01d647
            std::string path  = gFiles[p] ;
Packit 01d647
            std::string stamp ;
Packit 01d647
            try {
Packit 01d647
                time_t t       = readImageTime(path,&stamp) ;
Packit 01d647
                Position* pPos = searchTimeDict(gTimeDict,t,Position::deltaMax_);
Packit 01d647
                Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
Packit 01d647
                if ( image.get() ) {
Packit 01d647
                    image->readMetadata();
Packit 01d647
                    Exiv2::ExifData& exifData = image->exifData();
Packit 01d647
                    if ( pPos ) {
Packit 01d647
                        exifData["Exif.GPSInfo.GPSProcessingMethod" ] = "65 83 67 73 73 0 0 0 72 89 66 82 73 68 45 70 73 88"; // ASCII HYBRID-FIX
Packit 01d647
                        exifData["Exif.GPSInfo.GPSVersionID"        ] = "2 2 0 0";
Packit 01d647
                        exifData["Exif.GPSInfo.GPSMapDatum"         ] = "WGS-84";
Packit 01d647
Packit 01d647
                        exifData["Exif.GPSInfo.GPSLatitude"         ] = Position::toExifString(pPos->lat(),true,true);
Packit 01d647
                        exifData["Exif.GPSInfo.GPSLongitude"        ] = Position::toExifString(pPos->lon(),true,false);
Packit 01d647
                        exifData["Exif.GPSInfo.GPSAltitude"         ] = Position::toExifString(pPos->ele());
Packit 01d647
Packit 01d647
                        exifData["Exif.GPSInfo.GPSAltitudeRef"      ] = pPos->ele()<0.0?"1":"0";
Packit 01d647
                        exifData["Exif.GPSInfo.GPSLatitudeRef"      ] = pPos->lat()>0?"N":"S";
Packit 01d647
                        exifData["Exif.GPSInfo.GPSLongitudeRef"     ] = pPos->lon()>0?"E":"W";
Packit 01d647
Packit 01d647
                        exifData["Exif.GPSInfo.GPSDateStamp"        ] = stamp;
Packit 01d647
                        exifData["Exif.GPSInfo.GPSTimeStamp"        ] = Position::toExifTimeStamp(stamp);
Packit 01d647
                        exifData["Exif.Image.GPSTag"                ] = 4908;
Packit 01d647
Packit 01d647
                        printf("%s %s % 2d\n",path.c_str(),pPos->toString().c_str(),pPos->delta());
Packit 01d647
                    } else {
Packit 01d647
                        printf("%s *** not in time dict ***\n",path.c_str());
Packit 01d647
                    }
Packit 01d647
                    if ( !options.dryrun ) image->writeMetadata();
Packit 01d647
                }
Packit 01d647
            } catch ( ... ) {};
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    return result ;
Packit 01d647
}
Packit 01d647
Packit 01d647
// That's all Folks!
Packit 01d647
////