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.

603 lines
13KB

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