1 /*
2
3 Read/write Alan Map500 Waypoints, Routes and Tracklogs.
4
5 Provides "alanwpr" and "alantrl" formats for gpsbabel.
6 Currently supports OS 2.xx only.
7
8 Copyright (C) 2007 Gunar Megger, 0xff@quantentunnel.de
9 Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
24
25 */
26
27 #include <stdio.h>
28 #include <time.h>
29 #include "defs.h"
30
31
32 #define MYNAME "alan"
33
34 #define MAXWPT 1000 /* old 500 */
35
36 #define MAXRTE 50 /* old 20 */
37 #define MAXWPTINRTE 150 /* old 30 */
38
39 #define MAXTRK 8 /* old 5 */
40 #define MAXPTINTRK 2500
41
42 #define WPT_NAME_LEN 8
43 #define WPT_COMMENT_LEN 12
44
45 #define RTE_NAME_LEN 8
46 #define RTE_COMMENT_LEN 12
47
48 #define TRK_NAME_LEN 12
49 #define TRK_COMMENT_LEN 13
50
51 struct wpthdr {
52 gbuint32 id;
53 gbint16 num;
54 gbint16 next;
55 gbint16 idx[MAXWPT];
56 gbuint8 used[MAXWPT];
57 };
58
59 struct wpt {
60 char name[WPT_NAME_LEN];
61 char comment[WPT_COMMENT_LEN];
62 struct {
63 gbint32 x; /* degree * 36000 */
64 gbint32 y; /* degree * 36000 */
65 } pt;
66 gbint32 date;
67 gbint32 time;
68 gbint16 usecount;
69 gbint8 checked;
70 gbint8 reserved;
71 };
72
73 struct rtehdr {
74 gbuint32 id;
75 gbint16 num;
76 gbint16 next;
77 gbint16 idx[MAXRTE];
78 gbuint8 used[MAXRTE];
79 gbint16 rteno;
80 };
81
82 struct rte {
83 char name[RTE_NAME_LEN];
84 char comment[RTE_COMMENT_LEN];
85 gbint16 wptnum;
86 gbint16 wptidx[MAXWPTINRTE];
87 gbint16 reserved;
88 gbint32 date;
89 gbint32 time;
90 };
91
92 struct wprdata {
93 struct wpthdr wpthdr;
94 struct wpt wpt[MAXWPT];
95 struct rtehdr rtehdr;
96 struct rte rte[MAXRTE];
97 };
98
99 struct trkhdr {
100 gbint16 totalpt;
101 gbint16 next;
102 char name[TRK_NAME_LEN]; /* 10, null terminated */
103 char comment[TRK_COMMENT_LEN]; /* 12, null terminated */
104 gbuint8 reserved[3];
105 gbuint32 occupied;
106 gbuint32 show;
107 gbuint32 fill;
108 };
109
110 struct loghdr {
111 gbuint32 id;
112 gbint16 num;
113 gbint16 next;
114 gbint32 date;
115 gbint32 time;
116 struct trkhdr trkhdr[MAXTRK];
117 };
118
119 struct trklog {
120 struct {
121 gbint32 x; /* degree * 36000 */
122 gbint32 y; /* degree * 36000 */
123 } pt[MAXPTINTRK];
124 struct {
125 gbint16 speed; /* km/h * 200 */
126 gbint16 height; /* m * 5 */
127 } sh[MAXPTINTRK];
128 };
129
130 struct trldata {
131 struct loghdr loghdr;
132 struct trklog trklog[MAXTRK];
133 };
134
135 #define WPT_HDR_ID 0x5C38A600
136 #define RTE_HDR_ID 0xD87F5900
137 #define TRL_HDR_ID 0x38CB1200
138
139 #define WPT_IDX_NONE -1 /* 0xffff */
140 #define WPT_USED 0xff
141 #define WPT_UNUSED 0
142 #define WPT_CHECKED 1
143 #define WPT_UNCHECKED 0
144
145 #define RTE_IDX_NONE -1 /* 0xffff */
146 #define RTE_USED 0xff
147 #define RTE_UNUSED 0
148 #define RTE_RTENO_NONE -1
149
150 #define TRK_USED 1
151 #define TRK_UNUSED 0
152 #define TRK_SHOW 1
153 #define TRK_HIDE 0
154 #define TRK_FILL 1
155 #define TRK_WRAP 0
156
157 #define MAP500_PT_SCALE 36000.0
158 #define pt2deg(P) ((double)(P) / MAP500_PT_SCALE)
159 #define deg2pt(D) (gbint32)si_round((double)(D) * MAP500_PT_SCALE)
160
161 #define MAP500_ALTITUDE_SCALE 5.0
162 #define hgt2m(A) ((double)(A) / MAP500_ALTITUDE_SCALE)
163 #define m2hgt(A) (gbint16)si_round((double)(A) * MAP500_ALTITUDE_SCALE)
164
165 #define MAP500_SPEED_SCALE 720.0
166 #define sp2mps(S) ((double)(S) / MAP500_SPEED_SCALE)
167 #define mps2sp(S) (gbint16)si_round((double)(S) * MAP500_SPEED_SCALE)
168
169 #define BYTEORDER_TEST 0x04030201 /* 32bit reference value */
170 enum {
171 SWAP_NONE = 0x1234, /* map500 regular */
172 SWAP_BYTES = 0x2143, /* bytes swapped */
173 SWAP_WORDS = 0x3412, /* words swapped */
174 SWAP_BOTH = 0x4321 /* words + bytes swapped */
175 };
176
177 /**************************************************************************/
178
179 static gbfile* fin = NULL, *fout = NULL;
180 struct wprdata WPR;
181 struct trldata TRL;
182
183 static arglist_t wpr_args[] = {
184 /*
185 {"os3", &osversion, "Operating system version 3",
186 NULL, ARGTYPE_BOOL, ARGNOMINMAX },
187 */
188 ARG_TERMINATOR
189 };
190 static arglist_t trl_args[] = {
191 /*
192 {"os3", &osversion, "Operating system version 3",
193 NULL, ARGTYPE_BOOL, ARGNOMINMAX },
194 */
195 ARG_TERMINATOR
196 };
197
198 /**************************************************************************/
199 // FIXME: Why is this code doing its own byte order conversion?
byte_order(void)200 static unsigned int byte_order(void)
201 {
202 unsigned long test = BYTEORDER_TEST;
203 unsigned char* ptr;
204 unsigned int order;
205
206 ptr = (unsigned char*)(&test);
207 order = (ptr[0] << 12) | (ptr[1] << 8) | (ptr[2] << 4) | ptr[3];
208
209 return order;
210 }
211
sw_bytes(void * word)212 static void sw_bytes(void* word)
213 {
214 gbuint8* p = (gbuint8*) word;
215 gbuint16* r = (gbuint16*) word;
216
217 *r = (gbuint16)(p[1] << 8 | p[0]);
218 }
sw_words(void * dword)219 static void sw_words(void* dword)
220 {
221 gbuint16* p = (gbuint16*) dword;
222 gbuint32* r = (gbuint32*) dword;
223
224 *r = (gbuint32)(p[0] << 16 | p[1]);
225 }
rev_bytes(void * dword)226 static void rev_bytes(void* dword)
227 {
228 gbuint8* p = (gbuint8*) dword;
229 gbuint32* r = (gbuint32*) dword;
230
231 *r = (gbuint32)(p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]);
232 }
233
swap_wpthdr(struct wpthdr * wpthdr,void (* swap16_func)(void *),void (* swap32_func)(void *))234 static void swap_wpthdr(struct wpthdr* wpthdr,
235 void (*swap16_func)(void*), void (*swap32_func)(void*))
236 {
237 int i;
238
239 if (swap32_func != NULL) {
240 swap32_func(&wpthdr->id);
241 }
242 if (swap16_func != NULL) {
243 swap16_func(&wpthdr->num);
244 swap16_func(&wpthdr->next);
245 for (i=0; i<MAXWPT; i++) {
246 swap16_func(&wpthdr->idx[i]);
247 }
248 }
249 }
250
swap_wpt(struct wpt * wpt,void (* swap16_func)(void *),void (* swap32_func)(void *))251 static void swap_wpt(struct wpt* wpt,
252 void (*swap16_func)(void*), void (*swap32_func)(void*))
253 {
254 if (swap16_func != NULL) {
255 swap16_func(&wpt->usecount);
256 }
257 if (swap32_func != NULL) {
258 swap32_func(&wpt->pt.x);
259 swap32_func(&wpt->pt.y);
260 swap32_func(&wpt->date);
261 swap32_func(&wpt->time);
262 }
263 }
264
swap_rtehdr(struct rtehdr * rtehdr,void (* swap16_func)(void *),void (* swap32_func)(void *))265 static void swap_rtehdr(struct rtehdr* rtehdr,
266 void (*swap16_func)(void*), void (*swap32_func)(void*))
267 {
268 int i;
269
270 if (swap16_func != NULL) {
271 swap16_func(&rtehdr->num);
272 swap16_func(&rtehdr->next);
273 for (i=0; i<MAXRTE; i++) {
274 swap16_func(&rtehdr->idx[i]);
275 }
276 swap16_func(&rtehdr->rteno);
277 }
278 if (swap32_func != NULL) {
279 swap32_func(&rtehdr->id);
280 }
281 }
282
swap_rte(struct rte * rte,void (* swap16_func)(void *),void (* swap32_func)(void *))283 static void swap_rte(struct rte* rte,
284 void (*swap16_func)(void*), void (*swap32_func)(void*))
285 {
286 int i;
287
288 if (swap16_func != NULL) {
289 swap16_func(&rte->wptnum);
290 for (i=0; i<MAXWPTINRTE; i++) {
291 swap16_func(&rte->wptidx[i]);
292 }
293 swap16_func(&rte->reserved);
294 }
295 if (swap32_func != NULL) {
296 swap32_func(&rte->date);
297 swap32_func(&rte->time);
298 }
299 }
300
wpr_swap(struct wprdata * wprdata)301 static void wpr_swap(struct wprdata* wprdata)
302 {
303 void (*swap16_func)(void*);
304 void (*swap32_func)(void*);
305 int i;
306
307 switch (byte_order()) {
308 case SWAP_NONE: /* same byte oder, LITTLE_ENDIAN */
309 return;
310 break;
311 case SWAP_BOTH: /* swap words and bytes, BIG_ENDIAN */
312 swap16_func = sw_bytes;
313 swap32_func = rev_bytes;
314 break;
315 case SWAP_WORDS: /* swap words, PDP_ENDIAN */
316 swap16_func = NULL;
317 swap32_func = sw_words;
318 break;
319 case SWAP_BYTES: /* swap bytes */
320 swap16_func = sw_bytes;
321 swap32_func = NULL;
322 break;
323 default:
324 return; /* never reached */
325 }
326
327 swap_wpthdr(&(wprdata->wpthdr), swap16_func, swap32_func);
328 for (i=0; i< MAXWPT; i++) {
329 swap_wpt(&(wprdata->wpt[i]), swap16_func, swap32_func);
330 }
331 swap_rtehdr(&(wprdata->rtehdr), swap16_func, swap32_func);
332 for (i=0; i<MAXRTE; i++) {
333 swap_rte(&(wprdata->rte[i]), swap16_func, swap32_func);
334 }
335 }
336
swap_trkhdr(struct trkhdr * trkhdr,void (* swap16_func)(void *),void (* swap32_func)(void *))337 static void swap_trkhdr(struct trkhdr* trkhdr,
338 void (*swap16_func)(void*), void (*swap32_func)(void*))
339 {
340 if (swap16_func != NULL) {
341 swap16_func(&(trkhdr->totalpt));
342 swap16_func(&(trkhdr->next));
343 }
344 if (swap32_func != NULL) {
345 swap32_func(&(trkhdr->occupied));
346 swap32_func(&(trkhdr->show));
347 swap32_func(&(trkhdr->fill));
348 }
349 }
350
swap_loghdr(struct loghdr * loghdr,void (* swap16_func)(void *),void (* swap32_func)(void *))351 static void swap_loghdr(struct loghdr* loghdr,
352 void (*swap16_func)(void*), void (*swap32_func)(void*))
353 {
354 int i;
355
356 if (swap16_func != NULL) {
357 swap16_func(&(loghdr->num));
358 swap16_func(&(loghdr->next));
359 }
360 if (swap32_func != NULL) {
361 swap32_func(&(loghdr->id));
362 swap32_func(&(loghdr->date));
363 swap32_func(&(loghdr->time));
364 }
365 for (i=0; i<MAXTRK; i++) {
366 swap_trkhdr(&(loghdr->trkhdr[i]), swap16_func, swap32_func);
367 }
368 }
369
swap_trklog(struct trklog * trklog,void (* swap16_func)(void *),void (* swap32_func)(void *))370 static void swap_trklog(struct trklog* trklog,
371 void (*swap16_func)(void*), void (*swap32_func)(void*))
372 {
373 int i;
374
375 if (swap16_func != NULL) {
376 for (i=0; i<MAXPTINTRK; i++) {
377 swap16_func(&(trklog->sh[i].speed));
378 swap16_func(&(trklog->sh[i].height));
379 }
380 }
381 if (swap32_func != NULL) {
382 for (i=0; i<MAXPTINTRK; i++) {
383 swap32_func(&(trklog->pt[i].x));
384 swap32_func(&(trklog->pt[i].y));
385 }
386 }
387 }
388
trl_swap(struct trldata * trldata)389 static void trl_swap(struct trldata* trldata)
390 {
391 void (*swap16_func)(void*);
392 void (*swap32_func)(void*);
393 int i;
394
395 switch (byte_order()) {
396 case SWAP_NONE: /* same byte oder, LITTLE_ENDIAN */
397 return;
398 break;
399 case SWAP_BOTH: /* swap words and bytes, BIG_ENDIAN */
400 swap16_func = sw_bytes;
401 swap32_func = rev_bytes;
402 break;
403 case SWAP_WORDS: /* swap words, PDP_ENDIAN */
404 swap16_func = NULL;
405 swap32_func = sw_words;
406 break;
407 case SWAP_BYTES: /* swap bytes */
408 swap16_func = sw_bytes;
409 swap32_func = NULL;
410 break;
411 default:
412 return; /* never reached */
413 }
414
415 swap_loghdr(&(trldata->loghdr), swap16_func, swap32_func);
416 for (i=0; i<MAXTRK; i++) {
417 swap_trklog(&(trldata->trklog[i]), swap16_func, swap32_func);
418 }
419 }
420
421
422 /**************************************************************************/
423
str2lab(char * dest,char * src,int len,char * fmt,int n)424 static void str2lab(char* dest, char* src, int len, char* fmt, int n)
425 {
426 int i,j;
427
428 j = 0;
429 if (src != NULL) {
430 for (i=0; i<len && src[i] != '\0'; i++) {
431 if (isprint(src[i])) {
432 dest[j++] = src[i];
433 }
434 }
435 }
436 if (j == 0 && fmt != NULL) {
437 snprintf(dest, len, fmt, n);
438 j = strlen(dest);
439 }
440 if (j < len) {
441 memset(dest+j, ' ', len-j);
442 }
443 }
444
pack_time(time_t t,gbint32 * date,gbint32 * time)445 static void pack_time(time_t t, gbint32* date, gbint32* time)
446 {
447 struct tm* tm;
448
449 tm = gmtime(&t);
450 *date = tm->tm_mday | ((tm->tm_mon+1)<<8) | ((tm->tm_year+1900)<<16);
451 *time = t % 86400;
452 }
453
unpack_time(gbint32 date,gbint32 time)454 static time_t unpack_time(gbint32 date, gbint32 time)
455 {
456 time_t result;
457 short year, month, day;
458 static int m_to_d[12] =
459 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
460
461 year = (date >> 16) & 0xffff;
462 month = (date >> 8) & 0xff; /* 1-12 */
463 day = date & 0xff; /* 1-31 */
464
465 month -= 1; /* fit struct tm */
466 year += month / 12;
467
468 if (month < 0) {
469 year -= 1;
470 month += 12;
471 }
472 result = (year - 1970) * 365 + m_to_d[month];
473 if (month <= 1) {
474 year -= 1;
475 }
476 result += (year - 1968) / 4;
477 result -= (year - 1900) / 100;
478 result += (year - 1600) / 400;
479 result += day;
480 result -= 1;
481 result *= 86400;
482 result += time; /* map500 time is inseconds of the day */
483
484 return result;
485 }
486
487 /**************************************************************************/
488
get_wpt(struct wprdata * wprdata,unsigned n)489 static waypoint* get_wpt(struct wprdata* wprdata, unsigned n)
490 {
491 struct wpthdr* wpthdr;
492 struct wpt* wpt;
493 int j, idx;
494 waypoint* WP;
495
496 wpthdr = &(wprdata->wpthdr);
497 idx = wpthdr->idx[n];
498
499 if (idx == WPT_IDX_NONE || wpthdr->used[idx] == WPT_UNUSED) {
500 return NULL;
501 }
502 wpt = &(wprdata->wpt[idx]);
503
504 WP = waypt_new();
505 WP->latitude = -pt2deg(wpt->pt.y);
506 WP->longitude = pt2deg(wpt->pt.x);
507 WP->creation_time = unpack_time(wpt->date, wpt->time);
508 for (j=WPT_NAME_LEN-1; j >= 0 && wpt->name[j] == ' '; j--) {};
509 WP->shortname = xstrndup(wpt->name,j+1);
510 for (j=WPT_COMMENT_LEN-1; j >= 0 && wpt->comment[j] == ' '; j--) {};
511 if (j >= 0) {
512 WP->description = xstrndup(wpt->comment, j+1);
513 } else {
514 WP->description = xstrdup("");
515 }
516 WP->notes = xstrdup("");
517
518 return WP;
519 }
520
wpr_read(void)521 static void wpr_read(void)
522 {
523 struct wprdata wprdata;
524 struct rtehdr* rtehdr;
525 struct rte* rte;
526 int i, j, idx;
527 waypoint* WP;
528 route_head* RT;
529
530 if (gbfread(&wprdata, sizeof(struct wprdata), 1, fin) != 1) {
531 fatal(MYNAME ": Read error on %s\n", fin->name);
532 }
533 wpr_swap(&wprdata);
534 if (wprdata.wpthdr.id != WPT_HDR_ID ||
535 wprdata.rtehdr.id != RTE_HDR_ID) {
536 fatal(MYNAME ": %s is not in Alan .wpr format.\n", fin->name);
537 }
538
539 /* waypoints */
540 for (i=0; i<MAXWPT; i++) {
541 WP = get_wpt(&wprdata, i);
542 if (WP != NULL) {
543 waypt_add(WP);
544 }
545 }
546
547 /* routes */
548 rtehdr = &(wprdata.rtehdr);
549 for (i=0; i<MAXRTE; i++) {
550 idx = rtehdr->idx[i];
551 if (idx == RTE_IDX_NONE || rtehdr->used[idx] == RTE_UNUSED) {
552 continue;
553 }
554 rte = &(wprdata.rte[idx]);
555
556 RT = route_head_alloc();
557 RT->rte_num = i;
558 for (j=RTE_NAME_LEN-1; j >= 0 && rte->name[j] == ' '; j--) {};
559 RT->rte_name = xstrndup(rte->name,j+1);
560 for (j=RTE_COMMENT_LEN-1; j >= 0 && rte->comment[j] == ' '; j--) {};
561 if (j >= 0) {
562 RT->rte_desc = xstrndup(rte->comment,j+1);
563 } else {
564 RT->rte_desc = xstrdup("");
565 }
566
567 route_add_head(RT);
568
569 /* route points */
570 for (j=0; j<rte->wptnum; j++) {
571 WP = get_wpt(&wprdata, rte->wptidx[j]);
572 if (WP != NULL) {
573 route_add_wpt(RT, WP);
574 }
575 }
576 }
577 }
578
trl_read(void)579 static void trl_read(void)
580 {
581 struct trldata trldata;
582 struct trkhdr* trkhdr;
583 struct trklog* trklog;
584 waypoint* WP;
585 route_head* TL;
586 int i, j;
587
588 for (i=0; i<MAXTRK; i+=2) {
589 gbfseek(fin, 0x10000 * (i/2), SEEK_SET);
590 if (gbfread(&(trldata.trklog[i]), sizeof(struct trklog), 2, fin) != 2) {
591 fatal(MYNAME ": Read error on %s\n", fin->name);
592 }
593 }
594 gbfseek(fin, 0x10000 * MAXTRK/2, SEEK_SET);
595 if (gbfread(&(trldata.loghdr), sizeof(struct loghdr), 1, fin) != 1) {
596 fatal(MYNAME ": Read error on %s\n", fin->name);
597 }
598 trl_swap(&trldata);
599 if (trldata.loghdr.id != TRL_HDR_ID) {
600 fatal(MYNAME ": %s is not in Alan .trl format.\n", fin->name);
601 }
602
603 for (i=0; i<MAXTRK; i++) {
604 /* track header */
605 trkhdr = &(trldata.loghdr.trkhdr[i]);
606 if (trkhdr->occupied == TRK_UNUSED) {
607 continue;
608 }
609 TL = route_head_alloc();
610 for (j=TRK_NAME_LEN-1;
611 j >= 0 && (trkhdr->name[j] == ' ' || trkhdr->name[j] == '\0');
612 j--) {};
613 TL->rte_name = xstrndup(trkhdr->name,j+1);
614 /* TL->rte_name[TRK_NAME_LEN+1] = 0; */ /* MAYBE BAD ADDRESS (Valgrind) */
615 for (j=TRK_COMMENT_LEN-1;
616 j >= 0 && (trkhdr->comment[j] == ' ' || trkhdr->comment[j] == '\0');
617 j--) {};
618 TL->rte_desc = xstrndup(trkhdr->comment,j+1);
619 /* TL->rte_desc[TRK_COMMENT_LEN+1] = 0; */ /* MAYBE BAD ADDRESS (Valgrind) */
620 TL->rte_num = i;
621
622 track_add_head(TL);
623
624 /* track points */
625 trklog = &(trldata.trklog[i]);
626 for (j=0; j<trkhdr->totalpt; j++) {
627 WP = waypt_new();
628 WP->latitude = -pt2deg(trklog->pt[j].y);
629 WP->longitude = pt2deg(trklog->pt[j].x);
630 WP->altitude = hgt2m(trklog->sh[j].height);
631 if (trklog->sh[j].speed >= 0)
632 WAYPT_SET(WP, speed, sp2mps(trklog->sh[j].speed))
633 else { /* bad speed < 0 - set to 0.0 */
634 WAYPT_UNSET(WP, speed);
635 }
636 track_add_wpt(TL, WP);
637 }
638 }
639 }
640
641 /**************************************************************************/
642
find_wpt(struct wprdata * wprdata,const waypoint * WP)643 static int find_wpt(struct wprdata* wprdata, const waypoint* WP)
644 {
645 struct wpt pattern, *wpt;
646 int i, wpt_idx;
647
648 str2lab(pattern.name, WP->shortname, WPT_NAME_LEN, NULL, 0);
649 pattern.pt.x = deg2pt(WP->longitude);
650 pattern.pt.y = deg2pt(-WP->latitude);
651
652 wpt = wprdata->wpt;
653 for (i=0; i<MAXWPT; i++) {
654 wpt_idx = wprdata->wpthdr.idx[i];
655 if (wpt_idx == WPT_IDX_NONE ||
656 wprdata->wpthdr.used[wpt_idx] == WPT_UNUSED) {
657 continue;
658 }
659 if (strncmp(wpt[wpt_idx].name, pattern.name, WPT_NAME_LEN) == 0 &&
660 wpt[wpt_idx].pt.x == pattern.pt.x &&
661 wpt[wpt_idx].pt.y == pattern.pt.y) {
662 return i;
663 }
664 }
665
666 return -1;
667 }
668
add_wpt(struct wprdata * wprdata,const waypoint * WP,int isroute)669 static int add_wpt(struct wprdata* wprdata, const waypoint* WP,int isroute)
670 {
671 struct wpthdr* wpthdr;
672 int hdr_idx, wpt_idx;
673 struct wpt* wpt;
674 int i;
675
676 wpthdr = &(wprdata->wpthdr);
677
678 hdr_idx = find_wpt(wprdata, WP);
679 if (hdr_idx >= 0) {
680 /* duplicate waypoint */
681 if (isroute) {
682 wpt = &(wprdata->wpt[wpthdr->idx[hdr_idx]]);
683 wpt->usecount ++;
684 }
685 /*
686 warning(MYNAME ": using duplicate waypoint '%s' at (%f�, %f�)\n",
687 WP->shortname, WP->latitude, WP->longitude);
688 */
689 return hdr_idx;
690 }
691
692 for (i=0; i<MAXWPT && wpthdr->idx[i] != WPT_IDX_NONE; i++) { }
693 hdr_idx = i;
694 for (i=0; i<MAXWPT && wpthdr->used[i] != WPT_UNUSED; i++) { }
695 wpt_idx = i;
696 if (wpthdr->num >= MAXWPT || hdr_idx >= MAXWPT || wpt_idx >= MAXWPT) {
697 fatal(MYNAME ": Can't store more than %u waypoints\n", MAXWPT);
698 }
699
700 wpt = &(wprdata->wpt[wpt_idx]);
701 str2lab(wpt->name, WP->shortname, WPT_NAME_LEN, "W%05d", wpt_idx);
702 str2lab(wpt->comment, WP->description, WPT_COMMENT_LEN, NULL, 0);
703 wpt->pt.x = deg2pt(WP->longitude);
704 wpt->pt.y = deg2pt(-WP->latitude);
705 wpt->usecount = isroute ? 1 : 0;
706 wpt->checked = isroute ? 0 : 1;
707 wpt->reserved = 0;
708 pack_time(WP->creation_time, &(wpt->date), &(wpt->time));
709
710 wpthdr->idx[hdr_idx] = wpt_idx;
711 wpthdr->used[wpt_idx] = WPT_USED;
712 wpthdr->num++;
713 wpthdr->next++;
714 if (wpthdr->next >= MAXWPT) { /* overrun */
715 wpthdr->next = 0;
716 }
717
718 return hdr_idx;
719 }
720
wpr_waypoint(const waypoint * WP)721 static void wpr_waypoint(const waypoint* WP)
722 {
723 add_wpt(&WPR, WP, 0);
724 }
725
wpr_route_hdr(const route_head * RT)726 static void wpr_route_hdr(const route_head* RT)
727 {
728 struct rtehdr* rtehdr;
729 int hdr_idx, rte_idx;
730 struct rte* rte;
731 int i;
732
733 rtehdr = &(WPR.rtehdr);
734 for (i=0; i<MAXRTE && rtehdr->idx[i] != RTE_IDX_NONE; i++) { }
735 hdr_idx = i;
736 for (i=0; i<MAXRTE && rtehdr->used[i] != RTE_UNUSED; i++) { }
737 rte_idx = i;
738 if (rtehdr->num >= MAXRTE || hdr_idx >= MAXRTE || rte_idx >= MAXRTE) {
739 fatal(MYNAME ": Can't store more than %u routes", MAXRTE);
740 }
741
742 rte = &(WPR.rte[rte_idx]);
743 str2lab(rte->name, RT->rte_name, RTE_NAME_LEN, "R%03d", rte_idx);
744 str2lab(rte->comment, RT->rte_desc, RTE_COMMENT_LEN, NULL, 0);
745 pack_time(time(NULL), &(rte->date), &(rte->time));
746
747 rtehdr->idx[hdr_idx] = rte_idx;
748 rtehdr->used[rte_idx] = RTE_USED;
749 rtehdr->num++;
750 rtehdr->next++;
751 if (rtehdr->next >= MAXRTE) { /* overrun */
752 rtehdr->next = 0;
753 }
754
755 /* if you want the new route to be active, uncomment the next line */
756 /* rtehdr->rteno = rte_idx; */
757 }
758
wpr_route_wpt(const waypoint * WP)759 static void wpr_route_wpt(const waypoint* WP)
760 {
761 struct rte* rte;
762 int wpt_idx;
763
764 rte = &(WPR.rte[WPR.rtehdr.num -1]);
765 if (rte->wptnum >= MAXWPTINRTE) {
766 fatal(MYNAME ": Can't store more than %u waypoints per route", MAXWPTINRTE);
767 }
768
769 wpt_idx = add_wpt(&WPR, WP, 1);
770
771 rte->wptidx[rte->wptnum] = wpt_idx;
772 rte->wptnum ++;
773 }
774
wpr_route_trl(const route_head * RT)775 static void wpr_route_trl(const route_head* RT)
776 {
777 /* should we do some final sanity checks? */
778 }
779
wpr_write(void)780 static void wpr_write(void)
781 {
782 int i;
783
784 WPR.wpthdr.id = WPT_HDR_ID;
785 WPR.wpthdr.num = WPR.wpthdr.next = 0;
786 for (i=0; i<MAXWPT; i++) {
787 WPR.wpthdr.idx[i] = WPT_IDX_NONE;
788 WPR.wpthdr.used[i] = WPT_UNUSED;
789 }
790 memset(WPR.wpt, 0, MAXWPT * sizeof(struct wpt));
791 WPR.rtehdr.id = RTE_HDR_ID;
792 WPR.rtehdr.num = WPR.rtehdr.next = 0;
793 for (i=0; i<MAXRTE; i++) {
794 WPR.rtehdr.idx[i] = RTE_IDX_NONE;
795 WPR.rtehdr.used[i] = RTE_UNUSED;
796 }
797 WPR.rtehdr.rteno = RTE_RTENO_NONE;
798 memset(WPR.rte, 0, MAXRTE * sizeof(struct rte));
799
800 waypt_disp_all(wpr_waypoint);
801 route_disp_all(wpr_route_hdr, wpr_route_trl, wpr_route_wpt);
802
803 wpr_swap(&WPR);
804 if (gbfwrite(&WPR, sizeof(struct wprdata), 1, fout) != 1) {
805 fatal(MYNAME ": Write error on %s\n", fout->name);
806 }
807 }
808
809 /**************************************************************************/
810
trl_track_hdr(const route_head * TL)811 static void trl_track_hdr(const route_head* TL)
812 {
813 struct trkhdr* trkhdr;
814 int idx, l;
815
816 trkhdr = TRL.loghdr.trkhdr;
817
818 for (idx=0; idx< MAXTRK && trkhdr[idx].occupied != TRK_UNUSED; idx++) {};
819 if (idx >= MAXTRK) {
820 fatal(MYNAME ": Can't store more than %u tracklogs", MAXTRK);
821 }
822
823 if (TL->rte_name != NULL) {
824 strncpy(trkhdr[idx].name, TL->rte_name, TRK_NAME_LEN);
825 }
826 if (*(trkhdr[idx].name) == '\0') {
827 sprintf(trkhdr[idx].name, "T%03d", idx);
828 }
829 trkhdr[idx].name[TRK_NAME_LEN-1] = '\0';
830
831 if (TL->rte_desc != NULL) {
832 strncpy(trkhdr[idx].comment, TL->rte_desc, TRK_COMMENT_LEN);
833 l = strlen(TL->rte_desc);
834 if (l < TRK_COMMENT_LEN-1) {
835 memset(trkhdr[idx].comment + l, ' ', TRK_COMMENT_LEN - l);
836 }
837 }
838 trkhdr[idx].comment[TRK_COMMENT_LEN-1] = '\0';
839
840 trkhdr[idx].comment[TRK_COMMENT_LEN-1] = '\0';
841 trkhdr[idx].occupied = TRK_USED;
842 trkhdr[idx].totalpt = 0;
843 trkhdr[idx].next = 0;
844
845 TRL.loghdr.num = idx;
846 }
847
trl_track_wpt(const waypoint * WP)848 static void trl_track_wpt(const waypoint* WP)
849 {
850 struct trklog* trklog;
851 struct trkhdr* trkhdr;
852 int trk_idx, log_idx;
853
854 trk_idx = TRL.loghdr.num;
855
856 trkhdr = &(TRL.loghdr.trkhdr[trk_idx]);
857 if (trkhdr->totalpt >= MAXPTINTRK) {
858 fatal(MYNAME ": Can't store more than %u points per track", MAXPTINTRK);
859 }
860 log_idx = trkhdr->next;
861
862 trklog = &(TRL.trklog[trk_idx]);
863 trklog->pt[log_idx].x = deg2pt(WP->longitude);
864 trklog->pt[log_idx].y = deg2pt(-WP->latitude);
865 if WAYPT_HAS(WP, speed) {
866 trklog->sh[log_idx].speed = mps2sp(WP->speed);
867 }
868 if (WP->altitude != unknown_alt) {
869 trklog->sh[log_idx].height = m2hgt(WP->altitude);
870 }
871
872 trkhdr->totalpt ++;
873 trkhdr->next = trkhdr->totalpt;
874 }
875
trl_track_tlr(const route_head * TL)876 static void trl_track_tlr(const route_head* TL)
877 {
878 struct trkhdr* trkhdr;
879 int trk_idx;
880
881 trk_idx = TRL.loghdr.num;
882 trkhdr = &(TRL.loghdr.trkhdr[trk_idx]);
883
884 if (trkhdr->totalpt == 0) {
885 trkhdr->occupied = TRK_UNUSED;
886 }
887
888 TRL.loghdr.num = -1;
889 }
890
trl_write(void)891 static void trl_write(void)
892 {
893 struct trkhdr* trkhdr;
894 void* buf;
895 int i;
896 size_t fill;
897
898 TRL.loghdr.id = TRL_HDR_ID;
899 TRL.loghdr.num = TRL.loghdr.next = -1;
900 TRL.loghdr.date = TRL.loghdr.time = 0;
901 for (i=0; i<MAXTRK; i++) {
902 trkhdr = &(TRL.loghdr.trkhdr[i]);
903 trkhdr->totalpt = 0;
904 trkhdr->next = 0;
905 memset(trkhdr->name, 0, TRK_NAME_LEN);
906 memset(trkhdr->comment, ' ', TRK_COMMENT_LEN);
907 trkhdr->comment[TRK_COMMENT_LEN-1] = '\0';
908 trkhdr->occupied = TRK_UNUSED;
909 trkhdr->show = TRK_HIDE;
910 trkhdr->fill = TRK_FILL;
911 }
912 memset(TRL.trklog, 0xff, sizeof(struct trklog) * MAXTRK);
913
914 track_disp_all(trl_track_hdr, trl_track_tlr, trl_track_wpt);
915
916 trl_swap(&TRL);
917
918 fill = 0x10000 - 2 * sizeof(struct trklog);
919 buf = xmalloc(fill);
920 if (buf == NULL) {
921 fatal(MYNAME ": Not enough memory\n");
922 }
923 memset(buf, 0xff, fill);
924
925 for (i=0; i<MAXTRK; i+=2) {
926 if (gbfwrite(&(TRL.trklog[i]), sizeof(struct trklog), 2, fout) != 2 ||
927 gbfwrite(buf, fill, 1, fout) != 1) {
928 fatal(MYNAME ": Write error on %s\n", fout->name);
929 }
930 }
931 xfree(buf);
932
933 fill = 0x1000 - sizeof(struct loghdr);
934 buf = xmalloc(fill);
935 if (buf == NULL) {
936 fatal(MYNAME ": Not enough memory\n");
937 }
938 memset(buf, 0xff, fill);
939
940 if (gbfwrite(&(TRL.loghdr), sizeof(struct loghdr), 1, fout) != 1 ||
941 gbfwrite(buf, fill, 1, fout) != 1) {
942 fatal(MYNAME ": Write error on %s\n", fout->name);
943 }
944 xfree(buf);
945 }
946
947 /**************************************************************************/
948
alan_rd_init(const char * fname)949 static void alan_rd_init(const char* fname)
950 {
951 fin = gbfopen(fname, "rb", MYNAME);
952 }
953
alan_rd_deinit(void)954 static void alan_rd_deinit(void)
955 {
956 gbfclose(fin);
957 fin = NULL;
958 }
959
960
alan_wr_init(const char * fname)961 static void alan_wr_init(const char* fname)
962 {
963 fout = gbfopen(fname, "wb", MYNAME);
964 }
965
alan_wr_deinit(void)966 static void alan_wr_deinit(void)
967 {
968 gbfclose(fout);
969 fout = NULL;
970 }
971
972
alan_exit(void)973 static void alan_exit(void)
974 {
975 return;
976 }
977
978 /**************************************************************************/
979
980 ff_vecs_t alanwpr_vecs = {
981 ff_type_file,
982 {
983 (ff_cap)(ff_cap_read | ff_cap_write) /* waypoints */,
984 ff_cap_none /* tracks */,
985 (ff_cap)(ff_cap_read | ff_cap_write) /* routes */
986 },
987 alan_rd_init,
988 alan_wr_init,
989 alan_rd_deinit,
990 alan_wr_deinit,
991 wpr_read,
992 wpr_write,
993 alan_exit,
994 wpr_args,
995 CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
996 /* not fixed, can be changed through command
997 line parameter */
998 };
999
1000 ff_vecs_t alantrl_vecs = {
1001 ff_type_file,
1002 {
1003 ff_cap_none /* waypoints */,
1004 (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */,
1005 ff_cap_none /* routes */
1006 },
1007 alan_rd_init,
1008 alan_wr_init,
1009 alan_rd_deinit,
1010 alan_wr_deinit,
1011 trl_read,
1012 trl_write,
1013 alan_exit,
1014 trl_args,
1015 CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
1016 /* not fixed, can be changed through command
1017 line parameter */
1018 };
1019