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