1 /*
2 
3     Support for embedded (JPEG) Exif-GPS information.
4 
5     Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
20 
21  */
22 
23 #include <ctype.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "defs.h"
29 #include "garmin_tables.h"
30 #include "jeeps/gpsmath.h"
31 #include "strptime.h"
32 
33 #define MYNAME "exif"
34 
35 // #define EXIF_DBG
36 
37 #define UNKNOWN_TIMESTAMP 999999999
38 
39 #define IFD0		0
40 #define IFD1		1
41 #define EXIF_IFD	2		/* dummy index */
42 #define GPS_IFD		3		/* dummy index */
43 #define INTER_IFD	4		/* dummy index */
44 
45 #define EXIF_TYPE_BYTE		1
46 #define EXIF_TYPE_ASCII		2
47 #define EXIF_TYPE_SHORT		3
48 #define EXIF_TYPE_LONG		4
49 #define EXIF_TYPE_RAT		5
50 /* TIFF 6.0 */
51 #define EXIF_TYPE_SBYTE		6
52 #define EXIF_TYPE_UNK		7
53 #define EXIF_TYPE_SSHORT	8
54 #define EXIF_TYPE_SLONG		9
55 #define EXIF_TYPE_SRAT		10
56 #define EXIF_TYPE_FLOAT		11
57 #define EXIF_TYPE_DOUBLE	12
58 #define EXIF_TYPE_IFD		13
59 #define EXIF_TYPE_UNICODE	14
60 #define EXIF_TYPE_COMPLEX	15
61 #define EXIF_TYPE_LONG8		16
62 #define EXIF_TYPE_SLONG8	17
63 #define EXIF_TYPE_IFD8		18
64 
65 #define BYTE_TYPE(a) ( (a==EXIF_TYPE_BYTE) || (a==EXIF_TYPE_ASCII) || (a==EXIF_TYPE_UNK) )
66 #define WORD_TYPE(a) ( (a==EXIF_TYPE_SHORT) || (a==EXIF_TYPE_SSHORT) )
67 #define LONG_TYPE(a) ( (a==EXIF_TYPE_LONG) || (a==EXIF_TYPE_SLONG) || (a==EXIF_TYPE_IFD) )
68 
69 #define IFD0_TAG_EXIF_IFD_OFFS		0x8769
70 #define IFD0_TAG_GPS_IFD_OFFS		0x8825
71 
72 #define IFD1_TAG_STRIP_OFFS		0x0111
73 #define IFD1_TAG_JPEG_OFFS		0x0201
74 #define IFD1_TAG_JPEG_SIZE		0x0202
75 
76 #define EXIF_IFD_TAG_USER_CMT		0x9286
77 #define EXIF_IFD_TAG_INTER_IFD_OFFS	0xA005
78 
79 #define GPS_IFD_TAG_VERSION		0x0000
80 #define GPS_IFD_TAG_LATREF		0x0001
81 #define GPS_IFD_TAG_LAT			0x0002
82 #define GPS_IFD_TAG_LONREF		0x0003
83 #define GPS_IFD_TAG_LON			0x0004
84 #define GPS_IFD_TAG_ALTREF		0x0005
85 #define GPS_IFD_TAG_ALT			0x0006
86 #define GPS_IFD_TAG_TIMESTAMP		0x0007
87 #define GPS_IFD_TAG_SAT			0x0008
88 #define GPS_IFD_TAG_MODE		0x000A
89 #define GPS_IFD_TAG_DOP			0x000B
90 #define GPS_IFD_TAG_SPEEDREF		0x000C
91 #define GPS_IFD_TAG_SPEED		0x000D
92 #define GPS_IFD_TAG_DATUM		0x0012
93 #define GPS_IFD_TAG_DATESTAMP		0x001D
94 
95 typedef struct exif_tag_s {
96   queue Q;
97   gbuint16 id;
98   gbuint16 type;
99   gbuint32 count;
100   gbuint32 value;
101   gbuint32 origin;
102   gbuint32 size;
103 #ifdef EXIF_DBG
104   gbuint32 offs;
105 #endif
106   unsigned char data_is_dynamic:1;
107   void* data;
108 } exif_tag_t;
109 
110 typedef struct exif_ifd_s {
111   queue Q;
112   gbuint32 next_ifd;
113   gbuint16 nr;
114   gbuint16 count;
115   queue tags;
116 } exif_ifd_t, *exif_ifd_p;
117 
118 typedef struct exif_app_s {
119   queue Q;
120   gbuint16 marker;
121   gbsize_t len;
122   gbfile* fcache;
123   gbfile* fexif;
124   queue ifds;
125 } exif_app_t;
126 
127 static gbfile* fin, *fout;
128 static queue exif_apps;
129 static exif_app_t* exif_app;
130 const waypoint* exif_wpt_ref;
131 time_t exif_time_ref;
132 static char exif_success;
133 static char* exif_fout_name;
134 
135 static char* opt_filename, *opt_overwrite, *opt_frame, *opt_name;
136 
137 arglist_t exif_args[] = {
138   { "filename", &opt_filename, "Set waypoint name to source filename", "Y", ARGTYPE_BOOL, ARG_NOMINMAX },
139   { "frame", &opt_frame, "Time-frame (in seconds)", "10", ARGTYPE_INT, "0", NULL },
140   { "name", &opt_name, "Locate waypoint for tagging by this name", NULL, ARGTYPE_STRING, ARG_NOMINMAX },
141   { "overwrite", &opt_overwrite, "!OVERWRITE! the original file. Default=N", "N", ARGTYPE_BOOL, ARG_NOMINMAX },
142   ARG_TERMINATOR
143 };
144 
145 #ifdef EXIF_DBG
146 static void
print_buff(const char * buf,int sz,const char * cmt)147 print_buff(const char* buf, int sz, const char* cmt)
148 {
149   int i;
150 
151   printf("%s: ", cmt);
152   for (i = 0; i < sz; i++) {
153     printf("%02x ", buf[i] & 0xFF);
154   }
155   for (i = 0; i < sz; i++) {
156     char c = buf[i];
157     if (isspace(c)) {
158       c = ' ';
159     } else if (! isprint(c)) {
160       c = '.';
161     }
162     printf("%c", c);
163   }
164 }
165 #endif
166 
167 static gbuint16
exif_type_size(const gbuint16 type)168 exif_type_size(const gbuint16 type)
169 {
170   gbuint16 size;
171 
172   switch (type) {
173   case EXIF_TYPE_BYTE:
174   case EXIF_TYPE_ASCII:
175   case EXIF_TYPE_UNK:
176     size = 1;
177     break;
178 
179   case EXIF_TYPE_SHORT:
180   case EXIF_TYPE_SSHORT:
181   case EXIF_TYPE_UNICODE:
182     size = 2;
183     break;
184   case EXIF_TYPE_IFD:
185   case EXIF_TYPE_LONG:
186   case EXIF_TYPE_SLONG:
187   case EXIF_TYPE_FLOAT:
188     size = 4;
189     break;
190 
191   case EXIF_TYPE_RAT:
192   case EXIF_TYPE_SRAT:
193   case EXIF_TYPE_DOUBLE:
194   case EXIF_TYPE_LONG8:
195   case EXIF_TYPE_SLONG8:
196   case EXIF_TYPE_IFD8:
197     size = 8;
198     break;
199 
200   default:
201     fatal(MYNAME ": Unknown data type %d! Please report.\n", type);
202   }
203   return size;
204 }
205 
206 static char*
exif_time_str(const time_t time)207 exif_time_str(const time_t time)
208 {
209   struct tm tm;
210   char* res;
211 
212   tm = *localtime(&time);
213   tm.tm_year += 1900;
214   tm.tm_mon += 1;
215   xasprintf(&res, "%04d/%02d/%02d, %02d:%02d:%02d",
216             tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
217 
218   return res;
219 }
220 
221 static char*
exif_read_str(exif_tag_t * tag)222 exif_read_str(exif_tag_t* tag)
223 {
224   // Panasonic DMC-TZ10 stores datum with trailing spaces.
225   char* buf = xstrndup((char*)tag->data, tag->size);
226   rtrim(buf);
227   return buf;
228 }
229 
230 static double
exif_read_double(const exif_tag_t * tag,const int index)231 exif_read_double(const exif_tag_t* tag, const int index)
232 {
233   unsigned int num, den;
234   gbint32* data = (gbint32*)tag->data;
235 
236   num = data[index * 2];
237   den = data[(index * 2) + 1];
238   if (den == 0) {
239     den = 1;
240   }
241 
242   return (double)num / (double)den;
243 }
244 
245 static double
exif_read_coord(const exif_tag_t * tag)246 exif_read_coord(const exif_tag_t* tag)
247 {
248   double res, min, sec;
249 
250   res = exif_read_double(tag, 0);
251   if (tag->count == 1) {
252     return res;
253   }
254 
255   min = exif_read_double(tag, 1);
256   res += (min / 60);
257   if (tag->count == 2) {
258     return res;
259   }
260 
261   sec = exif_read_double(tag, 2);
262   res += (sec / 3600);
263 
264   return res;
265 }
266 
267 static time_t
exif_read_timestamp(const exif_tag_t * tag)268 exif_read_timestamp(const exif_tag_t* tag)
269 {
270   double hour, min, sec;
271 
272   hour = exif_read_double(tag, 0);
273   min = exif_read_double(tag, 1);
274   sec = exif_read_double(tag, 2);
275 
276   return ((int)hour * SECONDS_PER_HOUR) + ((int)min * 60) + (int)sec;
277 }
278 
279 static time_t
exif_read_datestamp(const exif_tag_t * tag)280 exif_read_datestamp(const exif_tag_t* tag)
281 {
282   struct tm tm;
283   char* str;
284 
285   memset(&tm, 0, sizeof(tm));
286   str = xstrndup((char*)tag->data, tag->size);
287   sscanf(str, "%d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
288   xfree(str);
289 
290   tm.tm_year -= 1900;
291   tm.tm_mon -= 1;
292 
293   return mkgmtime(&tm);
294 }
295 
296 static void
exif_release_tag(exif_tag_t * tag)297 exif_release_tag(exif_tag_t* tag)
298 {
299   dequeue(&tag->Q);
300   if (tag->data_is_dynamic) {
301     xfree(tag->data);
302   }
303   xfree(tag);
304 }
305 
306 static void
exif_release_ifd(exif_ifd_t * ifd)307 exif_release_ifd(exif_ifd_t* ifd)
308 {
309   if (ifd != NULL) {
310     queue* elem, *tmp;
311 
312     QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
313       exif_release_tag((exif_tag_t*)elem);
314     }
315     xfree(ifd);
316   }
317 }
318 
319 static void
exif_release_apps(void)320 exif_release_apps(void)
321 {
322   queue* e0, *t0;
323 
324   QUEUE_FOR_EACH(&exif_apps, e0, t0) {
325     queue* e1, *t1;
326     exif_app_t* app = (exif_app_t*)dequeue(e0);
327 
328     if (app->fcache) {
329       gbfclose(app->fcache);
330     }
331     if (app->fexif) {
332       gbfclose(app->fexif);
333     }
334     QUEUE_FOR_EACH(&app->ifds, e1, t1) {
335       exif_ifd_t* ifd = (exif_ifd_t*)dequeue(e1);
336       exif_release_ifd(ifd);
337     }
338     xfree(app);
339   }
340 }
341 
342 static gbuint32
exif_ifd_size(exif_ifd_t * ifd)343 exif_ifd_size(exif_ifd_t* ifd)
344 {
345   queue* elem, *tmp;
346   gbuint32 res = 6; 	/* nr of tags + next_ifd */
347 
348   res += (ifd->count * 12);
349   QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
350     exif_tag_t* tag = (exif_tag_t*)elem;
351     if (tag->size > 4) {
352       gbuint32 size = tag->size;
353       if (size & 1) {
354         size++;
355       }
356       res += size;
357     }
358   }
359 
360   return res;
361 }
362 
363 static exif_app_t*
exif_load_apps(void)364 exif_load_apps(void)
365 {
366   exif_app_t* exif_app = NULL;
367 
368   while (! gbfeof(fin)) {
369     exif_app_t* app = (exif_app_t*) xcalloc(sizeof(*app), 1);
370 
371     ENQUEUE_TAIL(&exif_apps, &app->Q);
372     QUEUE_INIT(&app->ifds);
373     app->fcache = gbfopen(NULL, "wb", MYNAME);
374 
375     app->marker = gbfgetuint16(fin);
376     app->len = gbfgetuint16(fin);
377 #ifdef EXIF_DBG
378     printf(MYNAME ": api = %02X, len = %d, offs = %04X\n", app->marker & 0xFF, app->len, gbftell(fin));
379 #endif
380     if (exif_app || (app->marker == 0xFFDA)) /* compressed data */ {
381       gbfcopyfrom(app->fcache, fin, 0x7FFFFFFF);
382 #ifdef EXIF_DBG
383       printf(MYNAME ": compressed data size = %d\n", gbftell(app->fcache));
384 #endif
385     } else {
386       gbfcopyfrom(app->fcache, fin, app->len - 2);
387       if (app->marker == 0xFFE1) {
388         exif_app = app;
389       }
390     }
391   }
392 
393   return exif_app;
394 }
395 
396 static exif_ifd_t*
exif_read_ifd(exif_app_t * app,const gbuint16 ifd_nr,gbsize_t offs,gbuint32 * exif_ifd_ofs,gbuint32 * gps_ifd_ofs,gbuint32 * inter_ifd_ofs)397 exif_read_ifd(exif_app_t* app, const gbuint16 ifd_nr, gbsize_t offs,
398               gbuint32* exif_ifd_ofs, gbuint32* gps_ifd_ofs, gbuint32* inter_ifd_ofs)
399 {
400   queue* elem, *tmp;
401   gbuint16 i;
402   exif_ifd_t* ifd;
403   gbfile* fin = app->fexif;
404 
405   ifd = (exif_ifd_t*) xcalloc(sizeof(*ifd), 1);
406   QUEUE_INIT(&ifd->tags);
407   ENQUEUE_TAIL(&app->ifds, &ifd->Q);
408   ifd->nr = ifd_nr;
409 
410   gbfseek(fin, offs, SEEK_SET);
411   ifd->count = gbfgetuint16(fin);
412 
413 #ifdef EXIF_DBG
414   {
415     char* name;
416     switch (ifd_nr) {
417     case IFD0:
418       name = "IFD0";
419       break;
420     case IFD1:
421       name = "IFD1";
422       break;
423     case GPS_IFD:
424       name = "GPS";
425       break;
426     case EXIF_IFD:
427       name = "EXIF";
428       break;
429     case INTER_IFD:
430       name = "INTER";
431       break;
432     default:
433       name = "private";
434       break;
435     }
436     printf(MYNAME "-offs 0x%04X: Number of items in IFD%d \"%s\" = %d (0x%2x)\n",
437            offs, ifd_nr, name, ifd->count, ifd->count);
438   }
439 #endif
440   if (ifd->count == 0) {
441     return ifd;
442   }
443 
444   for (i = 0; i < ifd->count; i++) {
445     exif_tag_t* tag;
446     offs = gbftell(fin);
447 
448     tag = (exif_tag_t*) xcalloc(sizeof(*tag), 1);
449 
450     ENQUEUE_TAIL(&ifd->tags, &tag->Q);
451 
452     tag->id = gbfgetuint16(fin);
453     tag->type = gbfgetuint16(fin);
454     tag->count = gbfgetuint32(fin);
455     tag->size = exif_type_size(tag->type) * tag->count;
456     tag->data = &tag->value;
457 #ifdef EXIF_DBG
458     tag->offs = offs;
459 #endif
460 
461     if (BYTE_TYPE(tag->type) && (tag->count <= 4)) {
462       gbfread(tag->data, 4, 1, fin);
463     } else {
464       tag->value = gbfgetuint32(fin);
465       tag->origin = tag->value;
466     }
467 
468     if (ifd_nr == IFD0) {
469       if (tag->id == IFD0_TAG_EXIF_IFD_OFFS) {
470         *exif_ifd_ofs = tag->value;
471       } else if (tag->id == IFD0_TAG_GPS_IFD_OFFS) {
472         *gps_ifd_ofs = tag->value;
473       }
474     } else if (ifd_nr == EXIF_IFD) {
475       if (tag->id == EXIF_IFD_TAG_INTER_IFD_OFFS) {
476         *inter_ifd_ofs = tag->value;
477       }
478     }
479   }
480 
481   ifd->next_ifd = gbfgetuint16(fin);
482 
483   QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
484     exif_tag_t* tag = (exif_tag_t*)elem;
485     if ((tag->size > 4) && (tag->value)) {
486       gbuint16 i;
487       char* ptr;
488 
489       tag->data = xmalloc(tag->size);
490       tag->data_is_dynamic = 1;
491 
492       ptr = (char*) tag->data;
493       gbfseek(fin, tag->value, SEEK_SET);
494 
495       if (BYTE_TYPE(tag->type)) {
496         gbfread(ptr, tag->count, 1, fin);
497       } else for (i = 0; i < tag->count; i++) {
498           switch (tag->type) {
499           case EXIF_TYPE_SHORT:
500           case EXIF_TYPE_SSHORT:
501             *(gbint16*)ptr = gbfgetuint16(fin);
502             break;
503           case EXIF_TYPE_IFD:
504           case EXIF_TYPE_LONG:
505           case EXIF_TYPE_SLONG:
506             *(gbint32*)ptr = gbfgetuint32(fin);
507             break;
508           case EXIF_TYPE_RAT:
509           case EXIF_TYPE_SRAT:
510             *(gbint32*)ptr = gbfgetuint32(fin);
511             *(gbint32*)(ptr+4) = gbfgetuint32(fin);
512             break;
513           case EXIF_TYPE_FLOAT:
514             *(float*)ptr = gbfgetflt(fin);
515             break;
516           case EXIF_TYPE_DOUBLE:
517             *(double*)ptr = gbfgetdbl(fin);
518             break;
519           default:
520             gbfread(ptr, 1, 1, fin);
521             break;
522           }
523           ptr += (tag->size / tag->count);
524         }
525     }
526 #ifdef EXIF_DBG
527     printf(MYNAME "-offs 0x%04X: ifd=%d id=0x%04X t=0x%04X c=%4d s=%4d v=0x%08X",
528            tag->offs, ifd->nr, tag->id, tag->type, tag->count, tag->size, tag->value);
529     if (tag->type == EXIF_TYPE_ASCII) {
530       printf(" \"%s\"", exif_read_str(tag));
531     }
532     printf("\n");
533 #endif
534   }
535 
536   return ifd;
537 }
538 
539 static void
exif_read_app(exif_app_t * app)540 exif_read_app(exif_app_t* app)
541 {
542   gbsize_t offs;
543   gbuint32 exif_ifd_ofs, gps_ifd_ofs, inter_ifd_ofs;
544   exif_ifd_t* ifd;
545   gbfile* fin = app->fexif;
546 
547 #ifdef EXIF_DBG
548   printf(MYNAME ": read_app...\n");
549   print_buff((const char*)fin->handle.mem, 16, MYNAME);
550   printf("\n");
551 #endif
552   exif_ifd_ofs = gps_ifd_ofs = inter_ifd_ofs = 0;
553 
554   gbfseek(fin, 4, SEEK_SET);
555   offs = gbfgetuint32(fin);
556 
557   ifd = exif_read_ifd(app, IFD0, offs, &exif_ifd_ofs, &gps_ifd_ofs, &inter_ifd_ofs);
558   if (ifd == NULL) {
559     return;
560   }
561 
562   if (ifd->next_ifd) {
563     ifd = exif_read_ifd(app, IFD1, ifd->next_ifd, &exif_ifd_ofs, &gps_ifd_ofs, &inter_ifd_ofs);
564   }
565   if (exif_ifd_ofs) {
566     ifd = exif_read_ifd(app, EXIF_IFD, exif_ifd_ofs, NULL, NULL, &inter_ifd_ofs);
567   }
568   if (gps_ifd_ofs) {
569     ifd = exif_read_ifd(app, 3, gps_ifd_ofs, NULL, NULL, NULL);
570   }
571   if (inter_ifd_ofs) {
572     ifd = exif_read_ifd(app, 4, inter_ifd_ofs, NULL, NULL, NULL);
573   }
574 }
575 
576 static void
exif_examine_app(exif_app_t * app)577 exif_examine_app(exif_app_t* app)
578 {
579   gbuint16 endianess;
580   gbuint32 ident;
581   gbfile* ftmp = exif_app->fcache;
582   int i;
583 
584   gbfrewind(ftmp);
585   ident = gbfgetuint32(ftmp);
586   is_fatal(ident != 0x66697845, MYNAME ": Invalid EXIF header magic.");
587   is_fatal(gbfgetint16(ftmp) != 0, MYNAME ": Error in EXIF header.");
588   endianess = gbfgetint16(ftmp);
589 
590 #ifdef EXIF_DBG
591   printf(MYNAME ": endianess = 0x%04X\n", endianess);
592 #endif
593   if (endianess == 0x4949) {
594     ftmp->big_endian = 0;
595   } else if (endianess == 0x4D4D) {
596     ftmp->big_endian = 1;
597   } else {
598     fatal(MYNAME ": Invalid endianess identifier 0x%04X!\n", endianess);
599   }
600 
601   gbfseek(ftmp, 6, SEEK_SET);
602   app->fexif = gbfopen(NULL, "wb", MYNAME);
603   app->fexif->big_endian = ftmp->big_endian;
604   i = gbfcopyfrom(app->fexif, ftmp, 0x7FFFFFFF);
605 
606   exif_read_app(exif_app);
607 }
608 
609 static exif_ifd_t*
exif_find_ifd(exif_app_t * app,const gbuint16 ifd_nr)610 exif_find_ifd(exif_app_t* app, const gbuint16 ifd_nr)
611 {
612   queue* e0, *t0;
613 
614   QUEUE_FOR_EACH(&app->ifds, e0, t0) {
615     exif_ifd_t* ifd = (exif_ifd_t*)e0;
616 
617     if (ifd->nr == ifd_nr) {
618       return ifd;
619     }
620   }
621   return NULL;
622 }
623 
624 static exif_tag_t*
exif_find_tag(exif_app_t * app,const gbuint16 ifd_nr,const gbuint16 tag_id)625 exif_find_tag(exif_app_t* app, const gbuint16 ifd_nr, const gbuint16 tag_id)
626 {
627   exif_ifd_t* ifd = exif_find_ifd(app, ifd_nr);
628   if (ifd != NULL) {
629     queue* elem, *tmp;
630     QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
631       exif_tag_t* tag = (exif_tag_t*)elem;
632       if (tag->id == tag_id) {
633         return tag;
634       }
635     }
636   }
637   return NULL;
638 }
639 
640 static time_t
exif_get_exif_time(exif_app_t * app)641 exif_get_exif_time(exif_app_t* app)
642 {
643   exif_tag_t* tag;
644   time_t res = 0;
645 
646   tag = exif_find_tag(app, EXIF_IFD, 0x9003);			/* DateTimeOriginal from EXIF */
647   if (! tag) {
648     tag = exif_find_tag(app, IFD0, 0x0132);  /* DateTime from IFD0 */
649   }
650   if (! tag) {
651     tag = exif_find_tag(app, EXIF_IFD, 0x9004);  /* DateTimeDigitized from EXIF */
652   }
653   if (tag) {
654     struct tm tm;
655     char* c, *str;
656 
657     memset(&tm, 0, sizeof(tm));
658     str = exif_read_str(tag);
659     c = strptime(str, "%Y:%m:%d %H:%M:%S", &tm);
660     if (c && (*c == '\0')) {
661       res = mklocaltime(&tm);
662     }
663 
664     xfree(str);
665   }
666   return res;
667 }
668 
669 static waypoint*
exif_waypt_from_exif_app(exif_app_t * app)670 exif_waypt_from_exif_app(exif_app_t* app)
671 {
672   waypoint* wpt;
673   queue* elem, *tmp;
674   exif_ifd_t* ifd;
675   exif_tag_t* tag;
676   char lat_ref = '\0';
677   char lon_ref = '\0';
678   char alt_ref = 0;
679   char speed_ref = '\0';
680   char* datum = NULL;
681   char mode = '\0';
682   double gpsdop = unknown_alt;
683   double alt = unknown_alt;
684   time_t timestamp = UNKNOWN_TIMESTAMP;
685   time_t datestamp = UNKNOWN_TIMESTAMP;
686 
687   ifd = exif_find_ifd(app, GPS_IFD);
688   if (ifd == NULL) {
689     return NULL;
690   }
691 
692   wpt = waypt_new();
693 
694   wpt->latitude = unknown_alt;
695   wpt->longitude = unknown_alt;
696 
697   QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
698     tag = (exif_tag_t*)elem;
699 
700     switch (tag->id) {
701     case GPS_IFD_TAG_VERSION:
702       break;
703     case GPS_IFD_TAG_LATREF:
704       lat_ref = *(char*)tag->data;
705       break;
706     case GPS_IFD_TAG_LAT:
707       wpt->latitude = exif_read_coord(tag);
708       break;
709     case GPS_IFD_TAG_LONREF:
710       lon_ref = *(char*)tag->data;
711       break;
712     case GPS_IFD_TAG_LON:
713       wpt->longitude = exif_read_coord(tag);
714       break;
715     case GPS_IFD_TAG_ALTREF:
716       alt_ref = *(char*)tag->data;
717       break;
718     case GPS_IFD_TAG_ALT:
719       alt = exif_read_double(tag, 0);
720       break;
721     case GPS_IFD_TAG_TIMESTAMP:
722       timestamp = exif_read_timestamp(tag);
723       break;
724     case GPS_IFD_TAG_SAT:
725       wpt->sat = atoi((char*)tag->data);
726       break;
727     case GPS_IFD_TAG_MODE:
728       mode = *(char*)tag->data;
729       break;
730     case GPS_IFD_TAG_DOP:
731       gpsdop = exif_read_double(tag, 0);
732       break;
733     case GPS_IFD_TAG_SPEEDREF:
734       speed_ref = *(char*)tag->data;
735       break;
736     case GPS_IFD_TAG_SPEED:
737       WAYPT_SET(wpt, speed, exif_read_double(tag, 0));
738       break;
739     case GPS_IFD_TAG_DATUM:
740       datum = exif_read_str(tag);
741       break;
742     case GPS_IFD_TAG_DATESTAMP:
743       datestamp = exif_read_datestamp(tag);
744       break;
745     }
746   }
747 
748   if ((wpt->latitude == unknown_alt) || (wpt->longitude == unknown_alt)) {
749     fatal(MYNAME ": Missing GPSLatitude and/or GPSLongitude!\n");
750   }
751 
752   if (lat_ref == 'S') {
753     wpt->latitude *= -1;
754   } else if (lat_ref != 'N') {
755     warning(MYNAME ": GPSLatitudeRef not set! Using N(orth).\n");
756   }
757 
758   if (lon_ref == 'W') {
759     wpt->longitude *= -1;
760   } else if (lon_ref != 'E') {
761     warning(MYNAME ": GPSLongitudeRef not set! Using E(east).\n");
762   }
763 
764 #ifdef EXIF_DBG
765   printf(MYNAME "-GPSLatitude =  %12.7f\n", wpt->latitude);
766   printf(MYNAME "-GPSLongitude = %12.7f\n", wpt->longitude);
767 #endif
768   if (datum) {
769     int idatum = gt_lookup_datum_index(datum, MYNAME);
770     if (idatum < 0) {
771       fatal(MYNAME ": Unknown GPSMapDatum \"%s\"!\n", datum);
772     }
773     if (idatum != DATUM_WGS84) {
774       double alt;
775       GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0,
776                                       &wpt->latitude, &wpt->longitude, &alt, idatum);
777     }
778     xfree(datum);
779   }
780 
781   if (alt != unknown_alt) {
782     double sign;
783     switch (alt_ref != 0) {
784     case 0:
785       sign = 1.0;
786       break;
787 
788     case 1:
789       sign = -1.0;
790       break;
791 
792     default:
793       warning(MYNAME ": Invalid GPSAltitudeRef (%d)! Using 0 (= Sea level).\n", alt_ref);
794       sign = 1.0;
795     }
796     wpt->altitude = sign * alt;
797 #ifdef EXIF_DBG
798     printf(MYNAME "-GPSAltitude =  %12.7f m\n", wpt->altitude);
799 #endif
800   }
801 
802   if WAYPT_HAS(wpt, speed) {
803     switch (speed_ref) {
804     case 'K':
805       wpt->speed = KPH_TO_MPS(wpt->speed);
806       break;
807     case 'M':
808       wpt->speed = MPH_TO_MPS(wpt->speed);
809       break;
810     case 'N':
811       wpt->speed = KNOTS_TO_MPS(wpt->speed);
812       break;
813     default:
814       wpt->speed = 0;
815       WAYPT_UNSET(wpt, speed);
816       warning(MYNAME ": Unknown GPSSpeedRef unit %c (0x%02x)!\n", speed_ref, speed_ref);
817     }
818 #ifdef EXIF_DBG
819     if WAYPT_HAS(wpt, speed) {
820       printf(MYNAME "-GPSSpeed = %12.2f m/s\n", wpt->speed);
821     }
822 #endif
823   }
824 
825   if (mode == '2') {
826     wpt->fix = fix_2d;
827     if (gpsdop != unknown_alt) {
828       wpt->hdop = gpsdop;
829     }
830   } else if (mode == '3') {
831     wpt->fix = fix_3d;
832     if (gpsdop != unknown_alt) {
833       wpt->pdop = gpsdop;
834     }
835   }
836 
837   if (timestamp != UNKNOWN_TIMESTAMP) {
838     if (datestamp != UNKNOWN_TIMESTAMP) {
839       timestamp += datestamp;
840     }
841   } else {
842     timestamp = datestamp;
843   }
844   if (timestamp != UNKNOWN_TIMESTAMP) {
845 #ifdef EXIF_DBG
846     char* str = exif_time_str(timestamp);
847     printf(MYNAME "-GPSTimeStamp =   %s\n", str);
848     xfree(str);
849 #endif
850     wpt->creation_time = timestamp;
851   } else {
852     wpt->creation_time = exif_get_exif_time(app);
853   }
854 
855   tag = exif_find_tag(app, EXIF_IFD, EXIF_IFD_TAG_USER_CMT); /* UserComment */
856   if (tag && (tag->size > 8)) {
857     char* str = NULL;
858     if (memcmp(tag->data, "ASCII\0\0\0", 8) == 0) {
859       str = xstrndup((char*)tag->data + 8, tag->size - 8);
860     } else if (memcmp(tag->data, "UNICODE\0", 8) == 0) {
861       int i, len = (tag->size - 8) / 2;
862       gbint16* s = (gbint16*)((char*)tag->data + 8);
863       for (i = 0; i < len; i++) {
864         s[i] = be_read16(&s[i]);  /* always BE ? */
865       }
866       str = cet_str_uni_to_any(s, len, global_opts.charset);
867     }
868     if (str != NULL) {
869       wpt->notes = str;
870     }
871   }
872 
873   if (opt_filename) {
874     char* c, *cx;
875     char* str = xstrdup(fin->name);
876 
877     cx = str;
878     if ((c = strrchr(cx, ':'))) {
879       cx = c + 1;
880     }
881     if ((c = strrchr(cx, '\\'))) {
882       cx = c + 1;
883     }
884     if ((c = strrchr(cx, '/'))) {
885       cx = c + 1;
886     }
887     if (((c = strchr(cx, '.'))) && (c != cx)) {
888       *c = '\0';
889     }
890 
891     if (wpt->shortname) {
892       xfree(wpt->shortname);
893     }
894     wpt->shortname = xstrdup(cx);
895     xfree(str);
896   }
897 
898   return wpt;
899 }
900 
901 static void
exif_dec2frac(double val,gbint32 * num,gbint32 * den)902 exif_dec2frac(double val, gbint32* num, gbint32* den)
903 {
904   char sval[16], snum[16];
905   char dot = 0;
906   int den1 = 1;
907   int num1, num2, den2, rem;
908   char* cx;
909   double vx;
910 
911   if (val < 0.000000001) {
912     val = 0.0;
913   } else if (val > 999999999.0) {
914     fatal(MYNAME ": Value (%f) to big for a rational representation!\n", val);
915   }
916 
917   num1 = 0;
918   vx = fabs(val);
919   while (vx > 1) {
920     num1++;
921     vx = vx / 10;
922   }
923 
924   snprintf(sval, sizeof(sval), "%*.*f", 9, 9 - num1, fabs(val));
925   snum[0] = '\0';
926 
927   cx = sval;
928   while (*cx) {
929     if (dot) {
930       den1 *= 10;
931     }
932     if (*cx == '.') {
933       dot = 1;
934     } else {
935       strncat(snum, cx, 1);
936     }
937     cx++;
938   }
939 
940   num1 = atoi(snum);
941   if (den1 == 1) {
942     *num = num1;
943     *den = den1;
944   }
945 
946   num2 = num1;
947   den2 = den1;
948   rem  = 1;
949 
950   /* Euclid's Algorithm to find the gcd */
951   while (num2 % den2) {
952     rem = num2 % den2;
953     num2 = den2;
954     den2 = rem;
955   }
956   if (den2 != den1) {
957     rem = den2;
958   }
959 
960   *num = num1 / rem;
961   *den = den1 / rem;
962 }
963 
964 static exif_tag_t*
exif_put_value(const int ifd_nr,const gbuint16 tag_id,const gbuint16 type,const gbuint32 count,const int index,const void * data)965 exif_put_value(const int ifd_nr, const gbuint16 tag_id, const gbuint16 type, const gbuint32 count, const int index, const void* data)
966 {
967   exif_tag_t* tag = NULL;
968   exif_ifd_t* ifd;
969   gbuint16 item_size, size;
970 
971   ifd = exif_find_ifd(exif_app, ifd_nr);
972   if (ifd == NULL) {
973     ifd = (exif_ifd_t*) xcalloc(sizeof(*ifd), 1);
974     ifd->nr = ifd_nr;
975     QUEUE_INIT(&ifd->tags);
976     ENQUEUE_TAIL(&exif_app->ifds, &ifd->Q);
977   } else {
978     tag = exif_find_tag(exif_app, ifd_nr, tag_id);
979   }
980 
981   item_size = exif_type_size(type);
982 
983   if ((data == NULL) || (count < 1) || (index < 0)) {
984     size = 0;
985   } else {
986     size = (index + count) * item_size;
987   }
988 
989   if (tag == NULL) {
990     if (size == 0) {
991       return NULL;
992     }
993 
994     tag = (exif_tag_t*) xcalloc(sizeof(*tag), 1);
995 
996     tag->id = tag_id;
997     tag->type = type;
998     tag->count = index + count;
999     tag->size = size;
1000     tag->data = xcalloc((size < 4) ? 4 : size, 1);
1001     tag->data_is_dynamic = 1;
1002     ifd->count++;
1003 
1004     ENQUEUE_TAIL(&ifd->tags, &tag->Q);
1005   } else {
1006     if (size == 0) {	/* remove this element */
1007       ifd->count--;
1008       exif_release_tag(tag);
1009       return NULL;
1010     }
1011     if (tag->count < (index + count)) {
1012       if (! tag->data_is_dynamic) {
1013         void* tmp = xmalloc(tag->size < 4 ? 4 : tag->size);
1014         memcpy(tmp, tag->data, tag->size);
1015         tag->data = tmp;
1016         tag->data_is_dynamic = 1;
1017       }
1018       tag->size = size;
1019       tag->count = index + count;
1020       tag->data = xrealloc(tag->data, size < 4 ? 4 : size);
1021     }
1022   }
1023 
1024   switch (type) {
1025   case EXIF_TYPE_RAT:
1026   case EXIF_TYPE_SRAT: {
1027     double val = *(double*)data;
1028     gbuint32* dest = (gbuint32*) tag->data;
1029 
1030     if ((int)val == val) {
1031       dest[index * 2] = (int)val;
1032       dest[(index * 2) + 1] = 1;
1033     } else {
1034       gbint32 Nom, Den;
1035       exif_dec2frac(val, &Nom, &Den);
1036       if ((type == EXIF_TYPE_SRAT) && (val < 0.0)) {
1037         Nom *= -1;
1038       }
1039       dest[index * 2] = Nom;
1040       dest[(index * 2) + 1] = Den;
1041     }
1042   }
1043   break;
1044   default: {
1045     char* dest = (char*) tag->data;
1046     memcpy(&dest[index * item_size], data, count * item_size);
1047   }
1048   }
1049   return tag;
1050 }
1051 
1052 
1053 static void
exif_put_double(const int ifd_nr,const int tag_id,const int index,const double val)1054 exif_put_double(const int ifd_nr, const int tag_id, const int index, const double val)
1055 {
1056   double d = fabs(val);
1057   exif_put_value(ifd_nr, tag_id, EXIF_TYPE_RAT, 1, index, &d);
1058 }
1059 
1060 
1061 static void
exif_put_str(const int ifd_nr,const int tag_id,const char * val)1062 exif_put_str(const int ifd_nr, const int tag_id, const char* val)
1063 {
1064   int len = (val) ? strlen(val) + 1 : 0;
1065   exif_put_value(ifd_nr, tag_id, EXIF_TYPE_ASCII, len, 0, val);
1066 }
1067 
1068 static void
exif_put_coord(const int ifd_nr,const int tag_id,const double val)1069 exif_put_coord(const int ifd_nr, const int tag_id, const double val)
1070 {
1071   double  vmin, vsec;
1072   int     vint;
1073 
1074   vint = abs((int) val);
1075   vmin = 60.0 * (fabs(val) - vint);
1076   vsec = 60.0 * (vmin - floor(vmin));
1077   vmin = floor(vmin);
1078 
1079   exif_put_double(ifd_nr, tag_id, 0, (double)vint);
1080   exif_put_double(ifd_nr, tag_id, 1, (double)vmin);
1081   exif_put_double(ifd_nr, tag_id, 2, (double)vsec);
1082 }
1083 
1084 static void
exif_put_long(const int ifd_nr,const int tag_id,const int index,const gbint32 val)1085 exif_put_long(const int ifd_nr, const int tag_id, const int index, const gbint32 val)
1086 {
1087   exif_put_value(ifd_nr, tag_id, EXIF_TYPE_LONG, 1, index, &val);
1088 }
1089 
1090 static void
exif_remove_tag(const int ifd_nr,const int tag_id)1091 exif_remove_tag(const int ifd_nr, const int tag_id)
1092 {
1093   exif_put_value(ifd_nr, tag_id, EXIF_TYPE_BYTE, 0, 0, NULL);
1094 }
1095 
1096 static void
exif_find_wpt_by_time(const waypoint * wpt)1097 exif_find_wpt_by_time(const waypoint* wpt)
1098 {
1099   if (wpt->creation_time <= 0) {
1100     return;
1101   }
1102 
1103   if (exif_wpt_ref == NULL) {
1104     exif_wpt_ref = wpt;
1105   } else if (abs(exif_time_ref - wpt->creation_time) < abs(exif_time_ref - exif_wpt_ref->creation_time)) {
1106     exif_wpt_ref = wpt;
1107   }
1108 }
1109 
1110 static void
exif_find_wpt_by_name(const waypoint * wpt)1111 exif_find_wpt_by_name(const waypoint* wpt)
1112 {
1113   if (exif_wpt_ref != NULL) {
1114     return;
1115   } else if ((wpt->shortname != NULL) && (case_ignore_strcmp(wpt->shortname, opt_name) == 0)) {
1116     exif_wpt_ref = wpt;
1117   }
1118 }
1119 
1120 
1121 static int
exif_sort_tags_cb(const queue * A,const queue * B)1122 exif_sort_tags_cb(const queue* A, const queue* B)
1123 {
1124   exif_tag_t* ta = (exif_tag_t*)A;
1125   exif_tag_t* tb = (exif_tag_t*)B;
1126 
1127   return ta->id - tb->id;
1128 }
1129 
1130 static int
exif_sort_ifds_cb(const queue * A,const queue * B)1131 exif_sort_ifds_cb(const queue* A, const queue* B)
1132 {
1133   exif_ifd_t* ia = (exif_ifd_t*)A;
1134   exif_ifd_t* ib = (exif_ifd_t*)B;
1135 
1136   return ia->nr - ib->nr;
1137 }
1138 
1139 static void
exif_write_value(exif_tag_t * tag,gbfile * fout)1140 exif_write_value(exif_tag_t* tag, gbfile* fout)
1141 {
1142   if (tag->size > 4) {
1143     gbfputuint32(tag->value, fout);  /* offset to data */
1144   } else {
1145     char* data = (char*) tag->data;
1146 
1147     if BYTE_TYPE(tag->type) {
1148       gbfwrite(data, 4, 1, fout);
1149     } else if WORD_TYPE(tag->type) {
1150       gbfputuint16(*(gbuint16*)data, fout);
1151       gbfputuint16(*(gbuint16*)(data+2), fout);
1152     } else if LONG_TYPE(tag->type) {
1153       gbfputuint32(*(gbuint32*)data, fout);
1154     } else if (tag->type == EXIF_TYPE_FLOAT) {
1155       gbfputflt(*(float*)data, fout);
1156     } else {
1157       fatal(MYNAME ": Unknown data type %d!\n", tag->type);
1158     }
1159   }
1160 }
1161 
1162 static void
exif_write_ifd(const exif_ifd_t * ifd,const char next,gbfile * fout)1163 exif_write_ifd(const exif_ifd_t* ifd, const char next, gbfile* fout)
1164 {
1165   gbsize_t offs;
1166   queue* elem, *tmp;
1167 
1168   gbfputuint16(ifd->count, fout);
1169   offs = gbftell(fout) + (ifd->count * 12) + 4;
1170 
1171   QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
1172     exif_tag_t* tag = (exif_tag_t*)elem;
1173 
1174     gbfputuint16(tag->id, fout);
1175     gbfputuint16(tag->type, fout);
1176     gbfputuint32(tag->count, fout);
1177     if (tag->size > 4) {
1178       tag->value = offs;
1179       offs += tag->size;
1180       if (offs & 1) {
1181         offs++;
1182       }
1183       gbfputuint32(tag->value, fout);
1184     } else {
1185       exif_write_value(tag, fout);
1186     }
1187   }
1188 
1189   if (next) {
1190     gbfputuint32(offs, fout);
1191   } else {
1192     gbfputuint32(0, fout);
1193   }
1194 
1195   QUEUE_FOR_EACH(&ifd->tags, elem, tmp) {
1196     exif_tag_t* tag = (exif_tag_t*)elem;
1197 
1198     if (tag->size > 4) {
1199       gbuint16 i;
1200       char* ptr = (char*) tag->data;
1201 
1202       if BYTE_TYPE(tag->type) {
1203         gbfwrite(tag->data, tag->size, 1, fout);
1204       } else for (i = 0; i < tag->count; i++) {
1205           switch (tag->type) {
1206           case EXIF_TYPE_SHORT:
1207           case EXIF_TYPE_SSHORT:
1208             gbfputuint16(*(gbint16*)ptr, fout);
1209             break;
1210           case EXIF_TYPE_LONG:
1211           case EXIF_TYPE_SLONG:
1212           case EXIF_TYPE_IFD:
1213             gbfputuint32(*(gbint32*)ptr, fout);
1214             break;
1215           case EXIF_TYPE_RAT:
1216           case EXIF_TYPE_SRAT:
1217             gbfputuint32(*(gbint32*)ptr, fout);
1218             gbfputuint32(*(gbint32*)(ptr+4), fout);
1219             break;
1220           case EXIF_TYPE_FLOAT:
1221             gbfputflt(*(float*)ptr, fout);
1222             break;
1223           case EXIF_TYPE_DOUBLE:
1224             gbfputdbl(*(double*)ptr, fout);
1225             break;
1226           default:
1227             gbfwrite(ptr, exif_type_size(tag->type), 1, fin);
1228             break;
1229           }
1230           ptr += (tag->size / tag->count);
1231         }
1232       if (gbftell(fout) & 1) {
1233         gbfputc(0, fout);
1234       }
1235     }
1236   }
1237 }
1238 
1239 static void
exif_write_apps(void)1240 exif_write_apps(void)
1241 {
1242   queue* e0, *t0;
1243 
1244   gbfputuint16(0xFFD8, fout);
1245 
1246   QUEUE_FOR_EACH(&exif_apps, e0, t0) {
1247     exif_app_t* app = (exif_app_t*)e0;
1248 
1249     gbfputuint16(app->marker, fout);
1250 
1251     if (app == exif_app) {
1252       queue* e1, *t1;
1253       gbuint16 len = 8;
1254       gbfile* ftmp;
1255       exif_tag_t* tag;
1256 
1257       exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, 0);
1258       exif_put_long(GPS_IFD, GPS_IFD_TAG_VERSION, 0, 2);
1259 
1260       sortqueue(&exif_app->ifds, exif_sort_ifds_cb);
1261 
1262       QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1263         exif_ifd_t* ifd = (exif_ifd_t*)e1;
1264 
1265         if (ifd->nr == GPS_IFD) {
1266           exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, len);
1267         } else if (ifd->nr == EXIF_IFD) {
1268           exif_put_long(IFD0, IFD0_TAG_EXIF_IFD_OFFS, 0, len);
1269         } else if (ifd->nr == INTER_IFD) {
1270           exif_put_long(EXIF_IFD, EXIF_IFD_TAG_INTER_IFD_OFFS, 0, len);
1271         }
1272 
1273         len += exif_ifd_size(ifd);
1274       }
1275 
1276       len += 4; /* DWORD(0) after last ifd */
1277 
1278       if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_OFFS))) {
1279         exif_put_long(IFD1, IFD1_TAG_JPEG_OFFS, 0, len);
1280       }
1281 
1282       QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1283         exif_ifd_t* ifd = (exif_ifd_t*)e1;
1284         sortqueue(&ifd->tags, exif_sort_tags_cb);
1285       }
1286 
1287       ftmp = gbfopen_be(NULL, "wb", MYNAME);
1288       ftmp->big_endian = app->fcache->big_endian;
1289 
1290       gbfwrite((ftmp->big_endian) ? "MM" : "II", 2, 1, ftmp);
1291       gbfputuint16(0x2A, ftmp);
1292       gbfputuint32(0x08, ftmp);	/* offset to first IFD */
1293 
1294       QUEUE_FOR_EACH(&app->ifds, e1, t1) {
1295         exif_ifd_t* ifd = (exif_ifd_t*)e1;
1296         exif_ifd_t* ifd_next = (exif_ifd_t*)t1;
1297         char next;
1298 
1299         if ((ifd->nr == IFD0) && (ifd_next->nr == IFD1)) {
1300           next = 1;
1301         } else {
1302           next = 0;
1303         }
1304 
1305         exif_write_ifd(ifd, next, ftmp);
1306         len = gbftell(ftmp);
1307       }
1308 
1309       gbfputuint32(0, ftmp); /* DWORD(0) after last ifd */
1310 
1311       if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_OFFS))) {
1312         gbsize_t offs = tag->origin;
1313         if ((tag = exif_find_tag(app, IFD1, IFD1_TAG_JPEG_SIZE))) {
1314           gbfseek(app->fexif, offs, SEEK_SET);
1315           gbfcopyfrom(ftmp, app->fexif, tag->value);
1316         }
1317       }
1318 
1319       len = gbftell(ftmp);
1320       gbfrewind(ftmp);
1321       gbfputuint16(len + 8, fout);
1322       gbfwrite("Exif\0\0", 6, 1, fout);
1323       gbfcopyfrom(fout, ftmp, len);
1324 
1325       gbfclose(ftmp);
1326     } else {
1327       gbfputuint16(app->len, fout);
1328       gbfrewind(app->fcache);
1329       gbfcopyfrom(fout, app->fcache, 0x7FFFFFFF);
1330     }
1331   }
1332 }
1333 
1334 /*******************************************************************************
1335 * %%%        global callbacks called by gpsbabel main process              %%% *
1336 *******************************************************************************/
1337 
1338 static void
exif_rd_init(const char * fname)1339 exif_rd_init(const char* fname)
1340 {
1341   fin = gbfopen_be(fname, "rb", MYNAME);
1342   QUEUE_INIT(&exif_apps);
1343 }
1344 
1345 static void
exif_rd_deinit(void)1346 exif_rd_deinit(void)
1347 {
1348   exif_release_apps();
1349   gbfclose(fin);
1350 }
1351 
1352 static void
exif_read(void)1353 exif_read(void)
1354 {
1355   gbuint16 soi;
1356   waypoint* wpt;
1357 
1358   soi = gbfgetuint16(fin);
1359   is_fatal(soi != 0xFFD8, MYNAME ": Unknown image file.");	/* only jpeg for now */
1360 
1361   exif_app = exif_load_apps();
1362   is_fatal(exif_app == NULL, MYNAME ": No EXIF header in source file \"%s\".", fin->name);
1363 
1364   exif_examine_app(exif_app);
1365   wpt = exif_waypt_from_exif_app(exif_app);
1366   if (wpt) {
1367     waypt_add(wpt);
1368   }
1369 }
1370 
1371 static void
exif_wr_init(const char * fname)1372 exif_wr_init(const char* fname)
1373 {
1374   gbuint16 soi;
1375   char* tmpname;
1376 
1377   exif_success = 0;
1378   exif_fout_name = xstrdup(fname);
1379 
1380   QUEUE_INIT(&exif_apps);
1381 
1382   fin = gbfopen_be(fname, "rb", MYNAME);
1383   is_fatal(fin->is_pipe, MYNAME ": Sorry, this format cannot be used with pipes!");
1384 
1385   soi = gbfgetuint16(fin);
1386   is_fatal(soi != 0xFFD8, MYNAME ": Unknown image file.");
1387   exif_app = exif_load_apps();
1388   is_fatal(exif_app == NULL, MYNAME ": No EXIF header found in source file \"%s\".", fin->name);
1389   exif_examine_app(exif_app);
1390   gbfclose(fin);
1391 
1392   exif_time_ref = exif_get_exif_time(exif_app);
1393   if (exif_time_ref == 0) {
1394     fatal(MYNAME ": No valid timestamp found in picture!\n");
1395   }
1396 
1397   xasprintf(&tmpname, "%s.jpg", fname);
1398   fout = gbfopen_be(tmpname, "wb", MYNAME);
1399   xfree(tmpname);
1400 }
1401 
1402 static void
exif_wr_deinit(void)1403 exif_wr_deinit(void)
1404 {
1405   char* tmpname;
1406 
1407   exif_release_apps();
1408   tmpname = xstrdup(fout->name);
1409   gbfclose(fout);
1410 
1411   if (exif_success) {
1412     if (*opt_overwrite == '1') {
1413       remove(exif_fout_name);
1414       rename(tmpname, exif_fout_name);
1415     }
1416   } else {
1417     remove(tmpname);
1418   }
1419 
1420   xfree(exif_fout_name);
1421   xfree(tmpname);
1422 }
1423 
1424 static void
exif_write(void)1425 exif_write(void)
1426 {
1427   char alt_ref = 0;
1428   time_t frame;
1429 
1430   exif_wpt_ref = NULL;
1431 
1432   if (opt_name) {
1433     waypt_disp_all(exif_find_wpt_by_name);
1434     if (exif_wpt_ref == NULL) {
1435       route_disp_all(NULL, NULL, exif_find_wpt_by_name);
1436     }
1437     if (exif_wpt_ref == NULL) {
1438       track_disp_all(NULL, NULL, exif_find_wpt_by_name);
1439     }
1440     if (exif_wpt_ref == NULL) {
1441       warning(MYNAME ": No matching point with name \"%s\" found.\n", opt_name);
1442     }
1443   } else {
1444     char* str = exif_time_str(exif_time_ref);
1445 
1446     track_disp_all(NULL, NULL, exif_find_wpt_by_time);
1447     route_disp_all(NULL, NULL, exif_find_wpt_by_time);
1448     waypt_disp_all(exif_find_wpt_by_time);
1449 
1450     frame = atoi(opt_frame);
1451 
1452     if (exif_wpt_ref == NULL) {
1453       warning(MYNAME ": No point with a valid timestamp found.\n");
1454     } else if (abs(exif_time_ref - exif_wpt_ref->creation_time) > frame) {
1455       warning(MYNAME ": No matching point found for image date %s!\n", str);
1456       if (exif_wpt_ref != NULL) {
1457         char* str = exif_time_str(exif_wpt_ref->creation_time);
1458         warning(MYNAME ": Best is from %s, %d second(s) away.\n",
1459                 str, abs(exif_time_ref - exif_wpt_ref->creation_time));
1460         xfree(str);
1461       }
1462       exif_wpt_ref = NULL;
1463     }
1464     xfree(str);
1465   }
1466 
1467   if (exif_wpt_ref != NULL) {
1468     const waypoint* wpt = exif_wpt_ref;
1469 
1470     exif_put_long(IFD0, IFD0_TAG_GPS_IFD_OFFS, 0, 0);
1471     exif_put_long(GPS_IFD, GPS_IFD_TAG_VERSION, 0, 2);
1472     exif_put_str(GPS_IFD, GPS_IFD_TAG_DATUM, "WGS-84");
1473 
1474     exif_put_str(GPS_IFD, GPS_IFD_TAG_LATREF, wpt->latitude < 0 ? "S" : "N");
1475     exif_put_coord(GPS_IFD, GPS_IFD_TAG_LAT, fabs(wpt->latitude));
1476     exif_put_str(GPS_IFD, GPS_IFD_TAG_LONREF, wpt->longitude < 0 ? "W" : "E");
1477     exif_put_coord(GPS_IFD, GPS_IFD_TAG_LON, fabs(wpt->longitude));
1478 
1479     if (wpt->altitude == unknown_alt) {
1480       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_ALT);
1481       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_ALTREF);
1482     } else {
1483       exif_put_value(GPS_IFD, GPS_IFD_TAG_ALTREF, EXIF_TYPE_BYTE, 1, 0, &alt_ref);
1484       exif_put_double(GPS_IFD, GPS_IFD_TAG_ALT, 0, wpt->altitude);
1485     }
1486 
1487     if (wpt->creation_time) {
1488       struct tm tm;
1489       char buf[32];
1490 
1491       tm = *gmtime(&wpt->creation_time);
1492       tm.tm_year += 1900;
1493       tm.tm_mon += 1;
1494 
1495       exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 0, tm.tm_hour);
1496       exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 1, tm.tm_min);
1497       exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 2, tm.tm_sec);
1498 
1499       snprintf(buf, sizeof(buf), "%04d:%02d:%02d", tm.tm_year, tm.tm_mon, tm.tm_mday);
1500       exif_put_str(GPS_IFD, GPS_IFD_TAG_DATESTAMP, buf);
1501     } else {
1502       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_TIMESTAMP);
1503       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_DATESTAMP);
1504     }
1505 
1506     if (wpt->sat > 0) {
1507       char buf[16];
1508       snprintf(buf, sizeof(buf), "%d", wpt->sat);
1509       exif_put_str(GPS_IFD, GPS_IFD_TAG_SAT, buf);
1510     } else {
1511       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SAT);
1512     }
1513 
1514     if (wpt->fix == fix_2d) {
1515       exif_put_str(GPS_IFD, GPS_IFD_TAG_MODE, "2");
1516     } else if (wpt->fix == fix_3d) {
1517       exif_put_str(GPS_IFD, GPS_IFD_TAG_MODE, "3");
1518     } else {
1519       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_MODE);
1520     }
1521 
1522     if (wpt->hdop > 0) {
1523       exif_put_double(GPS_IFD, GPS_IFD_TAG_DOP, 0, wpt->hdop);
1524     } else {
1525       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_DOP);
1526     }
1527 
1528     if WAYPT_HAS(wpt, speed) {
1529       exif_put_str(GPS_IFD, GPS_IFD_TAG_SPEEDREF, "K");
1530       exif_put_double(GPS_IFD, GPS_IFD_TAG_SPEED, 0, MPS_TO_KPH(wpt->speed));
1531     } else {
1532       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SPEEDREF);
1533       exif_remove_tag(GPS_IFD, GPS_IFD_TAG_SPEED);
1534     }
1535 
1536     exif_write_apps();	/* Success, write the new file */
1537 
1538     exif_success = 1;
1539   }
1540 
1541 }
1542 
1543 /**************************************************************************/
1544 
1545 ff_vecs_t exif_vecs = {
1546   ff_type_file,
1547   {
1548     (ff_cap)(ff_cap_read | ff_cap_write)	/* waypoints */,
1549     ff_cap_none 			/* tracks */,
1550     ff_cap_none 			/* routes */
1551   },
1552   exif_rd_init,
1553   exif_wr_init,
1554   exif_rd_deinit,
1555   exif_wr_deinit,
1556   exif_read,
1557   exif_write,
1558   NULL,
1559   exif_args,
1560   CET_CHARSET_UTF8, 0
1561 };
1562 
1563 /**************************************************************************/
1564