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.

garmin_fs.cc 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. Implementation of special data used by Garmin products.
  3. Copyright (C) 2006, 2007, 2008 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "cet_util.h"
  18. #include "garmin_fs.h"
  19. #include "garmin_tables.h"
  20. #include "inifile.h"
  21. #include <QtCore/QXmlStreamWriter>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #define MYNAME "garmin_fs"
  25. garmin_fs_t*
  26. garmin_fs_alloc(const int protocol)
  27. {
  28. garmin_fs_t* result = NULL;
  29. result = (garmin_fs_t*)xcalloc(1, sizeof(*result));
  30. result->fs.type = FS_GMSD;
  31. result->fs.copy = (fs_copy) garmin_fs_copy;
  32. result->fs.destroy = garmin_fs_destroy;
  33. result->fs.convert = garmin_fs_convert;
  34. result->fs.next = NULL;
  35. result->protocol = protocol;
  36. return result;
  37. }
  38. void
  39. garmin_fs_destroy(void* fs)
  40. {
  41. garmin_fs_t* data = (garmin_fs_t*) fs;
  42. if (data != NULL) {
  43. garmin_ilink_t* ilinks;
  44. if (data->addr != NULL) {
  45. xfree(data->addr);
  46. }
  47. if (data->cc != NULL) {
  48. xfree(data->cc);
  49. }
  50. if (data->city != NULL) {
  51. xfree(data->city);
  52. }
  53. if (data->country != NULL) {
  54. xfree(data->country);
  55. }
  56. if (data->cross_road != NULL) {
  57. xfree(data->cross_road);
  58. }
  59. if (data->facility != NULL) {
  60. xfree(data->facility);
  61. }
  62. if (data->phone_nr != NULL) {
  63. xfree(data->phone_nr);
  64. }
  65. if (data->phone_nr2 != NULL) {
  66. xfree(data->phone_nr2);
  67. }
  68. if (data->fax_nr != NULL) {
  69. xfree(data->fax_nr);
  70. }
  71. if (data->email != NULL) {
  72. xfree(data->email);
  73. }
  74. if (data->postal_code != NULL) {
  75. xfree(data->postal_code);
  76. }
  77. if (data->state != NULL) {
  78. xfree(data->state);
  79. }
  80. if ((ilinks = data->ilinks) != NULL) {
  81. ilinks->ref_count--;
  82. if (ilinks->ref_count <= 0) {
  83. while (ilinks != NULL) {
  84. garmin_ilink_t* tmp = ilinks;
  85. ilinks = ilinks->next;
  86. xfree(tmp);
  87. }
  88. }
  89. }
  90. xfree(data);
  91. }
  92. }
  93. void garmin_fs_copy(garmin_fs_t** dest, garmin_fs_t* src)
  94. {
  95. if (src == NULL) {
  96. *dest = NULL;
  97. return;
  98. }
  99. *dest = (garmin_fs_t*) xmalloc(sizeof(*src));
  100. /* do not copy interlinks, only increment the refrence counter */
  101. if (src->ilinks != NULL) {
  102. src->ilinks->ref_count++;
  103. }
  104. memcpy(*dest, src, sizeof(*src));
  105. (*dest)->addr = (src->addr != NULL) ? xstrdup(src->addr) : NULL;
  106. (*dest)->cc = (src->cc != NULL) ? xstrdup(src->cc) : NULL;
  107. (*dest)->city = (src->city != NULL) ? xstrdup(src->city) : NULL;
  108. (*dest)->country = (src->country != NULL) ? xstrdup(src->country) : NULL;
  109. (*dest)->cross_road = (src->cross_road != NULL) ? xstrdup(src->cross_road) : NULL;
  110. (*dest)->facility = (src->facility != NULL) ? xstrdup(src->facility) : NULL;
  111. (*dest)->phone_nr = (src->phone_nr != NULL) ? xstrdup(src->phone_nr) : NULL;
  112. (*dest)->phone_nr2 = (src->phone_nr2 != NULL) ? xstrdup(src->phone_nr2) : NULL;
  113. (*dest)->fax_nr = (src->fax_nr != NULL) ? xstrdup(src->fax_nr) : NULL;
  114. (*dest)->email = (src->email != NULL) ? xstrdup(src->email) : NULL;
  115. (*dest)->postal_code = (src->postal_code != NULL) ? xstrdup(src->postal_code) : NULL;
  116. (*dest)->state = (src->state != NULL) ? xstrdup(src->state) : NULL;
  117. }
  118. void garmin_fs_convert(void* fs)
  119. {
  120. garmin_fs_t* gmsd = (garmin_fs_t*) fs;
  121. if (gmsd->addr) {
  122. gmsd->addr = cet_convert_string(gmsd->addr);
  123. }
  124. if (gmsd->cc) {
  125. gmsd->cc = cet_convert_string(gmsd->cc);
  126. }
  127. if (gmsd->city) {
  128. gmsd->city = cet_convert_string(gmsd->city);
  129. }
  130. if (gmsd->country) {
  131. gmsd->country = cet_convert_string(gmsd->country);
  132. }
  133. if (gmsd->cross_road) {
  134. gmsd->cross_road = cet_convert_string(gmsd->cross_road);
  135. }
  136. if (gmsd->facility) {
  137. gmsd->facility = cet_convert_string(gmsd->facility);
  138. }
  139. if (gmsd->phone_nr) {
  140. gmsd->phone_nr = cet_convert_string(gmsd->phone_nr);
  141. }
  142. if (gmsd->phone_nr2) {
  143. gmsd->phone_nr2 = cet_convert_string(gmsd->phone_nr2);
  144. }
  145. if (gmsd->fax_nr) {
  146. gmsd->fax_nr = cet_convert_string(gmsd->fax_nr);
  147. }
  148. if (gmsd->email) {
  149. gmsd->email = cet_convert_string(gmsd->email);
  150. }
  151. if (gmsd->postal_code) {
  152. gmsd->postal_code = cet_convert_string(gmsd->postal_code);
  153. }
  154. if (gmsd->state) {
  155. gmsd->state = cet_convert_string(gmsd->state);
  156. }
  157. }
  158. /* GPX - out */
  159. void
  160. garmin_fs_xml_fprint(const Waypoint* waypt,
  161. QXmlStreamWriter* writer)
  162. {
  163. const char* phone, *addr;
  164. garmin_fs_t* gmsd = GMSD_FIND(waypt);
  165. if (gmsd == NULL) {
  166. return;
  167. }
  168. /* Find out if there is at least one field set */
  169. addr = GMSD_GET(addr, "");
  170. if (! *addr) {
  171. addr = GMSD_GET(city, "");
  172. }
  173. if (! *addr) {
  174. addr = GMSD_GET(country, "");
  175. }
  176. if (! *addr) {
  177. addr = GMSD_GET(postal_code, "");
  178. }
  179. if (! *addr) {
  180. addr = GMSD_GET(state, "");
  181. }
  182. phone = GMSD_GET(phone_nr, "");
  183. if (*addr || *phone ||
  184. (gmsd->flags.category && gmsd->category) ||
  185. WAYPT_HAS(waypt, depth) ||
  186. WAYPT_HAS(waypt, proximity) ||
  187. WAYPT_HAS(waypt, temperature) ||
  188. gmsd->flags.display) {
  189. writer->writeStartElement("extensions");
  190. writer->writeStartElement("gpxx:WaypointExtension");
  191. writer->writeNamespace("http://www.garmin.com/xmlschemas/GpxExtensions/v3",
  192. "gpxx");
  193. if WAYPT_HAS(waypt, proximity) {
  194. writer->writeTextElement("gpxx:Proximity", QString::number(waypt->proximity, 'f', 6));
  195. }
  196. if WAYPT_HAS(waypt, temperature) {
  197. writer->writeTextElement("gpxx:Temperature", QString::number(waypt->temperature, 'f', 6));
  198. }
  199. if WAYPT_HAS(waypt, depth) {
  200. writer->writeTextElement("gpxx:Depth", QString::number(waypt->depth, 'f', 6));
  201. }
  202. if (gmsd->flags.display) {
  203. const char* cx;
  204. switch (gmsd->display) {
  205. case gt_display_mode_symbol:
  206. cx = "SymbolOnly";
  207. break;
  208. case gt_display_mode_symbol_and_comment:
  209. cx = "SymbolAndDescription";
  210. break;
  211. default:
  212. cx = "SymbolAndName";
  213. break;
  214. }
  215. writer->writeTextElement("gpxx:DisplayMode", cx);
  216. }
  217. if (gmsd->flags.category && gmsd->category) {
  218. int i;
  219. uint16_t cx = gmsd->category;
  220. writer->writeStartElement("gpxx:Categories");
  221. for (i = 0; i < 16; i++) {
  222. if (cx & 1) {
  223. writer->writeTextElement("gpxx:Category", QString("Category %1").arg(i+1));
  224. }
  225. cx = cx >> 1;
  226. }
  227. writer->writeEndElement(); // gpxx:Categories
  228. }
  229. if (*addr) {
  230. char* str;
  231. writer->writeStartElement("gpxx:Address");
  232. if ((str = GMSD_GET(addr, NULL))) {
  233. writer->writeTextElement("gpxx:StreetAddress", str);
  234. }
  235. if ((str = GMSD_GET(city, NULL))) {
  236. writer->writeTextElement("gpxx:City", str);
  237. }
  238. if ((str = GMSD_GET(state, NULL))) {
  239. writer->writeTextElement("gpxx:State", str);
  240. }
  241. if ((str = GMSD_GET(country, NULL))) {
  242. writer->writeTextElement("gpxx:Country", str);
  243. }
  244. if ((str = GMSD_GET(postal_code, NULL))) {
  245. writer->writeTextElement("gpxx:PostalCode", str);
  246. }
  247. writer->writeEndElement(); // /gpxx::Address
  248. }
  249. if (*phone) {
  250. writer->writeTextElement("gpxx:PhoneNumber", phone);
  251. }
  252. writer->writeEndElement(); // /gpxx::WaypointExtension
  253. writer->writeEndElement(); // /extensions.
  254. }
  255. }
  256. void
  257. garmin_fs_xml_convert(const int base_tag, int tag, const QString& Qcdatastr, Waypoint* waypt)
  258. {
  259. garmin_fs_t* gmsd;
  260. // FIXME: eliminate C string copy/use here:
  261. const char *cdatastr = xstrdup(Qcdatastr);
  262. gmsd = GMSD_FIND(waypt);
  263. if (gmsd == NULL) {
  264. gmsd = garmin_fs_alloc(-1);
  265. fs_chain_add(&waypt->fs, (format_specific_data*) gmsd);
  266. }
  267. tag -= base_tag;
  268. /*
  269. tt_garmin_waypt_extension, -> 0
  270. tt_garmin_proximity, -> 1
  271. tt_garmin_temperature,-> 2
  272. tt_garmin_depth, -> 3
  273. tt_garmin_display_mode, -> 4
  274. tt_garmin_categories, -> 5
  275. tt_garmin_category, -> 6
  276. tt_garmin_addr, -> 7
  277. tt_garmin_city, -> 8
  278. tt_garmin_state, -> 9
  279. tt_garmin_country, -> 10
  280. tt_garmin_postal_code, -> 11
  281. tt_garmin_phone_nr, -> 12
  282. */
  283. switch (tag) {
  284. case 1:
  285. if (*cdatastr) {
  286. WAYPT_SET(waypt, proximity, atof(cdatastr));
  287. }
  288. break;
  289. case 2:
  290. if (*cdatastr) {
  291. WAYPT_SET(waypt, temperature, atof(cdatastr));
  292. }
  293. break;
  294. case 3:
  295. if (*cdatastr) {
  296. WAYPT_SET(waypt, depth, atof(cdatastr));
  297. }
  298. break;
  299. case 4:
  300. if (case_ignore_strcmp(cdatastr, "SymbolOnly") == 0) {
  301. GMSD_SET(display, gt_display_mode_symbol);
  302. } else if (case_ignore_strcmp(cdatastr, "SymbolAndDescription") == 0) {
  303. GMSD_SET(display, gt_display_mode_symbol_and_comment);
  304. } else {
  305. GMSD_SET(display, gt_display_mode_symbol_and_name);
  306. }
  307. break;
  308. case 6:
  309. if (! garmin_fs_merge_category(cdatastr, waypt)) {
  310. // There's nothing a user can really do about this (well, they could
  311. // create a gpsbabel.ini that mapped them to garmin category numbers
  312. // but that feature is so obscure and used in so few outputs that
  313. // there's no reason to alarm the user. Just silently disregard
  314. // category names that don't map cleanly.
  315. // warning(MYNAME ": Unable to convert category \"%s\"!\n", cdatastr);
  316. }
  317. break;
  318. case 7:
  319. GMSD_SETSTR(addr, cdatastr);
  320. break;
  321. case 8:
  322. GMSD_SETSTR(city, cdatastr);
  323. break;
  324. case 9:
  325. GMSD_SETSTR(state, cdatastr);
  326. break;
  327. case 10:
  328. GMSD_SETSTR(country, cdatastr);
  329. break;
  330. case 11:
  331. GMSD_SETSTR(postal_code, cdatastr);
  332. break;
  333. case 12:
  334. GMSD_SETSTR(phone_nr, cdatastr);
  335. break;
  336. }
  337. xfree(cdatastr);
  338. }
  339. unsigned char
  340. garmin_fs_convert_category(const char* category_name, uint16_t* category)
  341. {
  342. int i;
  343. int cat = 0;
  344. // Is the name "Category" followed by a number? Use that number.
  345. if ((case_ignore_strncmp(category_name, "Category ", 9) == 0) &&
  346. (1 == sscanf(category_name + 9, "%d", &i)) &&
  347. (i >= 1) && (i <= 16)) {
  348. cat = (1 << --i);
  349. } else if (global_opts.inifile != NULL) {
  350. // Do we have a gpsbabel.ini that maps category names to category #'s?
  351. for (i = 0; i < 16; i++) {
  352. char* c;
  353. char key[3];
  354. snprintf(key, sizeof(key), "%d", i + 1);
  355. c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key);
  356. if ((c != NULL) && (case_ignore_strcmp(c, category_name) == 0)) {
  357. cat = (1 << i);
  358. break;
  359. }
  360. }
  361. }
  362. if (cat == 0) {
  363. return 0;
  364. } else {
  365. *category = cat;
  366. return 1;
  367. }
  368. }
  369. unsigned char
  370. garmin_fs_merge_category(const char* category_name, Waypoint* waypt)
  371. {
  372. uint16_t cat;
  373. garmin_fs_t* gmsd;
  374. // Attempt to get a textual category name to a category number.
  375. if (!garmin_fs_convert_category(category_name, &cat)) {
  376. return 0;
  377. }
  378. gmsd = GMSD_FIND(waypt);
  379. cat = cat | (GMSD_GET(category, 0));
  380. if (gmsd == NULL) {
  381. gmsd = garmin_fs_alloc(-1);
  382. fs_chain_add(&waypt->fs, (format_specific_data*) gmsd);
  383. }
  384. GMSD_SET(category, cat);
  385. return 1;
  386. }
  387. void
  388. garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid)
  389. {
  390. garmin_fs_t* gmsd = NULL;
  391. gmsd = garmin_fs_alloc(protoid);
  392. fs_chain_add(&wpt->fs, (format_specific_data*) gmsd);
  393. /* nothing happens until gmsd is allocated some lines above */
  394. /* !!! class needs protocol specific conversion !!! (ToDo)
  395. GMSD_SET(wpt_class, way[i]->wpt_class);
  396. */
  397. /* flagged data fields */
  398. GMSD_SET(display, gt_switch_display_mode_value(way->dspl, gps_waypt_type, 1));
  399. if (way->category != 0) {
  400. GMSD_SET(category, way->category);
  401. }
  402. if (way->dst < 1.0e25f) {
  403. WAYPT_SET(wpt, proximity, way->dst);
  404. }
  405. if (way->temperature_populated) {
  406. WAYPT_SET(wpt, temperature, way->temperature);
  407. }
  408. if (way->dpth < 1.0e25f) {
  409. WAYPT_SET(wpt, depth, way->dpth);
  410. }
  411. GMSD_SETNSTR(cc, way->cc, sizeof(way->cc));
  412. GMSD_SETNSTR(state, way->state, sizeof(way->state));
  413. GMSD_SETSTR(city, way->city);
  414. GMSD_SETSTR(facility, way->facility);
  415. GMSD_SETSTR(cross_road, way->cross_road);
  416. GMSD_SETSTR(addr, way->addr);
  417. }
  418. void
  419. garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, const int protoid)
  420. {
  421. garmin_fs_t* gmsd = GMSD_FIND(wpt);
  422. (void)protoid; // unused for now.
  423. if (gmsd == NULL) {
  424. return;
  425. }
  426. /* ToDo: protocol specific conversion of class
  427. way[i]->wpt_class = GMSD_GET(wpt_class, way[i]->wpt_class);
  428. */
  429. way->dspl = gt_switch_display_mode_value(
  430. GMSD_GET(display, way->dspl), gps_waypt_type, 0);
  431. way->category = GMSD_GET(category, way->category);
  432. way->dpth = WAYPT_GET(wpt, depth, way->dpth);
  433. way->dst = WAYPT_GET(wpt, proximity, way->dpth);
  434. way->temperature = WAYPT_GET(wpt, temperature, way->temperature);
  435. GMSD_GETNSTR(cc, way->cc, sizeof(way->cc));
  436. GMSD_GETNSTR(city, way->city, sizeof(way->city));
  437. GMSD_GETNSTR(state, way->state, sizeof(way->state));
  438. GMSD_GETNSTR(facility, way->facility, sizeof(way->facility));
  439. GMSD_GETNSTR(cross_road, way->cross_road, sizeof(way->cross_road));
  440. GMSD_GETNSTR(addr, way->addr, sizeof(way->addr));
  441. }