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