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.

tef_xml.cc 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. Support for XML based "TourExchangeFormat",
  3. found in Map & Guide Motorrad-Tourenplaner 2005/06
  4. Copyright (C) 2005 Olaf Klein, o.b.klein@gpsbabel.org
  5. Based on kml.c, Keyhole "kml" format.
  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 <QtCore/QXmlStreamAttributes>
  20. #include "defs.h"
  21. #include "xmlgeneric.h"
  22. static Waypoint* wpt_tmp;
  23. static int item_count;
  24. static int waypoints;
  25. static double version;
  26. static route_head* route = NULL;
  27. static char* routevia = NULL;
  28. static arglist_t tef_xml_args[] = {
  29. {
  30. "routevia", &routevia, "Include only via stations in route",
  31. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  32. },
  33. ARG_TERMINATOR
  34. };
  35. #define MYNAME "TourExchangeFormat"
  36. static xg_callback tef_start, tef_header, tef_list_start, tef_list_end;
  37. static xg_callback tef_item_start, tef_point, tef_item_end;
  38. static
  39. xg_tag_mapping tef_xml_map[] = {
  40. { tef_start, cb_start, "/TEF" },
  41. { tef_header, cb_start, "/TEF/Header" },
  42. { tef_list_start, cb_start, "/TEF/WaypointList" },
  43. { tef_item_start, cb_start, "/TEF/WaypointList/Item" },
  44. { tef_point, cb_start, "/TEF/WaypointList/Item/Point" },
  45. { tef_item_end, cb_end, "/TEF/WaypointList/Item" },
  46. { tef_list_end, cb_end, "/TEF/WaypointList" },
  47. { NULL, (xg_cb_type)0, NULL }
  48. };
  49. /*
  50. * tef_start: check for comment "TourExchangeFormat"
  51. */
  52. void
  53. tef_start(xg_string args, const QXmlStreamAttributes* attrv)
  54. {
  55. bool valid = false;
  56. foreach(QXmlStreamAttribute attr, *attrv) {
  57. if (attr.name().compare("Comment", Qt::CaseInsensitive) == 0) {
  58. if (attr.value().compare("TourExchangeFormat", Qt::CaseInsensitive) == 0) {
  59. valid = true;
  60. }
  61. } else if (attr.name().compare("Version", Qt::CaseInsensitive) == 0) {
  62. version = attr.value().toString().toDouble();
  63. }
  64. }
  65. if (!valid) {
  66. fatal(MYNAME ": Error in source file.\n");
  67. }
  68. }
  69. /*
  70. * tef_header: "Name" > Route name, "Software" > Route descr.
  71. */
  72. static void
  73. tef_header(xg_string args, const QXmlStreamAttributes* attrv)
  74. {
  75. route = route_head_alloc();
  76. foreach(QXmlStreamAttribute attr, *attrv) {
  77. if (attr.name().compare("Name", Qt::CaseInsensitive) == 0) {
  78. route->rte_name = attr.value().toString().trimmed();
  79. } else if (attr.name().compare("Software", Qt::CaseInsensitive) == 0) {
  80. route->rte_desc = attr.value().toString().trimmed();
  81. }
  82. }
  83. route_add_head(route);
  84. }
  85. static void
  86. tef_list_start(xg_string args, const QXmlStreamAttributes* attrv)
  87. {
  88. if (attrv->hasAttribute("ItemCount")) {
  89. item_count = attrv->value("ItemCount").toString().toUInt();
  90. }
  91. }
  92. #if OMG
  93. TODO: this whole horrible mess is not covered at all in the test suite,
  94. so just stub it all out until someone cares. (TEF is rarely used from
  95. what we can tell.)
  96. /* in "TourExchangeFormat" the following can happen:
  97. *
  98. * SegDescription="L34\Wittlicher Strasse"
  99. * PointDescription="Wittlicher Strasse ( "
  100. *
  101. * fix_notes tries to create a new PointDescription, which
  102. * should be "Wittlicher Strasse (L34)" for the example above
  103. */
  104. // FIXME: the calling convention here is screwy. notes is an input AND
  105. // output argument and may be modified.
  106. static char*
  107. fix_notes(const char* name, char* notes)
  108. {
  109. const char* cleft, *cright, *cback;
  110. char* ctmp;
  111. if ((! name) || (! notes)) {
  112. return notes;
  113. }
  114. /* do we have a BACKSLASH in shortname ? */
  115. cback = strchr(name, '\\');
  116. if ((! cback) || (cback == name)) {
  117. return notes;
  118. }
  119. /* do we have left, but no right parenthesis in notes ? */
  120. if (!(cleft = strchr(notes, '('))) {
  121. return notes;
  122. }
  123. cright = strchr(notes, ')');
  124. if (cright && (cright > cleft)) {
  125. return notes;
  126. }
  127. /* now contruct the new name */
  128. ctmp = lrtrim(xstrndup(notes, cleft - notes));
  129. xfree(notes);
  130. xasprintf(&notes, "%s (%*.*s)", ctmp, (int)(cback - name), (int)(cback - name), name);
  131. xfree(ctmp);
  132. return notes;
  133. }
  134. static char*
  135. Xfix_notes(const QString& name, const QString& notes)
  136. {
  137. char* cname = xstrdup(name);
  138. char* cnotes = xstrdup(notes);
  139. char *r = fix_notes(cname, cnotes);
  140. xfree(cname);
  141. // WTH? fix_notes() modifies the note string...and
  142. // may reallocate it.
  143. // xfree(cnotes);
  144. return r;
  145. }
  146. #else
  147. static QString
  148. fix_notes(const QString& name, const QString& notes){
  149. return notes;
  150. }
  151. #endif
  152. static void
  153. waypoint_final()
  154. {
  155. int via;
  156. if (wpt_tmp == NULL) {
  157. return;
  158. }
  159. via = wpt_tmp->wpt_flags.fmt_use ;
  160. wpt_tmp->wpt_flags.fmt_use = 0;
  161. if (version < 2) { /* keep the old behaviour */
  162. wpt_tmp->notes = wpt_tmp->description;
  163. wpt_tmp->description = QString();
  164. }
  165. wpt_tmp->notes = fix_notes(wpt_tmp->shortname, wpt_tmp->notes);
  166. if (via != 0) {
  167. waypt_add(wpt_tmp);
  168. }
  169. if (route != NULL) {
  170. if ((via != 0) || (routevia == NULL)) {
  171. Waypoint* wpt = new Waypoint(*wpt_tmp);
  172. route_add_wpt(route, wpt);
  173. }
  174. }
  175. if (via == 0) {
  176. delete wpt_tmp;
  177. }
  178. wpt_tmp = NULL;
  179. }
  180. static void
  181. tef_item_end(xg_string args, const QXmlStreamAttributes*)
  182. {
  183. waypoint_final();
  184. }
  185. static void
  186. tef_list_end(xg_string args, const QXmlStreamAttributes*)
  187. {
  188. waypoint_final();
  189. if (waypoints != item_count)
  190. fatal(MYNAME ": waypoint count differs to internal \"ItemCount\"! (%d to %d)\n",
  191. waypoints, item_count);
  192. }
  193. static void
  194. tef_item_start(xg_string args, const QXmlStreamAttributes* attrv)
  195. {
  196. waypoints++;
  197. wpt_tmp = new Waypoint;
  198. if ((waypoints == 1) || (waypoints == item_count)) {
  199. wpt_tmp->wpt_flags.fmt_use ++;
  200. }
  201. foreach(QXmlStreamAttribute attr, *attrv) {
  202. QString attrstr = attr.value().toString();
  203. QByteArray attrtext = attrstr.toUtf8();
  204. if (attr.name().compare("SegDescription", Qt::CaseInsensitive) == 0) {
  205. wpt_tmp->shortname = attrstr.trimmed();
  206. } else if (attr.name().compare("PointDescription", Qt::CaseInsensitive) == 0) {
  207. wpt_tmp->description = attrstr.trimmed();
  208. } else if (attr.name().compare("ViaStation", Qt::CaseInsensitive) == 0 &&
  209. attr.value().compare("true", Qt::CaseInsensitive) == 0) {
  210. wpt_tmp->wpt_flags.fmt_use = 1; /* only a flag */
  211. /* new in TEF V2 */
  212. } else if (attr.name().compare("Instruction", Qt::CaseInsensitive) == 0) {
  213. wpt_tmp->description = attrstr.trimmed();
  214. } else if (attr.name().compare("Altitude", Qt::CaseInsensitive) == 0) {
  215. wpt_tmp->altitude = attrstr.toDouble();
  216. } else if (attr.name().compare("TimeStamp", Qt::CaseInsensitive) == 0) {
  217. /* nothing for the moment */
  218. }
  219. }
  220. }
  221. static double
  222. tef_read_comma_float(const QStringRef& value)
  223. {
  224. QString svalue = value.toString();
  225. int cidx;
  226. cidx = svalue.indexOf(',');
  227. if (cidx == -1) {
  228. return svalue.toDouble();
  229. }
  230. QString fixed = svalue.replace(cidx, 1, '.');
  231. return fixed.toDouble();
  232. }
  233. static void
  234. tef_point(xg_string args, const QXmlStreamAttributes* attrv)
  235. {
  236. if (!wpt_tmp) {
  237. return;
  238. }
  239. if (attrv->hasAttribute("y")) {
  240. wpt_tmp->latitude = tef_read_comma_float(attrv->value("y"));
  241. }
  242. if (attrv->hasAttribute("x")) {
  243. wpt_tmp->longitude = tef_read_comma_float(attrv->value("x"));
  244. }
  245. }
  246. static void
  247. tef_xml_rd_init(const QString& fname)
  248. {
  249. wpt_tmp = NULL;
  250. waypoints = 0;
  251. item_count = -1;
  252. version = 1.5;
  253. xml_init(fname, tef_xml_map, NULL);
  254. }
  255. static void
  256. tef_xml_read(void)
  257. {
  258. xml_read();
  259. }
  260. static void
  261. tef_xml_rd_deinit(void)
  262. {
  263. xml_deinit();
  264. }
  265. ff_vecs_t tef_xml_vecs = {
  266. ff_type_file,
  267. { ff_cap_none, ff_cap_none, ff_cap_read },
  268. tef_xml_rd_init,
  269. NULL,
  270. tef_xml_rd_deinit,
  271. NULL,
  272. tef_xml_read,
  273. NULL,
  274. NULL,
  275. tef_xml_args,
  276. CET_CHARSET_UTF8, 1
  277. };