1 /*
2
3 Support for Destinator POI's, Itineraries and Tracklogs.
4 ( as described at "http://mozoft.com/d3log.html" )
5
6 Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
7
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
22
23 */
24
25 #include "defs.h"
26 #include "cet.h"
27 #include "cet_util.h"
28 #include "garmin_fs.h"
29 #include "strptime.h"
30 #include <ctype.h>
31 #include <time.h>
32
33 #define MYNAME "destinator"
34 #define DST_DYN_POI "Dynamic POI"
35 #define DST_ITINERARY "City->Street"
36
37 static
38 arglist_t destinator_args[] = {
39 ARG_TERMINATOR
40 };
41
42 static gbfile* fin, *fout;
43 static gpsdata_type data_type;
44
45
46 /*******************************************************************************/
47 /* READER */
48 /*-----------------------------------------------------------------------------*/
49
50 static garmin_fs_t*
gmsd_init(waypoint * wpt)51 gmsd_init(waypoint* wpt)
52 {
53 garmin_fs_t* gmsd = GMSD_FIND(wpt);
54 if (gmsd == NULL) {
55 gmsd = garmin_fs_alloc(-1);
56 fs_chain_add(&wpt->fs, (format_specific_data*) gmsd);
57 }
58 return gmsd;
59 }
60
61 static char*
read_wcstr(const int discard)62 read_wcstr(const int discard)
63 {
64 gbint16* buff = NULL, c;
65 int size = 0, pos = 0;
66
67 while (gbfread(&c, sizeof(c), 1, fin) && (c != 0)) {
68 if (size == 0) {
69 size = 16;
70 buff = (gbint16*) xmalloc(size * sizeof(*buff));
71 } else if (pos == size) {
72 size += 16;
73 buff = (gbint16*) xrealloc(buff, size * sizeof(*buff));
74 }
75 buff[pos] = c;
76 pos += 1;
77 }
78
79 if (pos != 0) {
80 char* res;
81 if (discard) {
82 res = NULL;
83 } else {
84 res = cet_str_uni_to_utf8(buff, pos);
85 res = lrtrim(res);
86 if (*res == '\0') {
87 xfree(res);
88 res = NULL;
89 }
90 }
91 xfree(buff);
92 return res;
93 } else {
94 return NULL;
95 }
96 }
97
98 static void
write_wcstr(const char * str)99 write_wcstr(const char* str)
100 {
101 int len;
102 short* unicode;
103
104 unicode = cet_str_utf8_to_uni(str, &len);
105 gbfwrite((void*)unicode, 2, len + 1, fout);
106 xfree(unicode);
107 }
108
109 static int
read_until_wcstr(const char * str)110 read_until_wcstr(const char* str)
111 {
112 char* buff;
113 int len, sz;
114 int eos = 0, res = 0;
115
116 len = strlen(str);
117 sz = (len + 1) * 2;
118 buff = (char*) xcalloc(sz, 1);
119
120 while (! gbfeof(fin)) {
121
122 char c = gbfgetc(fin);
123 memmove(buff, buff + 1, sz - 1);
124 buff[sz - 1] = c;
125
126 if (c == 0) {
127 eos++;
128 if (eos >= 2) { /* two or more zero bytes => end of string */
129 char* test = cet_str_uni_to_utf8((short*)buff, len);
130 if (test) {
131 res = (strcmp(str, test) == 0);
132 xfree(test);
133 if (res) {
134 break;
135 }
136 }
137 }
138 } else {
139 eos = 0;
140 }
141 }
142 xfree(buff);
143 return res;
144 }
145
146 static void
destinator_read_poi(void)147 destinator_read_poi(void)
148 {
149 waypoint* wpt;
150 int count = 0;
151
152 gbfrewind(fin);
153
154 while (!(gbfeof(fin))) {
155 char* str, *hnum;
156 double ll;
157 garmin_fs_t* gmsd;
158
159 if (count == 0) {
160 str = read_wcstr(0);
161 if ((str == NULL) || (strcmp(str, DST_DYN_POI) != 0)) {
162 fatal(MYNAME "_poi: Invalid record header!\n");
163 }
164 xfree(str);
165 } else if (! read_until_wcstr(DST_DYN_POI)) {
166 break;
167 }
168
169 count++;
170
171 wpt = waypt_new();
172
173 wpt->shortname = read_wcstr(0);
174 wpt->notes = read_wcstr(0); /* comment */
175
176 hnum = read_wcstr(0); /* house number */
177
178 str = read_wcstr(0); /* street */
179 if (!str) {
180 str = hnum;
181 hnum = NULL;
182 }
183 if (str) {
184 gmsd = gmsd_init(wpt);
185 if (hnum) {
186 str = xstrappend(str, " ");
187 str = xstrappend(str, hnum);
188 }
189 GMSD_SET(addr, str);
190 }
191
192 if ((str = read_wcstr(0))) { /* city */
193 gmsd = gmsd_init(wpt);
194 GMSD_SET(city, str);
195 }
196
197 if (hnum) {
198 xfree(hnum);
199 }
200
201 (void) read_wcstr(1); /* unknown */
202
203 if ((str = read_wcstr(0))) { /* postcode */
204 gmsd = gmsd_init(wpt);
205 GMSD_SET(postal_code, str);
206 }
207
208 (void) read_wcstr(1); /* unknown */
209
210 (void) gbfgetdbl(fin);
211
212 wpt->longitude = gbfgetdbl(fin);
213 wpt->latitude = gbfgetdbl(fin);
214 ll = gbfgetdbl(fin);
215 if (ll != wpt->longitude) {
216 fatal(MYNAME "_poi: Invalid file!\n");
217 }
218 ll = gbfgetdbl(fin);
219 if (ll != wpt->latitude) {
220 fatal(MYNAME "_poi: Invalid file!\n");
221 }
222
223 waypt_add(wpt);
224 }
225 }
226
227 static void
destinator_read_rte(void)228 destinator_read_rte(void)
229 {
230 int count = 0;
231 route_head* rte = NULL;
232
233 gbfrewind(fin);
234
235 while (!(gbfeof(fin))) {
236 char* str;
237 waypoint* wpt;
238
239 if (count == 0) {
240 str = read_wcstr(0);
241 if ((str == NULL) || (strcmp(str, DST_ITINERARY) != 0)) {
242 fatal(MYNAME "_itn: Invalid record header!\n");
243 }
244 xfree(str);
245 } else if (! read_until_wcstr(DST_ITINERARY)) {
246 break;
247 }
248
249 count++;
250
251 wpt = waypt_new();
252
253 wpt->shortname = read_wcstr(0);
254 wpt->notes = read_wcstr(0);
255
256 (void) gbfgetint32(fin);
257 (void) gbfgetdbl(fin);
258 (void) gbfgetdbl(fin);
259
260 wpt->longitude = gbfgetdbl(fin);
261 wpt->latitude = gbfgetdbl(fin);
262 if (gbfgetdbl(fin) != wpt->longitude) {
263 fatal(MYNAME "_itn: Invalid file!\n");
264 }
265 if (gbfgetdbl(fin) != wpt->latitude) {
266 fatal(MYNAME "_itn: Invalid file!\n");
267 }
268
269 if (! rte) {
270 rte = route_head_alloc();
271 route_add_head(rte);
272 }
273 route_add_wpt(rte, wpt);
274
275 (void) gbfgetdbl(fin);
276 (void) gbfgetdbl(fin);
277 }
278 }
279
280 static void
destinator_read_trk(void)281 destinator_read_trk(void)
282 {
283 char TXT[4] = "TXT";
284 int recno = -1;
285 route_head* trk = NULL;
286
287 gbfrewind(fin);
288
289 while (!(gbfeof(fin))) {
290 waypoint* wpt;
291 struct tm tm;
292 char buff[20];
293 int date;
294 double time;
295
296 recno++;
297
298 if (gbfeof(fin)) {
299 break;
300 }
301
302 wpt = waypt_new();
303
304 wpt->longitude = gbfgetdbl(fin);
305 wpt->latitude = gbfgetdbl(fin);
306 wpt->altitude = gbfgetdbl(fin);
307
308 (void) gbfgetdbl(fin); /* unknown */
309 (void) gbfgetdbl(fin); /* unknown */
310 (void) gbfgetdbl(fin); /* unknown */
311
312 wpt->fix = (fix_type) gbfgetint32(fin);
313 wpt->sat = gbfgetint32(fin);
314
315 gbfseek(fin, 12 * sizeof(gbint32), SEEK_CUR); /* SAT info */
316
317 date = gbfgetint32(fin);
318 time = gbfgetflt(fin);
319
320 gbfseek(fin, 2 * 12, SEEK_CUR); /* SAT info */
321
322 gbfread(TXT, 1, 3, fin);
323 if (strcmp(TXT, "TXT") != 0) {
324 fatal(MYNAME "_trk: No (or unknown) file!\n");
325 }
326
327 gbfseek(fin, 13, SEEK_CUR); /* unknown */
328
329 memset(&tm, 0, sizeof(tm));
330
331 snprintf(buff, sizeof(buff), "%06d%.f", date, time);
332 strptime(buff, "%d%m%y%H%M%S", &tm);
333 wpt->creation_time = mkgmtime(&tm);
334 wpt->microseconds = ((int)time % 1000) * 1000;
335
336 if (wpt->fix > 0) {
337 wpt->fix = (fix_type)(wpt->fix + 1);
338 }
339
340 if (! trk) {
341 trk = route_head_alloc();
342 track_add_head(trk);
343 }
344 track_add_wpt(trk, wpt);
345 }
346 }
347
348 static void
destinator_read(void)349 destinator_read(void)
350 {
351 int i0, i1;
352 double d0, d1;
353 char buff[16];
354
355 if (! gbfread(buff, 1, sizeof(buff), fin)) {
356 fatal(MYNAME ": Unexpected EOF (end of file)!\n");
357 }
358
359 i0 = le_read32(&buff[0]);
360 i1 = le_read32(&buff[4]);
361
362 if ((i0 == 0x690043) && (i1 == 0x790074)) {
363 if (data_type != rtedata) {
364 warning(MYNAME ": Using Destinator Itinerary Format!\n");
365 }
366 destinator_read_rte();
367 } else if ((i0 == 0x790044) && (i1 == 0x61006e)) {
368 if (data_type != wptdata) {
369 warning(MYNAME ": Using Destinator POI Format!\n");
370 }
371 destinator_read_poi();
372 } else {
373 if (data_type != trkdata) {
374 warning(MYNAME ": Using Destinator Tracklog Format!\n");
375 }
376
377 le_read64(&d0, &buff[0]);
378 le_read64(&d1, &buff[8]);
379 if ((fabs(d0) > 180) || (fabs(d1) > 90)) {
380 fatal(MYNAME ": No Destinator (.dat) file!\n");
381 }
382 destinator_read_trk();
383 }
384 }
385
386 /*******************************************************************************/
387 /* WRITER */
388 /*-----------------------------------------------------------------------------*/
389
390 static void
destinator_wpt_disp(const waypoint * wpt)391 destinator_wpt_disp(const waypoint* wpt)
392 {
393 garmin_fs_t* gmsd = GMSD_FIND(wpt);
394
395 write_wcstr(DST_DYN_POI);
396 write_wcstr((wpt->shortname) ? wpt->shortname : "WPT");
397 write_wcstr((wpt->notes) ? wpt->notes : wpt->description);
398
399 write_wcstr(NULL); /* house number */
400 write_wcstr(GMSD_GET(addr, NULL)); /* street */
401 write_wcstr(GMSD_GET(city, NULL)); /* city */
402 write_wcstr(NULL); /* unknown */
403 write_wcstr(GMSD_GET(postal_code, NULL)); /* postcode */
404 write_wcstr(NULL); /* unknown */
405
406 gbfputint32(0, fout);
407 gbfputint32(0, fout);
408
409 gbfputdbl(wpt->longitude, fout);
410 gbfputdbl(wpt->latitude, fout);
411 gbfputdbl(wpt->longitude, fout);
412 gbfputdbl(wpt->latitude, fout);
413
414 gbfputdbl(0, fout);
415 gbfputdbl(0, fout);
416 }
417
418 static void
destinator_trkpt_disp(const waypoint * wpt)419 destinator_trkpt_disp(const waypoint* wpt)
420 {
421 int i;
422
423 gbfputdbl(wpt->longitude, fout);
424 gbfputdbl(wpt->latitude, fout);
425 gbfputdbl(wpt->altitude, fout);
426 gbfputdbl(0, fout);
427 gbfputdbl(0, fout);
428 gbfputdbl(0, fout);
429 gbfputint32(wpt->fix > fix_unknown ? wpt->fix - 1 : 0, fout);
430 gbfputint32(wpt->sat, fout);
431 for (i = 0; i < 12; i++) {
432 gbfputint32(0, fout);
433 }
434
435 if (wpt->creation_time) {
436 struct tm tm;
437 double time;
438 int date;
439
440 tm = *gmtime(&wpt->creation_time);
441 tm.tm_mon += 1;
442 tm.tm_year -= 100;
443 date = ((int)tm.tm_mday * 10000) + ((int)tm.tm_mon * 100) + tm.tm_year;
444 gbfputint32(date, fout);
445
446 time = ((int)tm.tm_hour * 10000) + ((int)tm.tm_min * 100) + tm.tm_sec;
447 time = (time * 1000) + (wpt->microseconds / 1000);
448 gbfputflt(time, fout);
449 } else {
450 gbfputint32(0, fout); /* Is this invalid ? */
451 gbfputflt(0, fout);
452 }
453
454 for (i = 0; i < 12; i++) {
455 gbfputint16(0, fout);
456 }
457 gbfputcstr("TXT", fout);
458 for (i = 0; i < 12; i++) {
459 gbfputc(0, fout);
460 }
461 }
462
463 static void
destinator_rtept_disp(const waypoint * wpt)464 destinator_rtept_disp(const waypoint* wpt)
465 {
466 write_wcstr(DST_ITINERARY);
467 write_wcstr((wpt->shortname) ? wpt->shortname : "RTEPT");
468 write_wcstr((wpt->notes) ? wpt->notes : wpt->description);
469
470 gbfputint32(0, fout);
471 gbfputdbl(0, fout);
472 gbfputdbl(0, fout);
473
474 gbfputdbl(wpt->longitude, fout);
475 gbfputdbl(wpt->latitude, fout);
476 gbfputdbl(wpt->longitude, fout);
477 gbfputdbl(wpt->latitude, fout);
478
479 gbfputdbl(0, fout);
480 gbfputdbl(0, fout);
481 }
482
483 /*******************************************************************************
484 * %%% global callbacks called by gpsbabel main process %%% *
485 *******************************************************************************/
486
487 static void
destinator_rd_init(const char * fname)488 destinator_rd_init(const char* fname)
489 {
490 fin = gbfopen_le(fname, "rb", MYNAME);
491 }
492
493 static void
destinator_rd_deinit(void)494 destinator_rd_deinit(void)
495 {
496 gbfclose(fin);
497 }
498
499 static void
destinator_read_poi_wrapper(void)500 destinator_read_poi_wrapper(void)
501 {
502 data_type = wptdata;
503 destinator_read();
504 }
505
506 static void
destinator_read_rte_wrapper(void)507 destinator_read_rte_wrapper(void)
508 {
509 data_type = rtedata;
510 destinator_read();
511 }
512
513 static void
destinator_read_trk_wrapper(void)514 destinator_read_trk_wrapper(void)
515 {
516 data_type = trkdata;
517 destinator_read();
518 }
519
520 static void
destinator_wr_init(const char * fname)521 destinator_wr_init(const char* fname)
522 {
523 fout = gbfopen_le(fname, "wb", MYNAME);
524 }
525
526 static void
destinator_wr_deinit(void)527 destinator_wr_deinit(void)
528 {
529 gbfclose(fout);
530 }
531
532 static void
destinator_write_poi(void)533 destinator_write_poi(void)
534 {
535 waypt_disp_all(destinator_wpt_disp);
536 }
537
538 static void
destinator_write_rte(void)539 destinator_write_rte(void)
540 {
541 route_disp_all(NULL, NULL, destinator_rtept_disp);
542 }
543
544 static void
destinator_write_trk(void)545 destinator_write_trk(void)
546 {
547 track_disp_all(NULL, NULL, destinator_trkpt_disp);
548 }
549
550 /**************************************************************************/
551
552 ff_vecs_t destinator_poi_vecs = {
553 ff_type_file,
554 {
555 (ff_cap)(ff_cap_read | ff_cap_write) /* waypoints */,
556 ff_cap_none /* tracks */,
557 ff_cap_none /* routes */
558 },
559 destinator_rd_init,
560 destinator_wr_init,
561 destinator_rd_deinit,
562 destinator_wr_deinit,
563 destinator_read_poi_wrapper,
564 destinator_write_poi,
565 NULL,
566 destinator_args,
567 CET_CHARSET_UTF8, 1 /* fixed */
568 };
569
570 ff_vecs_t destinator_itn_vecs = {
571 ff_type_file,
572 {
573 ff_cap_none /* waypoints */,
574 ff_cap_none /* tracks */,
575 (ff_cap)(ff_cap_read | ff_cap_write) /* routes */
576 },
577 destinator_rd_init,
578 destinator_wr_init,
579 destinator_rd_deinit,
580 destinator_wr_deinit,
581 destinator_read_rte_wrapper,
582 destinator_write_rte,
583 NULL,
584 destinator_args,
585 CET_CHARSET_UTF8, 1 /* fixed */
586 };
587
588 ff_vecs_t destinator_trl_vecs = {
589 ff_type_file,
590 {
591 ff_cap_none /* waypoints */,
592 (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */,
593 ff_cap_none /* routes */
594 },
595 destinator_rd_init,
596 destinator_wr_init,
597 destinator_rd_deinit,
598 destinator_wr_deinit,
599 destinator_read_trk_wrapper,
600 destinator_write_trk,
601 NULL,
602 destinator_args,
603 CET_CHARSET_UTF8, 1 /* fixed */
604 };
605
606 /**************************************************************************/
607