You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1032 lines
25KB

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