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.

gdb.cc 48KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896
  1. /*
  2. Garmin GPS Database Reader/Writer
  3. Copyright (C) 2005-2008 Olaf Klein, o.b.klein@gpsbabel.org
  4. Mainly based on mapsource.c,
  5. Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  17. */
  18. #include "defs.h"
  19. #include "cet_util.h"
  20. #include "csv_util.h"
  21. #include "garmin_fs.h"
  22. #include "garmin_tables.h"
  23. #include "grtcirc.h"
  24. #include "jeeps/gpsmath.h"
  25. #include <cmath>
  26. #include <stdlib.h>
  27. #define MYNAME "gdb"
  28. #define GDB_VER_1 1
  29. #define GDB_VER_2 2
  30. #define GDB_VER_3 3
  31. #define GDB_VER_UTF8 GDB_VER_3
  32. #define GDB_VER_MIN GDB_VER_1
  33. #define GDB_VER_MAX GDB_VER_3
  34. #define GDB_DEF_CLASS gt_waypt_class_user_waypoint
  35. #define GDB_DEF_HIDDEN_CLASS gt_waypt_class_map_point
  36. #define GDB_DEF_ICON 18
  37. #define GDB_NAME_BUFFERLEN 1024
  38. #define GDB_DBG_WPT 1
  39. #define GDB_DBG_RTE 2
  40. #define GDB_DBG_TRK 4
  41. #define GDB_DBG_WPTe 8
  42. #define GDB_DBG_RTEe 16
  43. #define GDB_DBG_TRKe 32
  44. #define GDB_DEBUG (GDB_DBG_WPTe) /* | GDB_DBG_RTE) */
  45. #undef GDB_DEBUG
  46. // #define GDB_DEBUG 0xff
  47. #define DBG(a,b) if ((GDB_DEBUG & (a)) && (b))
  48. /*******************************************************************************/
  49. /* static char gdb_release[] = "$Revision: 1.74 $"; */
  50. static char gdb_release_date[] = "$Date: 2011-04-14 01:30:01 $";
  51. static gbfile* fin, *fout, *ftmp;
  52. static int gdb_ver, gdb_category, gdb_via, gdb_roadbook;
  53. static queue wayptq_in, wayptq_out, wayptq_in_hidden;
  54. static short_handle short_h;
  55. static char* gdb_opt_category;
  56. static char* gdb_opt_ver;
  57. static char* gdb_opt_via;
  58. static char* gdb_opt_roadbook;
  59. static char* gdb_opt_bitcategory;
  60. static int waypt_flag;
  61. static int route_flag;
  62. static int waypt_ct; /* informational: total number of waypoints in/out */
  63. static int waypth_ct; /* informational: total number of hidden waypoints in/out */
  64. static int rtept_ct; /* informational: total number of route points in/out */
  65. static int trkpt_ct; /* informational: total number of track points in/out */
  66. static int rte_ct; /* informational: total number of routes in/out */
  67. static int trk_ct; /* informational: total number of tracks in/out */
  68. /*******************************************************************************/
  69. #define ELEMENTS(a) a->rte_waypt_ct
  70. #define NOT_EMPTY(a) (a && *a)
  71. static void
  72. gdb_flush_waypt_queue(queue* Q)
  73. {
  74. queue* elem, *tmp;
  75. QUEUE_FOR_EACH(Q, elem, tmp) {
  76. Waypoint* wpt = (Waypoint*)elem;
  77. dequeue(elem);
  78. if (wpt->extra_data) {
  79. #if NEW_STRINGS
  80. // FIXME
  81. // wpt->extra_data may be holding a pointer to a QString, courtesy
  82. // the grossness at the end of write_waypt_cb(). If that leaks,
  83. // (and I think it will) find some way to do the approximate equivalent
  84. // of:
  85. // delete static_cast<QString*>(wpt->extra_data);
  86. #else
  87. xfree(wpt->extra_data);
  88. #endif
  89. }
  90. delete wpt;
  91. }
  92. }
  93. #if GDB_DEBUG
  94. static void
  95. disp_summary(const gbfile* f)
  96. {
  97. int i, len;
  98. len = strlen(f->name);
  99. warning(MYNAME ": =====================");
  100. for (i = 0; i < len; i++) {
  101. warning("=");
  102. }
  103. warning("\n" MYNAME ": %s summary for \"%s\"\n",
  104. (f->mode == 'r') ? "Reader" : "Writer", f->name);
  105. warning(MYNAME ": ---------------------");
  106. for (i = 0; i < len; i++) {
  107. warning("-");
  108. }
  109. warning("\n" MYNAME ": %d waypoint(s)\n", waypt_ct - waypth_ct);
  110. warning(MYNAME ": %d hidden waypoint(s)\n", waypth_ct);
  111. warning(MYNAME ": %d route(s) with total %d point(s)\n", rte_ct, rtept_ct);
  112. warning(MYNAME ": %d track(s) with total %d point(s)\n", trk_ct, trkpt_ct);
  113. warning(MYNAME ": ---------------------");
  114. for (i = 0; i < len; i++) {
  115. warning("-");
  116. }
  117. warning("\n");
  118. }
  119. #else
  120. #define disp_summary(a)
  121. #endif
  122. /*******************************************************************************/
  123. /* TOOLS AND MACROS FOR THE READER */
  124. /*-----------------------------------------------------------------------------*/
  125. #define FREAD_C gbfgetc(fin)
  126. #define FREAD(a,b) gbfread(a,(b),1,fin)
  127. #define FREAD_i32 gbfgetint32(fin)
  128. #define FREAD_i16 gbfgetint16(fin)
  129. #define FREAD_DBL gbfgetdbl(fin)
  130. #define FREAD_LATLON GPS_Math_Semi_To_Deg(gbfgetint32(fin))
  131. #define FREAD_STR(a) gdb_fread_str(a,sizeof(a),fin)
  132. // This is all very messy. Some versions of GDB store strings as
  133. // 8859-1 strings and others as UTF8. This wrapper tries to hide
  134. // all that while (while keeping the character sets correct) and
  135. // not pushing that decision down into gbfread. This module is
  136. // still pretty messy and the points as to which fields are encode
  137. // which ways in which versions are not at all clear, leaing to
  138. // encoding issues on read and leaks because of teh differences
  139. // in calling conventions on who owns/destroys the result.
  140. //#define FREAD_CSTR \
  141. // (gdb_ver >= GDB_VER_UTF8) ? QString::fromUtf8(gdb_fread_cstr(fin)) : \
  142. // QString::fromLatin1(gdb_fread_cstr(fin))
  143. #define FREAD_CSTR_AS_QSTR gbfgetcstr(fin)
  144. static char* gdb_fread_cstr(gbfile* fin);
  145. QString fread_cstr()
  146. {
  147. QString rv;
  148. char* s = gdb_fread_cstr(fin);
  149. if (gdb_ver >= GDB_VER_UTF8) {
  150. rv = QString::fromUtf8(s);
  151. } else {
  152. rv = QString::fromLatin1(s);
  153. }
  154. xfree(s);
  155. return rv;
  156. }
  157. #if GDB_DEBUG
  158. static char*
  159. nice(const char* str)
  160. {
  161. char* res, *env;
  162. cet_cs_vec_t* vec;
  163. if (!(str && *str)) {
  164. return "";
  165. }
  166. env = getenv("LANG");
  167. if (env == NULL) {
  168. return (char*)str;
  169. }
  170. if ((res = strchr(env, '.'))) {
  171. env = ++res;
  172. }
  173. vec = cet_find_cs_by_name(env);
  174. if ((vec != NULL) && (vec != global_opts.charset)) {
  175. static char buf[128];
  176. res = cet_str_any_to_any(str, global_opts.charset, vec);
  177. strncpy(buf, res, sizeof(buf));
  178. xfree(res);
  179. return buf;
  180. } else {
  181. return (char*)str;
  182. }
  183. }
  184. #endif
  185. static char*
  186. gdb_fread_cstr(gbfile* fin)
  187. {
  188. char* result = gbfgetcstr_old(fin);
  189. if (result && (*result == '\0')) {
  190. xfree(result);
  191. result = NULL;
  192. }
  193. return result;
  194. }
  195. static int
  196. gdb_fread_str(char* buf, int size, gbfile* fin)
  197. {
  198. char c;
  199. int res = 0;
  200. while (size--) {
  201. gbfread(&c, 1, 1, fin);
  202. buf[res] = c;
  203. if (c == '\0') {
  204. return res;
  205. }
  206. res++;
  207. }
  208. buf[res] = '\0';
  209. return res;
  210. }
  211. static QString
  212. gdb_fread_strlist(void)
  213. {
  214. // char* res = NULL;
  215. QString res;
  216. int count;
  217. count = FREAD_i32;
  218. while (count > 0) {
  219. QString str = fread_cstr();
  220. if (!str.isEmpty()) {
  221. res = str;
  222. }
  223. count--;
  224. }
  225. QString qres = res;
  226. // xfree(res);
  227. return qres;
  228. }
  229. static Waypoint*
  230. gdb_find_wayptq(const queue* Q, const Waypoint* wpt, const char exact)
  231. {
  232. queue* elem, *tmp;
  233. QString name = wpt->shortname;
  234. QUEUE_FOR_EACH(Q, elem, tmp) {
  235. Waypoint* tmp = (Waypoint*)elem;
  236. if (name.compare(tmp->shortname,Qt::CaseInsensitive) == 0) {
  237. if (! exact) {
  238. return tmp;
  239. }
  240. if ((tmp->latitude == wpt->latitude) &&
  241. (tmp->longitude == wpt->longitude)) {
  242. return tmp;
  243. }
  244. }
  245. }
  246. return NULL;
  247. }
  248. static Waypoint*
  249. gdb_reader_find_waypt(const Waypoint* wpt, const char exact)
  250. {
  251. Waypoint* res;
  252. res = gdb_find_wayptq(&wayptq_in, wpt, exact);
  253. if (res == NULL) {
  254. res = gdb_find_wayptq(&wayptq_in_hidden, wpt, exact);
  255. }
  256. return res;
  257. }
  258. static Waypoint*
  259. gdb_add_route_waypt(route_head* rte, Waypoint* ref, const int wpt_class)
  260. {
  261. Waypoint* tmp, *res;
  262. int turn_point;
  263. tmp = gdb_reader_find_waypt(ref, 1);
  264. if (tmp == NULL) {
  265. double dist;
  266. tmp = find_waypt_by_name(ref->shortname);
  267. if (tmp == NULL) {
  268. route_add_wpt(rte, ref);
  269. return ref;
  270. }
  271. /* At this point we have found a waypoint with same name,
  272. but probably from another data stream. Check coordinates!
  273. */
  274. dist = radtometers(gcdist(
  275. RAD(ref->latitude), RAD(ref->longitude),
  276. RAD(tmp->latitude), RAD(tmp->longitude)));
  277. if (fabs(dist) > 100) {
  278. warning(MYNAME ": Route point mismatch!\n");
  279. warning(MYNAME ": \"%s\" from waypoints differs to \"%s\"\n",
  280. qPrintable(tmp->shortname), qPrintable(ref->shortname));
  281. fatal(MYNAME ": from route table by more than %0.1f meters!\n",
  282. dist);
  283. }
  284. }
  285. res = NULL;
  286. turn_point = (gdb_roadbook && (wpt_class > gt_waypt_class_map_point) && !tmp->description.isEmpty());
  287. if (turn_point || (gdb_via == 0) || (wpt_class < gt_waypt_class_map_point)) {
  288. res = new Waypoint(*tmp);
  289. route_add_wpt(rte, res);
  290. }
  291. delete ref;
  292. return res;
  293. }
  294. /*******************************************************************************/
  295. /* TOOLS AND MACROS FOR THE WRITER */
  296. /*-----------------------------------------------------------------------------*/
  297. void FWRITE_CSTR(QString a) {
  298. if (a.isEmpty()) {
  299. gbfputc(0, fout);
  300. return;
  301. }
  302. if (gdb_ver >= GDB_VER_UTF8) {
  303. gbfputcstr(a.toUtf8().constData(), fout);
  304. } else {
  305. gbfputcstr(a.toLatin1().constData(), fout);
  306. }
  307. }
  308. #define FWRITE_i16(a) gbfputint16((a),fout)
  309. #define FWRITE_i32(a) gbfputint32((a),fout)
  310. #define FWRITE(a, b) gbfwrite(a,(b),1,fout)
  311. #define FWRITE_C(a) gbfputc((a),fout)
  312. #define FWRITE_DBL(a,b) gdb_write_dbl((a),(b))
  313. #define FWRITE_TIME(a) gdb_write_time((a))
  314. #define FWRITE_CSTR_LIST(a) gdb_write_cstr_list((a))
  315. #define FWRITE_LATLON(a) gbfputint32(GPS_Math_Deg_To_Semi((a)),fout)
  316. static void
  317. gdb_write_cstr_list(const char* str)
  318. {
  319. if NOT_EMPTY(str) {
  320. gbfputint32(1, fout);
  321. gbfputcstr(str, fout);
  322. } else {
  323. gbfputint32(0, fout);
  324. }
  325. }
  326. static void
  327. gdb_write_cstr_list(const QString& str)
  328. {
  329. return gdb_write_cstr_list(CSTRc(str));
  330. }
  331. static void
  332. gdb_write_dbl(const double value, const double def)
  333. {
  334. if (value == def) {
  335. gbfputc(0, fout);
  336. } else {
  337. gbfputc(1, fout);
  338. gbfputdbl(value, fout);
  339. }
  340. }
  341. static void
  342. gdb_write_time(const int time)
  343. {
  344. if (time > 0) {
  345. gbfputc(1, fout);
  346. gbfputint32(time, fout);
  347. } else {
  348. gbfputc(0, fout);
  349. }
  350. }
  351. /*******************************************************************************/
  352. /* GDB "Garmin Database" READER CODE */
  353. /*-----------------------------------------------------------------------------*/
  354. static void
  355. read_file_header(void)
  356. {
  357. char buf[128];
  358. int i, reclen;
  359. /*
  360. We are beginning with a simple binary read.
  361. */
  362. FREAD(buf, 6);
  363. /*
  364. A "gbfgetcstr" (FREAD_CSTR) works too, but if we get a wrong file as input,
  365. the file validation my be comes too late. For example a XML base file normally
  366. has no binary zeros inside and produce, if big enought, a buffer overflow.
  367. The following message "local buffer overflow detected..." could be
  368. misinterpreted.
  369. */
  370. is_fatal(strcmp(buf, "MsRcf") != 0, MYNAME ": Invalid file \"%s\"!", fin->name);
  371. reclen = FREAD_i32;
  372. i = FREAD_STR(buf);
  373. is_fatal(buf[0] != 'D', MYNAME ": Invalid file \"%s\"!", fin->name);
  374. gdb_ver = buf[1] - 'k' + 1;
  375. is_fatal((gdb_ver < GDB_VER_MIN) || (gdb_ver > GDB_VER_MAX),
  376. MYNAME ": Unknown or/and unsupported GDB version (%d.0)!", gdb_ver);
  377. if (global_opts.verbose_status > 0) {
  378. printf(MYNAME ": Reading Garmin GPS Database version %d.0\n", gdb_ver);
  379. }
  380. reclen = FREAD_i32;
  381. i = FREAD(buf, reclen + 1);
  382. if (global_opts.verbose_status > 0) {
  383. const char* name = buf+2;
  384. if (strstr(name, "SQA") == 0) {
  385. name = "MapSource";
  386. } else if (strstr(name, "neaderhi") == 0) {
  387. name = "MapSource BETA";
  388. }
  389. warning(MYNAME ": File created with \"%s\"\n", name);
  390. }
  391. i = FREAD_STR(buf);
  392. is_fatal(!(((i == 9) && (strcmp(buf, "MapSource") == 0)) || ((i == 8) && (strcmp(buf, "BaseCamp") == 0))), MYNAME ": Not a recognized signature in header");
  393. }
  394. /*-----------------------------------------------------------------------------*/
  395. static Waypoint*
  396. read_waypoint(gt_waypt_classes_e* waypt_class_out)
  397. {
  398. char buf[128]; /* used for temporary stuff */
  399. int display, icon;
  400. gt_waypt_classes_e wpt_class;
  401. int i;
  402. Waypoint* res;
  403. garmin_fs_t* gmsd;
  404. char* str;
  405. char* bufp = buf;
  406. #ifdef GMSD_EXPERIMENTAL
  407. char subclass[22];
  408. #endif
  409. #if GDB_DEBUG
  410. char* sn;
  411. #endif
  412. waypt_ct++;
  413. res = new Waypoint;
  414. gmsd = garmin_fs_alloc(-1);
  415. fs_chain_add(&res->fs, (format_specific_data*) gmsd);
  416. res->shortname = fread_cstr();
  417. #if GDB_DEBUG
  418. sn = xstrdup(nice(res->shortname));
  419. #endif
  420. wpt_class = (gt_waypt_classes_e) FREAD_i32;
  421. GMSD_SET(wpt_class, wpt_class);
  422. if (wpt_class != 0) {
  423. waypth_ct++;
  424. }
  425. FREAD_STR(buf); /* Country code */
  426. GMSD_SETSTR(cc, bufp);
  427. #ifdef GMSD_EXPERIMENTAL
  428. FREAD(subclass, sizeof(subclass));
  429. if (gmsd && (wpt_class >= gt_waypt_class_map_point)) {
  430. memcpy(gmsd->subclass, subclass, sizeof(gmsd->subclass));
  431. gmsd->flags.subclass = 1;
  432. }
  433. #else
  434. FREAD(buf, 22);
  435. #endif
  436. res->latitude = FREAD_LATLON;
  437. res->longitude = FREAD_LATLON;
  438. if (FREAD_C == 1) {
  439. double alt = FREAD_DBL;
  440. if (alt < 1.0e24) {
  441. res->altitude = alt;
  442. #if GDB_DEBUG
  443. DBG(GDB_DBG_WPTe, 1)
  444. printf(MYNAME "-wpt \"%s\" (%d): Altitude = %.1f\n",
  445. sn, wpt_class, alt);
  446. #endif
  447. }
  448. }
  449. #if GDB_DEBUG
  450. DBG(GDB_DBG_WPT, 1)
  451. printf(MYNAME "-wpt \"%s\": coordinates = %c%0.6f %c%0.6f\n",
  452. sn,
  453. res->latitude < 0 ? 'S' : 'N', res->latitude,
  454. res->longitude < 0 ? 'W' : 'E', res->longitude);
  455. #endif
  456. res->notes = fread_cstr();
  457. #if GDB_DEBUG
  458. DBG(GDB_DBG_WPTe, res->notes) {
  459. char* str = gstrsub(res->notes, "\r\n", ", ");
  460. printf(MYNAME "-wpt \"%s\" (%d): notes = %s\n",
  461. sn, wpt_class, nice(str));
  462. xfree(str);
  463. }
  464. #endif
  465. if (FREAD_C == 1) {
  466. WAYPT_SET(res, proximity, FREAD_DBL);
  467. #if GDB_DEBUG
  468. DBG(GDB_DBG_WPTe, 1)
  469. printf(MYNAME "-wpt \"%s\" (%d): Proximity = %.1f\n",
  470. sn, wpt_class, res->proximity / 1000);
  471. #endif
  472. }
  473. i = FREAD_i32;
  474. #if GDB_DEBUG
  475. DBG(GDB_DBG_WPTe, i)
  476. printf(MYNAME "-wpt \"%s\" (%d): display = %d\n",
  477. sn, wpt_class, i);
  478. #endif
  479. switch (i) { /* display value */
  480. case gt_gdb_display_mode_symbol:
  481. display = gt_display_mode_symbol;
  482. break;
  483. case gt_gdb_display_mode_symbol_and_comment:
  484. display = gt_display_mode_symbol_and_comment;
  485. break;
  486. default:
  487. display = gt_display_mode_symbol_and_name;
  488. break;
  489. }
  490. GMSD_SET(display, display);
  491. FREAD_i32; /* color !not implemented! */
  492. icon = FREAD_i32;
  493. GMSD_SET(icon, icon); /* icon */
  494. FREAD_STR(buf); /* city */
  495. GMSD_SETSTR(city, bufp);
  496. FREAD_STR(buf); /* state */
  497. GMSD_SETSTR(state, bufp);
  498. FREAD_STR(buf); /* facility */
  499. GMSD_SETSTR(facility, bufp);
  500. FREAD(buf, 1);
  501. if (FREAD_C == 1) {
  502. WAYPT_SET(res, depth, FREAD_DBL);
  503. #if GDB_DEBUG
  504. DBG(GDB_DBG_WPTe, 1)
  505. printf(MYNAME "-wpt \"%s\" (%d): Depth = %.1f\n",
  506. sn, wpt_class, res->depth);
  507. #endif
  508. }
  509. /* VERSION DEPENDENT CODE */
  510. if (gdb_ver <= GDB_VER_2) {
  511. FREAD(buf, 2); /* ?????????????????????????????????? */
  512. waypt_flag = FREAD_C;
  513. if (waypt_flag == 0) {
  514. FREAD(buf, 3);
  515. } else {
  516. FREAD(buf, 2);
  517. }
  518. QString junk = FREAD_CSTR_AS_QSTR; /* undocumented & unused string */
  519. #if GDB_DEBUG
  520. DBG(GDB_DBG_WPTe, temp)
  521. printf(MYNAME "-wpt \"%s\" (%d): Unknown string = %s\n",
  522. sn, wpt_class, nice(temp));
  523. #endif
  524. QString linky = FREAD_CSTR_AS_QSTR;
  525. UrlLink l(linky);
  526. if (!linky.isEmpty()) {
  527. res->AddUrlLink(l);
  528. }
  529. if (wpt_class != 0) {
  530. res->description = l.url_;
  531. }
  532. } else { // if (gdb_ver >= GDB_VER_3)
  533. int i, url_ct;
  534. waypt_flag = 0;
  535. FREAD_STR(buf); /* street address */
  536. GMSD_SETSTR(addr, bufp);
  537. FREAD(buf, 5); /* instruction depended */
  538. res->description = FREAD_CSTR_AS_QSTR; /* instruction */
  539. url_ct = FREAD_i32;
  540. for (i = url_ct; (i); i--) {
  541. QString str = FREAD_CSTR_AS_QSTR;
  542. if (!str.isEmpty()) {
  543. waypt_add_url(res, str, NULL);
  544. #if GDB_DEBUG
  545. DBG(GDB_DBG_WPTe, 1)
  546. printf(MYNAME "-wpt \"%s\" (%d): url(%d) = %s\n",
  547. sn, wpt_class, url_ct - i, qPrintable(str));
  548. #endif
  549. }
  550. }
  551. }
  552. #if GDB_DEBUG
  553. DBG(GDB_DBG_WPTe, res->description)
  554. printf(MYNAME "-wpt \"%s\" (%d): description = %s\n",
  555. sn, wpt_class, nice(res->description));
  556. DBG(GDB_DBG_WPTe, !res->url.isNull())
  557. printf(MYNAME "-wpt \"%s\" (%d): url = %s\n",
  558. sn, wpt_class, nice(qPrintable(res->url))); // FIXME: qPrintable and nice probably are fighting.
  559. #endif
  560. i = FREAD_i16;
  561. if (i != 0) {
  562. GMSD_SET(category, i);
  563. }
  564. #if GDB_DEBUG
  565. DBG(GDB_DBG_WPTe, i)
  566. printf(MYNAME "-wpt \"%s\" (%d): category = %d\n",
  567. sn, wpt_class, i);
  568. #endif
  569. if (FREAD_C == 1) {
  570. WAYPT_SET(res, temperature, FREAD_DBL);
  571. #if GDB_DEBUG
  572. DBG(GDB_DBG_WPTe, 1)
  573. printf(MYNAME "-wpt \"%s\" (%d): temperature = %.1f\n",
  574. sn, wpt_class, res->temperature);
  575. #endif
  576. }
  577. /* VERSION DEPENDENT CODE */
  578. if (gdb_ver <= GDB_VER_2) {
  579. if (waypt_flag != 0) {
  580. FREAD(buf, 1);
  581. }
  582. }
  583. if (FREAD_C == 1) {
  584. res->SetCreationTime(FREAD_i32);
  585. }
  586. /* VERSION DEPENDENT CODE */
  587. if (gdb_ver >= GDB_VER_3) {
  588. if (FREAD_i32 == 1) {
  589. FREAD_STR(buf); /* phone number */
  590. GMSD_SETSTR(phone_nr, bufp);
  591. FREAD_STR(buf); /* ?? fax / mobile ?? */
  592. }
  593. FREAD_STR(buf); /* country */
  594. GMSD_SETSTR(country, bufp);
  595. FREAD_STR(buf); /* postal code */
  596. GMSD_SETSTR(postal_code, bufp);
  597. }
  598. res->icon_descr = gt_find_desc_from_icon_number(icon, GDB);
  599. #if GDB_DEBUG
  600. DBG(GDB_DBG_WPTe, icon != GDB_DEF_ICON)
  601. printf(MYNAME "-wpt \"%s\" (%d): icon = \"%s\" (MapSource symbol %d)\n",
  602. sn, wpt_class, nice(qPrintable(res->icon_descr)), icon); // FIXME: qPrintable and nice probably are fighting.
  603. #endif
  604. if ((str = GMSD_GET(cc, NULL))) {
  605. if (! GMSD_HAS(country)) {
  606. GMSD_SETSTR(country, gt_get_icao_country(str));
  607. }
  608. }
  609. if (gdb_roadbook && (wpt_class > gt_waypt_class_map_point) && !res->description.isEmpty()) {
  610. wpt_class = gt_waypt_class_user_waypoint;
  611. GMSD_SET(wpt_class, wpt_class);
  612. #ifdef GMSD_EXPERIMENTAL
  613. GMSD_UNSET(subclass);
  614. #endif
  615. }
  616. #if GDB_DEBUG
  617. xfree(sn);
  618. #endif
  619. *waypt_class_out = wpt_class;
  620. return res;
  621. }
  622. /*-----------------------------------------------------------------------------*/
  623. static route_head*
  624. read_route(void)
  625. {
  626. route_head* rte;
  627. int points, warnings, links, i;
  628. char buf[128];
  629. bounds bounds;
  630. int color_idx;
  631. rte_ct++;
  632. warnings = 0;
  633. rte = route_head_alloc();
  634. rte->rte_name = fread_cstr();
  635. FREAD(buf, 1); /* display/autoname - 1 byte */
  636. if (FREAD_C == 0) { /* max. data flag */
  637. /* maxlat = */ (void) FREAD_i32;
  638. /* maxlon = */
  639. (void) FREAD_i32;
  640. if (FREAD_C == 1) { /* maxalt = */
  641. FREAD_DBL;
  642. }
  643. /* minlat = */ (void) FREAD_i32;
  644. /* minlon = */
  645. (void) FREAD_i32;
  646. if (FREAD_C == 1) { /* minalt = */
  647. FREAD_DBL;
  648. }
  649. }
  650. links = 0;
  651. points = FREAD_i32;
  652. #if GDB_DEBUG
  653. DBG(GDB_DBG_RTE, 1)
  654. printf(MYNAME "-rte \"%s\": loading route with %d point(s)...\n",
  655. nice(rte->rte_name), points);
  656. #endif
  657. for (i = 0; i < points; i++) {
  658. int wpt_class, j;
  659. char buf[128];
  660. garmin_ilink_t* il_root, *il_anchor;
  661. Waypoint* wpt;
  662. wpt = new Waypoint;
  663. rtept_ct++;
  664. wpt->shortname = fread_cstr(); /* shortname */
  665. wpt_class = FREAD_i32; /* waypoint class */
  666. FREAD_STR(buf); /* country code */
  667. FREAD(buf, 18 + 4); /* subclass part 1-3 / unknown */
  668. if (FREAD_C != 0) {
  669. FREAD(buf, 8); /* aviation data (?); only seen with class "1" (Airport) */
  670. /* VERSION DEPENDENT CODE */
  671. if (gdb_ver >= GDB_VER_3) {
  672. FREAD(buf, 8); /* a second block since V3 */
  673. }
  674. }
  675. FREAD(buf, 18); /* unknown 18 bytes; but first should be 0x01 or 0x03 */
  676. /* seen also 0 with VER3 */
  677. if ((buf[0] != 0x00) && (buf[0] != 0x01) && (buf[0] != 0x03)) {
  678. int i;
  679. warnings++;
  680. if (warnings > 3) {
  681. fatal(MYNAME "-rte_pt \"%s\": too many warnings!\n", qPrintable(wpt->shortname));
  682. }
  683. warning(MYNAME "-rte_pt \"%s\" (class %d): possible error in route.\n", qPrintable(wpt->shortname), wpt_class);
  684. warning(MYNAME "-rte_pt (dump):");
  685. for (i = 0; i < 18; i++) {
  686. warning(" %02x", (unsigned char)buf[i]);
  687. }
  688. warning("\n");
  689. }
  690. links = FREAD_i32;
  691. il_anchor = NULL;
  692. il_root = NULL;
  693. #if GDB_DEBUG
  694. DBG(GDB_DBG_RTE, links)
  695. printf(MYNAME "-rte_pt \"%s\" (%d): %d interlink step(s)\n",
  696. nice(wpt->shortname), wpt_class, links);
  697. #endif
  698. for (j = 0; j < links; j++) {
  699. garmin_ilink_t* il_step = (garmin_ilink_t*) xmalloc(sizeof(*il_step));
  700. il_step->ref_count = 1;
  701. il_step->lat = FREAD_LATLON;
  702. il_step->lon = FREAD_LATLON;
  703. if (FREAD_C == 1) {
  704. il_step->alt = FREAD_DBL;
  705. } else {
  706. il_step->alt = unknown_alt;
  707. }
  708. if (j == 0) {
  709. wpt->latitude = il_step->lat;
  710. wpt->longitude = il_step->lon;
  711. wpt->altitude = il_step->alt;
  712. }
  713. il_step->next = NULL;
  714. if (il_anchor == NULL) {
  715. il_root = il_step;
  716. } else {
  717. il_anchor->next = il_step;
  718. }
  719. il_anchor = il_step;
  720. #if GDB_DEBUG
  721. DBG(GDB_DBG_RTEe, 1) {
  722. printf(MYNAME "-rte_il \"%s\" (%d of %d): %c%0.6f %c%0.6f\n",
  723. nice(wpt->shortname), j + 1, links,
  724. il_step->lat < 0 ? 'S' : 'N', il_step->lat,
  725. il_step->lon < 0 ? 'W' : 'E', il_step->lon);
  726. }
  727. #endif
  728. }
  729. waypt_init_bounds(&bounds);
  730. if (FREAD_C == 0) { /* interlink bounds */
  731. bounds.max_lat = FREAD_LATLON;
  732. bounds.max_lon = FREAD_LATLON;
  733. if (FREAD_C == 1) {
  734. bounds.max_alt = FREAD_DBL;
  735. }
  736. bounds.min_lat = FREAD_LATLON;
  737. bounds.min_lat = FREAD_LATLON;
  738. if (FREAD_C == 1) {
  739. bounds.min_alt = FREAD_DBL;
  740. }
  741. }
  742. if (links == 0) {
  743. /* Without links we need all informations from wpt */
  744. Waypoint* tmp = gdb_reader_find_waypt(wpt, 0);
  745. if (tmp != NULL) {
  746. delete wpt;
  747. wpt = new Waypoint(*tmp);
  748. } else {
  749. if (waypt_bounds_valid(&bounds)) {
  750. warning(MYNAME ": (has bounds)\n");
  751. }
  752. warning(MYNAME ": Data corruption detected!\n");
  753. fatal(MYNAME ": Sleeping route point without coordinates!\n");
  754. }
  755. }
  756. /* VERSION DEPENDENT CODE */
  757. if (gdb_ver >= GDB_VER_2) {
  758. FREAD(buf, 8);
  759. if (gdb_ver >= GDB_VER_3) {
  760. FREAD(buf, 2);
  761. }
  762. }
  763. #if GDB_DEBUG
  764. DBG(GDB_DBG_RTE, 1)
  765. printf(MYNAME "-rte_pt \"%s\": coordinates = %c%0.6f, %c%0.6f\n",
  766. nice(wpt->shortname),
  767. wpt->latitude < 0 ? 'S' : 'N', wpt->latitude,
  768. wpt->longitude < 0 ? 'W' : 'E', wpt->longitude);
  769. #endif
  770. wpt = gdb_add_route_waypt(rte, wpt, wpt_class);
  771. if (wpt != NULL) {
  772. garmin_fs_t* gmsd = GMSD_FIND(wpt);
  773. if (gmsd == NULL) {
  774. gmsd = garmin_fs_alloc(-1);
  775. fs_chain_add(&wpt->fs, (format_specific_data*) gmsd);
  776. }
  777. GMSD_SET(wpt_class, wpt_class);
  778. gmsd->ilinks = il_root;
  779. il_root = NULL;
  780. }
  781. while (il_root) {
  782. garmin_ilink_t* il = il_root;
  783. il_root = il_root->next;
  784. xfree(il);
  785. }
  786. } /* ENDFOR: for (i = 0; i < points; i++) */
  787. /* VERSION DEPENDENT CODE */
  788. if (gdb_ver <= GDB_VER_2) {
  789. rte->rte_url = fread_cstr();
  790. } else {
  791. rte->rte_url = gdb_fread_strlist();
  792. color_idx = FREAD_i32;
  793. rte->line_color.bbggrr = gt_color_value(color_idx);
  794. FREAD(buf, 1); /* ?????????????????????????????????? */
  795. rte->rte_desc = fread_cstr();
  796. #if 0
  797. /* replace CRLF's with ", " */
  798. if (rte->rte_desc) {
  799. char* c = rte->rte_desc;
  800. while ((c = strstr(c, "\r\n"))) {
  801. *c++ = ',';
  802. *c++ = ' ';
  803. }
  804. }
  805. #endif
  806. }
  807. return rte;
  808. }
  809. /*-----------------------------------------------------------------------------*/
  810. static route_head*
  811. read_track(void)
  812. {
  813. route_head* res;
  814. int points, index;
  815. char dummy;
  816. int color_idx;
  817. trk_ct++;
  818. res = route_head_alloc();
  819. res->rte_name = fread_cstr();
  820. // res->rte_num = trk_ct;
  821. FREAD(&dummy, 1); /* display - 1 byte */
  822. color_idx = FREAD_i32; /* color - 1 dword */
  823. res->line_color.bbggrr = gt_color_value(color_idx);
  824. points = FREAD_i32;
  825. for (index = 0; index < points; index++) {
  826. Waypoint* wpt = new Waypoint;
  827. trkpt_ct++;
  828. wpt->latitude = FREAD_LATLON;
  829. wpt->longitude = FREAD_LATLON;
  830. if (FREAD_C == 1) {
  831. double alt = FREAD_DBL;
  832. if (alt < 1.0e24) {
  833. wpt->altitude = alt;
  834. }
  835. }
  836. if (FREAD_C == 1) {
  837. wpt->SetCreationTime(FREAD_i32);
  838. }
  839. if (FREAD_C == 1) {
  840. WAYPT_SET(wpt, depth, FREAD_DBL);
  841. }
  842. if (FREAD_C == 1) {
  843. WAYPT_SET(wpt, temperature, FREAD_DBL);
  844. }
  845. track_add_wpt(res, wpt);
  846. }
  847. /* VERSION DEPENDENT CODE */
  848. if (gdb_ver >= GDB_VER_3) {
  849. res->rte_url = gdb_fread_strlist();
  850. } else { /* if (gdb_ver <= GDB_VER_2) */
  851. res->rte_url = FREAD_CSTR_AS_QSTR;
  852. }
  853. #if GDB_DEBUG
  854. DBG(GDB_DBG_TRK, !res->rte_url.isNull())
  855. printf(MYNAME "-trk \"%s\": url = %s\n",
  856. res->rte_name, qPrintable(res->rte_url));
  857. #endif
  858. return res;
  859. }
  860. /*******************************************************************************/
  861. static void
  862. gdb_rd_init(const QString& fname)
  863. {
  864. fin = gbfopen_le(fname, "rb", MYNAME);
  865. ftmp = gbfopen_le(NULL, "wb", MYNAME);
  866. read_file_header();
  867. /* VERSION DEPENDENT CODE */
  868. if (gdb_ver >= GDB_VER_UTF8) {
  869. cet_convert_init(CET_CHARSET_UTF8, 1);
  870. }
  871. QUEUE_INIT(&wayptq_in);
  872. QUEUE_INIT(&wayptq_in_hidden);
  873. gdb_via = (gdb_opt_via && *gdb_opt_via) ? atoi(gdb_opt_via) : 0;
  874. gdb_roadbook = (gdb_opt_roadbook && *gdb_opt_roadbook) ? atoi(gdb_opt_roadbook) : 0;
  875. if (gdb_roadbook) { /* higher priority */
  876. gdb_via = 1;
  877. }
  878. waypt_ct = 0;
  879. waypth_ct = 0;
  880. rtept_ct = 0;
  881. trkpt_ct = 0;
  882. rte_ct = 0;
  883. trk_ct = 0;
  884. }
  885. static void
  886. gdb_rd_deinit(void)
  887. {
  888. disp_summary(fin);
  889. gdb_flush_waypt_queue(&wayptq_in);
  890. gdb_flush_waypt_queue(&wayptq_in_hidden);
  891. gbfclose(ftmp);
  892. gbfclose(fin);
  893. }
  894. static void
  895. read_data(void)
  896. {
  897. gbfile* fsave;
  898. int incomplete = 0; /* number of incomplete reads */
  899. for (;;) {
  900. int len, delta;
  901. char typ, dump;
  902. gt_waypt_classes_e wpt_class;
  903. Waypoint* wpt;
  904. route_head* trk, *rte;
  905. len = FREAD_i32;
  906. if (FREAD(&typ, 1) < 1) {
  907. fatal(MYNAME ": Attempt to read past EOF.");
  908. }
  909. if (typ == 'V') {
  910. break; /* break the loop */
  911. }
  912. gbfrewind(ftmp);
  913. gbfwrite(NULL, 0, 0, ftmp); /* truncate */
  914. gbfcopyfrom(ftmp, fin, len);
  915. gbfrewind(ftmp);
  916. fsave = fin; /* swap standard 'fin' with cached input */
  917. fin = ftmp;
  918. dump = 1;
  919. wpt_class = GDB_DEF_CLASS;
  920. switch (typ) {
  921. case 'W':
  922. wpt = read_waypoint(&wpt_class);
  923. if ((gdb_via == 0) || (wpt_class == 0)) {
  924. Waypoint* dupe;
  925. waypt_add(wpt);
  926. dupe = new Waypoint(*wpt);
  927. ENQUEUE_TAIL(&wayptq_in, &dupe->Q);
  928. } else {
  929. ENQUEUE_TAIL(&wayptq_in_hidden, &wpt->Q);
  930. }
  931. break;
  932. case 'R':
  933. rte = read_route();
  934. if (rte) {
  935. route_add_head(rte);
  936. }
  937. break;
  938. case 'T':
  939. trk = read_track();
  940. if (trk) {
  941. track_add_head(trk);
  942. }
  943. break;
  944. default:
  945. dump = 0; /* make a dump only for main types */
  946. break;
  947. }
  948. fin = fsave;
  949. delta = len - gbftell(ftmp);
  950. is_fatal(delta > 1000000, "Internal consistency error. Delta too big");
  951. // Avoid finite loop on bogus beta files from '06.
  952. // THe 100000 is totally pulled from my hat.
  953. // is_fatal((delta > 1000000) || (delta < 0), "Internal GDB error; invalid delta.");
  954. if (dump && delta) {
  955. if (! incomplete++) {
  956. warning(MYNAME ":==========================================\n");
  957. warning(MYNAME ":=== W A R N I N G ===\n");
  958. }
  959. if (typ == 'W')
  960. warning(MYNAME ":(%d%c-%02d): delta = %d (flag=%3d/%02x)-",
  961. gdb_ver, typ, wpt_class, delta, waypt_flag, waypt_flag);
  962. else {
  963. warning(MYNAME ":(%d%c): delta = %d -", gdb_ver, typ, delta);
  964. }
  965. if (delta > 0) {
  966. int i;
  967. char* buf = (char*) xmalloc(delta);
  968. if (FREAD(buf, delta) < 1) {
  969. fatal(MYNAME ": Attempt to read past EOF.\n");
  970. }
  971. for (i = 0; i < delta; i++) {
  972. warning(" %02x", (unsigned char)buf[i]);
  973. }
  974. xfree(buf);
  975. }
  976. warning("\n");
  977. }
  978. }
  979. if (incomplete) {
  980. warning(MYNAME ":------------------------------------------\n");
  981. warning(MYNAME ": \"%s\"\n", fin->name);
  982. warning(MYNAME ":------------------------------------------\n");
  983. warning(MYNAME ": Please mail this information\n");
  984. warning(MYNAME " and, if you can, the used GDB file\n");
  985. warning(MYNAME ": to gpsbabel-misc@lists.sourceforge.net\n");
  986. warning(MYNAME ":==========================================\n");
  987. }
  988. }
  989. /*******************************************************************************/
  990. /*
  991. * reset_short_handle: used for waypoint, route and track names
  992. */
  993. static void
  994. reset_short_handle(const char* defname)
  995. {
  996. if (short_h != NULL) {
  997. mkshort_del_handle(&short_h);
  998. }
  999. short_h = mkshort_new_handle();
  1000. setshort_length(short_h, GDB_NAME_BUFFERLEN);
  1001. setshort_badchars(short_h, "\r\n\t");
  1002. setshort_mustupper(short_h, 0);
  1003. setshort_mustuniq(short_h, 1);
  1004. setshort_whitespace_ok(short_h, 1);
  1005. setshort_repeating_whitespace_ok(short_h, 1);
  1006. setshort_defname(short_h, defname);
  1007. }
  1008. /* ----------------------------------------------------------------------------*/
  1009. static void
  1010. write_header(void)
  1011. {
  1012. char buff[128], tbuff[32];
  1013. char* c;
  1014. int len, n = 0;
  1015. struct tm tm;
  1016. FWRITE_CSTR("MsRcf");
  1017. FWRITE_i32(2);
  1018. strncpy(buff, "Dx", sizeof(buff));
  1019. buff[1] = 'k' - 1 + gdb_ver;
  1020. FWRITE_CSTR(buff);
  1021. #if 0
  1022. /* Take this if anything is wrong with our self generated watermark */
  1023. strncpy(buff, "A].SQA*Dec 27 2004*17:40:51", sizeof(buff)); /* MapSource V6.5 */
  1024. #else
  1025. /* This is our "Watermark" to show this file was created by GPSbabel */
  1026. /* history:
  1027. "A].GPSBabel_1.2.7-beta*Sep 13 2005*20:10:00" - gpsbabel V1.2.7 BETA
  1028. "A].GPSBabel_1.2.8-beta*Jan 18 2006*20:11:00" - gpsbabel 1.2.8-beta01182006_clyde
  1029. "A].GPSBabel_1.2.8-beta*Apr 18 2006*20:12:00" - gpsbabel 1.2.8-beta20060405
  1030. "A].GPSBabel-1.3*Jul 02 2006*20:13:00" - gpsbabel 1.3.0
  1031. "A].GPSBabel-1.3.1*Sep 03 2006*20:14:00" - gpsbabel 1.3.1
  1032. "A].GPSBabel-1.3.2*Nov 01 2006*22:23:39" - gpsbabel 1.3.2
  1033. New since 11/01/2006:
  1034. version: version and release of gpsbabel (defined in configure.in)
  1035. timestamp: date and time of gdb.c (handled by CVS)
  1036. "A].GPSBabel-1.3.2*Nov 01 2006*22:23:39" - gpsbabel 1.3.2
  1037. "A].GPSBabel-beta20061125*Feb 06 2007*23:24:14" gpsbabel beta20061125
  1038. "A].GPSBabel-1.3.3*Feb 20 2007*20:51:15" - gpsbabel 1.3.3
  1039. */
  1040. memset(&tm, 0, sizeof(tm));
  1041. n = sscanf(gdb_release_date+7, "%d-%d-%d %d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
  1042. if (n != 6) {
  1043. // The $Date string in gdb_release_date[] above is bad.
  1044. fatal(MYNAME ": internal date format error on %s\n", gdb_release_date + 7);
  1045. }
  1046. tm.tm_year -= 1900;
  1047. tm.tm_mon -= 1;
  1048. n = strftime(tbuff, sizeof(tbuff), "%b %d %Y*%H:%M:%S", &tm);
  1049. if (n == 0) {
  1050. // The build of the struct tm was bad.
  1051. fatal(MYNAME ": internal date generation error for %s\n", gdb_release_date + 7);
  1052. }
  1053. snprintf(buff, sizeof(buff), "A].GPSBabel-%s*%s", gpsbabel_version, tbuff);
  1054. #endif
  1055. len = strlen(buff);
  1056. buff[2] = 2;
  1057. c = buff;
  1058. while ((c = strchr(c, '*'))) {
  1059. *c++ = '\0';
  1060. }
  1061. FWRITE_i32(len);
  1062. FWRITE(buff, len + 1);
  1063. FWRITE_CSTR("MapSource"); /* MapSource magic */
  1064. }
  1065. /*-----------------------------------------------------------------------------*/
  1066. /*
  1067. * gdb_check_waypt: As implemented in waypt_add, but we have some leaks where
  1068. * waypoints are modified after waypt_add. Maybe we need a data check
  1069. * after each input module.
  1070. */
  1071. static void
  1072. gdb_check_waypt(Waypoint* wpt)
  1073. {
  1074. double lat_orig = wpt->latitude;
  1075. double lon_orig = wpt->longitude;
  1076. if (wpt->latitude < -90) {
  1077. wpt->latitude += 180;
  1078. } else if (wpt->latitude > +90) {
  1079. wpt->latitude -= 180;
  1080. }
  1081. if (wpt->longitude < -180) {
  1082. wpt->longitude += 360;
  1083. } else if (wpt->longitude > +180) {
  1084. wpt->longitude -= 360;
  1085. }
  1086. if ((wpt->latitude < -90) || (wpt->latitude > 90.0))
  1087. fatal("Invalid latitude %f in waypoint %s.\n",
  1088. lat_orig, !wpt->shortname.isEmpty() ? qPrintable(wpt->shortname) : "<no name>");
  1089. if ((wpt->longitude < -180) || (wpt->longitude > 180.0))
  1090. fatal("Invalid longitude %f in waypoint %s.\n",
  1091. lon_orig, !wpt->shortname.isEmpty() ? qPrintable(wpt->shortname) : "<no name>");
  1092. }
  1093. /*-----------------------------------------------------------------------------*/
  1094. static void
  1095. write_waypoint(
  1096. const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd,
  1097. const int icon, const int display)
  1098. {
  1099. char zbuf[32], ffbuf[32];
  1100. int wpt_class;
  1101. waypt_ct++; /* increase informational number of written waypoints */
  1102. memset(zbuf, 0, sizeof(zbuf));
  1103. memset(ffbuf, 0xFF, sizeof(ffbuf));
  1104. wpt_class = wpt->wpt_flags.fmt_use; /* trick */
  1105. FWRITE_CSTR(shortname); /* uniqe (!!!) shortname */
  1106. FWRITE_i32(wpt_class); /* waypoint class */
  1107. FWRITE_CSTR(GMSD_GET(cc, "")); /* country code */
  1108. if (wpt_class != 0) {
  1109. waypth_ct++;
  1110. }
  1111. #ifdef GMSD_EXPERIMENTAL
  1112. if (gmsd && gmsd->flags.subclass && (wpt_class >= gt_waypt_class_map_point)) {
  1113. FWRITE(gmsd->subclass, sizeof(gmsd->subclass));
  1114. } else
  1115. #endif
  1116. {
  1117. FWRITE(zbuf, 4); /* subclass part 1 */
  1118. FWRITE(ffbuf, 12); /* subclass part 2 */
  1119. FWRITE(zbuf, 2); /* subclass part 3 */
  1120. FWRITE(ffbuf, 4); /* unknown */
  1121. }
  1122. FWRITE_LATLON(wpt->latitude); /* latitude */
  1123. FWRITE_LATLON(wpt->longitude); /* longitude */
  1124. FWRITE_DBL(wpt->altitude, unknown_alt); /* altitude */
  1125. if (!wpt->notes.isEmpty()) {
  1126. FWRITE_CSTR(wpt->notes);
  1127. } else {
  1128. FWRITE_CSTR(wpt->description);
  1129. }
  1130. FWRITE_DBL(WAYPT_GET(wpt, proximity, unknown_alt), unknown_alt); /* proximity */
  1131. FWRITE_i32(display); /* display */
  1132. FWRITE_i32(0); /* color */
  1133. FWRITE_i32(icon); /* icon */
  1134. FWRITE_CSTR(GMSD_GET(city, "")); /* city */
  1135. FWRITE_CSTR(GMSD_GET(state, "")); /* state */
  1136. FWRITE_CSTR(GMSD_GET(facility, "")); /* facility */
  1137. FWRITE_C(0); /* unknown */
  1138. FWRITE_DBL(WAYPT_GET(wpt, depth, unknown_alt), unknown_alt); /* depth */
  1139. /* VERSION DEPENDENT CODE */
  1140. if (gdb_ver <= GDB_VER_2) {
  1141. QString descr;
  1142. FWRITE(zbuf, 3);
  1143. FWRITE(zbuf, 4);
  1144. QString ld;
  1145. if (wpt->HasUrlLink()) {
  1146. UrlLink l = wpt->GetUrlLink();
  1147. ld = l.url_;
  1148. }
  1149. descr = (wpt_class < gt_waypt_class_map_point) ?
  1150. ld : wpt->description;
  1151. if ((descr != NULL) && (wpt_class >= gt_waypt_class_map_point) && \
  1152. descr == CSTRc(wpt->shortname)) {
  1153. descr.clear();
  1154. }
  1155. FWRITE_CSTR(descr);
  1156. } else { /* if (gdb_ver > GDB_VER_3) */
  1157. int cnt;
  1158. // url_link* url_next;
  1159. // const char* str;
  1160. QString str;
  1161. if (wpt_class < gt_waypt_class_map_point) { /* street address */
  1162. str = GMSD_GET(addr, "");
  1163. } else {
  1164. str = "";
  1165. }
  1166. FWRITE_CSTR(str);
  1167. FWRITE(zbuf, 5); /* instruction dependend */
  1168. /* GBD doesn't have a native description field */
  1169. /* here we misuse the instruction field */
  1170. #if 1
  1171. QString d = wpt->description;
  1172. if (wpt->description == wpt->shortname) {
  1173. d.clear();
  1174. }
  1175. if (str == wpt->notes) {
  1176. d.clear();
  1177. }
  1178. FWRITE_CSTR(d); /* instruction */
  1179. #else
  1180. str = wpt->description;
  1181. if (str && (strcmp(str, wpt->shortname) == 0)) {
  1182. str = NULL;
  1183. }
  1184. if (str && wpt->notes && (strcmp(str, wpt->notes) == 0)) {
  1185. str = NULL;
  1186. }
  1187. FWRITE_CSTR(str); /* instruction */
  1188. #endif
  1189. cnt = 0;
  1190. cnt += wpt->url_link_list_.size();
  1191. FWRITE_i32(cnt);
  1192. foreach(UrlLink l, wpt->GetUrlLinks()) {
  1193. FWRITE_CSTR(l.url_);
  1194. }
  1195. }
  1196. FWRITE_i16(GMSD_GET(category, gdb_category));
  1197. FWRITE_DBL(WAYPT_GET(wpt, temperature, 0), 0);
  1198. FWRITE_TIME(wpt->GetCreationTime().toTime_t());
  1199. /* VERSION DEPENDENT CODE */
  1200. if (gdb_ver >= GDB_VER_3) {
  1201. const char* str = GMSD_GET(phone_nr, "");
  1202. if (*str) {
  1203. FWRITE_i32(1);
  1204. FWRITE_CSTR(str);
  1205. FWRITE_CSTR("");
  1206. } else {
  1207. FWRITE_i32(0);
  1208. }
  1209. FWRITE_CSTR(GMSD_GET(country, ""));
  1210. FWRITE_CSTR(GMSD_GET(postal_code, ""));
  1211. }
  1212. }
  1213. static void
  1214. route_compute_bounds(const route_head* rte, bounds* bounds)
  1215. {
  1216. queue* elem, *tmp;
  1217. waypt_init_bounds(bounds);
  1218. QUEUE_FOR_EACH((queue*)&rte->waypoint_list, elem, tmp) {
  1219. Waypoint* wpt = (Waypoint*)elem;
  1220. gdb_check_waypt(wpt);
  1221. waypt_add_to_bounds(bounds, wpt);
  1222. }
  1223. }
  1224. static void
  1225. route_write_bounds(bounds* bounds)
  1226. {
  1227. if (waypt_bounds_valid(bounds)) {
  1228. FWRITE_C(0);
  1229. FWRITE_LATLON(bounds->max_lat);
  1230. FWRITE_LATLON(bounds->max_lon);
  1231. FWRITE_DBL(bounds->max_alt, unknown_alt);
  1232. FWRITE_LATLON(bounds->min_lat);
  1233. FWRITE_LATLON(bounds->min_lon);
  1234. FWRITE_DBL(bounds->min_alt, -(unknown_alt));
  1235. } else {
  1236. FWRITE_C(1);
  1237. }
  1238. }
  1239. static void
  1240. write_route(const route_head* rte, const QString& rte_name)
  1241. {
  1242. bounds bounds;
  1243. int points, index;
  1244. queue* elem, *tmp;
  1245. char zbuf[32], ffbuf[32];
  1246. memset(zbuf, 0, sizeof(zbuf));
  1247. memset(ffbuf, 0xFF, sizeof(ffbuf));
  1248. FWRITE_CSTR(rte_name);
  1249. FWRITE_C(0); /* display/autoname - 1 byte */
  1250. route_compute_bounds(rte, &bounds);
  1251. route_write_bounds(&bounds);
  1252. points = ELEMENTS(rte);
  1253. FWRITE_i32(points);
  1254. index = 0;
  1255. QUEUE_FOR_EACH((queue*)&rte->waypoint_list, elem, tmp) {
  1256. Waypoint* wpt = (Waypoint*)elem;
  1257. Waypoint* next = (Waypoint*)tmp;
  1258. Waypoint* test;
  1259. garmin_fs_t* gmsd = NULL;
  1260. int wpt_class;
  1261. index++;
  1262. rtept_ct++; /* increase informational number of written route points */
  1263. if (index == 1) {
  1264. gdb_check_waypt(wpt);
  1265. }
  1266. if (index < points) {
  1267. gdb_check_waypt(next);
  1268. }
  1269. test = gdb_find_wayptq(&wayptq_out, wpt, 1);
  1270. if (test != NULL) {
  1271. wpt = test;
  1272. } else {
  1273. fatal(MYNAME ": Sorry, that should never happen!!!\n");
  1274. }
  1275. gmsd = GMSD_FIND(wpt);
  1276. /* extra_data may contain a modified shortname */
  1277. FWRITE_CSTR((wpt->extra_data) ? (char*)wpt->extra_data : wpt->shortname);
  1278. wpt_class = wpt->wpt_flags.fmt_use; /* trick */
  1279. FWRITE_i32(wpt_class); /* waypoint class */
  1280. FWRITE_CSTR(GMSD_GET(cc, "")); /* country */
  1281. #ifdef GMSD_EXPERIMENTAL
  1282. if (gmsd && gmsd->flags.subclass && (wpt_class >= gt_waypt_class_map_point)) {
  1283. FWRITE(gmsd->subclass, sizeof(gmsd->subclass));
  1284. } else
  1285. #endif
  1286. {
  1287. FWRITE(zbuf, 4); /* subclass part 1 */
  1288. FWRITE(ffbuf, 12); /* subclass part 2 */
  1289. FWRITE(zbuf, 2); /* subclass part 3 */
  1290. FWRITE(ffbuf, 4); /* unknown */
  1291. }
  1292. FWRITE_C(0); /* unknown value or string */
  1293. FWRITE_C(3); /* unknown 18 bytes starting with 0x03 */
  1294. FWRITE(zbuf, 3);
  1295. FWRITE(ffbuf, 4);
  1296. FWRITE(zbuf, 10);
  1297. if (index == points) {
  1298. FWRITE_i32(0); /* no more steps */
  1299. FWRITE_C(1); /* skip bounds */
  1300. } else { /* if (index < points) */
  1301. FWRITE_i32(2); /* two interstep links */
  1302. FWRITE_LATLON(wpt->latitude);
  1303. FWRITE_LATLON(wpt->longitude);
  1304. FWRITE_DBL(wpt->altitude, unknown_alt);
  1305. FWRITE_LATLON(next->latitude);
  1306. FWRITE_LATLON(next->longitude);
  1307. FWRITE_DBL(next->altitude, unknown_alt);
  1308. waypt_init_bounds(&bounds);
  1309. waypt_add_to_bounds(&bounds, wpt);
  1310. waypt_add_to_bounds(&bounds, next);
  1311. route_write_bounds(&bounds);
  1312. }
  1313. /* VERSION DEPENDENT CODE */
  1314. if (gdb_ver >= GDB_VER_2) {
  1315. FWRITE(ffbuf, 8);
  1316. if (gdb_ver >= GDB_VER_3) {
  1317. FWRITE(zbuf, 2);
  1318. }
  1319. }
  1320. }
  1321. /* VERSION DEPENDENT CODE */
  1322. if (gdb_ver <= GDB_VER_2) {
  1323. FWRITE_CSTR(rte->rte_url);
  1324. } else { /* if (gdb_ver >= GDB_VER_3) */
  1325. FWRITE_CSTR_LIST(rte->rte_url);
  1326. /* "Magenta" (14) is MapSource default */
  1327. FWRITE_i32((rte->line_color.bbggrr < 0) ? 14 : gt_color_index_by_rgb(rte->line_color.bbggrr));
  1328. FWRITE_C(0);
  1329. FWRITE_CSTR(rte->rte_desc);
  1330. }
  1331. }
  1332. static void
  1333. write_track(const route_head* trk, const QString& trk_name)
  1334. {
  1335. queue* elem, *tmp;
  1336. int points = ELEMENTS(trk);
  1337. FWRITE_CSTR(trk_name);
  1338. FWRITE_C(0);
  1339. /* "Unknown" (0) is MapSource default */
  1340. FWRITE_i32(gt_color_index_by_rgb(trk->line_color.bbggrr));
  1341. FWRITE_i32(points); /* total number of waypoints in waypoint list */
  1342. QUEUE_FOR_EACH((queue*)&trk->waypoint_list, elem, tmp) {
  1343. double d;
  1344. Waypoint* wpt = (Waypoint*)elem;
  1345. trkpt_ct++; /* increase informational number of written route points */
  1346. FWRITE_LATLON(wpt->latitude);
  1347. FWRITE_LATLON(wpt->longitude);
  1348. FWRITE_DBL(wpt->altitude, unknown_alt);
  1349. FWRITE_TIME(wpt->GetCreationTime().toTime_t());
  1350. d = WAYPT_GET(wpt, depth, unknown_alt);
  1351. FWRITE_DBL(d, unknown_alt);
  1352. d = WAYPT_GET(wpt, temperature, -99999);
  1353. FWRITE_DBL(d, -99999);
  1354. }
  1355. /* finalize track */
  1356. /* VERSION DEPENDENT CODE */
  1357. if (gdb_ver <= GDB_VER_2) {
  1358. FWRITE_CSTR(trk->rte_url);
  1359. } else { /* if (gdb_ver >= GDB_VER_3 */
  1360. FWRITE_CSTR_LIST(trk->rte_url);
  1361. }
  1362. }
  1363. /*-----------------------------------------------------------------------------*/
  1364. static void
  1365. finalize_item(gbfile* origin, const char identifier)
  1366. {
  1367. int len = gbftell(fout);
  1368. fout = origin;
  1369. gbfseek(ftmp, 0, SEEK_SET);
  1370. FWRITE_i32(len);
  1371. FWRITE_C(identifier);
  1372. gbfcopyfrom(fout, ftmp, len);
  1373. gbfseek(ftmp, 0, SEEK_SET); /* Truncate memory stream */
  1374. gbfwrite(NULL, 0, 0, ftmp);
  1375. }
  1376. /*-----------------------------------------------------------------------------*/
  1377. static void
  1378. write_waypoint_cb(const Waypoint* refpt)
  1379. {
  1380. garmin_fs_t* gmsd;
  1381. Waypoint* test;
  1382. gbfile* fsave;
  1383. /* do this when backup always happens in main */
  1384. #if NEW_STRINGS
  1385. // but, but, casting away the const here is wrong...
  1386. ((Waypoint*)refpt)->shortname = refpt->shortname.trimmed();
  1387. #else
  1388. rtrim(((Waypoint*)refpt)->shortname);
  1389. #endif
  1390. test = gdb_find_wayptq(&wayptq_out, refpt, 1);
  1391. if (refpt->HasUrlLink() && test && test->HasUrlLink() && route_flag == 0) {
  1392. UrlLink orig_link = refpt->GetUrlLink();
  1393. UrlLink test_link = test->GetUrlLink();
  1394. if (orig_link.url_ != test_link.url_) {
  1395. test = NULL;
  1396. }
  1397. }
  1398. if ((test != NULL) && (route_flag == 0)) {
  1399. if (test->notes != refpt->notes) {
  1400. test = NULL;
  1401. }
  1402. }
  1403. if (test == NULL) {
  1404. int icon, display, wpt_class;
  1405. Waypoint* wpt = new Waypoint(*refpt);
  1406. gdb_check_waypt(wpt);
  1407. ENQUEUE_TAIL(&wayptq_out, &wpt->Q);
  1408. fsave = fout;
  1409. fout = ftmp;
  1410. /* prepare the waypoint */
  1411. gmsd = GMSD_FIND(wpt);
  1412. wpt_class = GMSD_GET(wpt_class, -1);
  1413. if (wpt_class == -1) {
  1414. wpt_class = (route_flag) ? GDB_DEF_HIDDEN_CLASS : GDB_DEF_CLASS;
  1415. }
  1416. wpt->wpt_flags.fmt_use = wpt_class; /* trick, we need this for the route(s) */
  1417. icon = GMSD_GET(icon, -1);
  1418. if (icon < 0) {
  1419. if (wpt->icon_descr.isNull()) {
  1420. icon = GDB_DEF_ICON;
  1421. } else {
  1422. icon = gt_find_icon_number_from_desc(wpt->icon_descr, GDB);
  1423. }
  1424. }
  1425. switch (GMSD_GET(display, -1)) { /* display */
  1426. case -1:
  1427. if (wpt_class < 8) {
  1428. display = gt_gdb_display_mode_symbol_and_name;
  1429. } else {
  1430. display = gt_gdb_display_mode_symbol;
  1431. }
  1432. break;
  1433. case gt_display_mode_symbol:
  1434. display = gt_gdb_display_mode_symbol;
  1435. break;
  1436. case gt_display_mode_symbol_and_comment:
  1437. display = gt_gdb_display_mode_symbol_and_comment;
  1438. break;
  1439. default:
  1440. display = gt_gdb_display_mode_symbol_and_name;
  1441. break;
  1442. }
  1443. QString name = wpt->shortname;
  1444. if (global_opts.synthesize_shortnames || name.isEmpty()) {
  1445. name = wpt->notes;
  1446. if (name.isEmpty()) {
  1447. name = wpt->description;
  1448. }
  1449. if (name.isEmpty()) {
  1450. name = wpt->shortname;
  1451. }
  1452. }
  1453. name = mkshort(short_h, name);
  1454. #if NEW_STRINGS
  1455. // This is sooooo tacky.
  1456. // Actually, it's not just tacky. I can't figure out what this code
  1457. // was trying to do, but it's wrong and it breaks things.
  1458. // robertl 2013-12-30.
  1459. // wpt->extra_data = static_cast<void*>(&name);
  1460. #else
  1461. wpt->extra_data = (void*)name;
  1462. #endif
  1463. write_waypoint(wpt, name, gmsd, icon, display);
  1464. finalize_item(fsave, 'W');
  1465. }
  1466. }
  1467. static void
  1468. write_route_cb(const route_head* rte)
  1469. {
  1470. gbfile* fsave;
  1471. if (ELEMENTS(rte) <= 0) {
  1472. return;
  1473. }
  1474. QString name;
  1475. if (rte->rte_name.isNull()) {
  1476. name = mkshort(short_h, QString().sprintf("Route%04d", rte->rte_num));
  1477. } else {
  1478. name = mkshort(short_h, rte->rte_name);
  1479. }
  1480. rte_ct++; /* increase informational number of written routes */
  1481. fsave = fout;
  1482. fout = ftmp;
  1483. write_route(rte, name);
  1484. finalize_item(fsave, 'R');
  1485. }
  1486. static void
  1487. write_track_cb(const route_head* trk)
  1488. {
  1489. gbfile* fsave;
  1490. if (ELEMENTS(trk) <= 0) {
  1491. return;
  1492. }
  1493. QString name;
  1494. if (trk->rte_name.isNull()) {
  1495. name = mkshort(short_h, QString().sprintf("Track%04d", trk->rte_num));
  1496. } else {
  1497. name = mkshort(short_h, trk->rte_name);
  1498. }
  1499. trk_ct++; /* increase informational number of written tracks */
  1500. fsave = fout;
  1501. fout = ftmp;
  1502. write_track(trk, name);
  1503. finalize_item(fsave, 'T');
  1504. }
  1505. /*-----------------------------------------------------------------------------*/
  1506. static void
  1507. gdb_wr_init(const QString& fname)
  1508. {
  1509. fout = gbfopen_le(fname, "wb", MYNAME);
  1510. ftmp = gbfopen_le(NULL, "wb", MYNAME);
  1511. gdb_category = (gdb_opt_category) ? atoi(gdb_opt_category) : 0;
  1512. gdb_ver = (gdb_opt_ver && *gdb_opt_ver) ? atoi(gdb_opt_ver) : 0;
  1513. if (gdb_category) {
  1514. is_fatal((gdb_category < 1) || (gdb_category > 16),
  1515. MYNAME ": cat must be between 1 and 16!");
  1516. gdb_category = 1 << (gdb_category - 1);
  1517. }
  1518. if (gdb_opt_bitcategory) {
  1519. gdb_category = strtol(gdb_opt_bitcategory, NULL, 0);
  1520. }
  1521. if (gdb_ver >= GDB_VER_UTF8) {
  1522. cet_convert_init(CET_CHARSET_UTF8, 1);
  1523. }
  1524. QUEUE_INIT(&wayptq_out);
  1525. short_h = NULL;
  1526. waypt_ct = 0;
  1527. waypth_ct = 0;
  1528. rtept_ct = 0;
  1529. trkpt_ct = 0;
  1530. rte_ct = 0;
  1531. trk_ct = 0;
  1532. }
  1533. static void
  1534. gdb_wr_deinit(void)
  1535. {
  1536. disp_summary(fout);
  1537. gdb_flush_waypt_queue(&wayptq_out);
  1538. mkshort_del_handle(&short_h);
  1539. gbfclose(fout);
  1540. gbfclose(ftmp);
  1541. }
  1542. static void
  1543. write_data(void)
  1544. {
  1545. if (gdb_opt_ver) {
  1546. gdb_ver = atoi(gdb_opt_ver);
  1547. }
  1548. write_header();
  1549. reset_short_handle("WPT");
  1550. route_flag = 0;
  1551. waypt_disp_all(write_waypoint_cb);
  1552. route_flag = 1;
  1553. route_disp_all(NULL, NULL, write_waypoint_cb);
  1554. reset_short_handle("Route");
  1555. route_disp_all(write_route_cb, NULL, NULL);
  1556. reset_short_handle("Track");
  1557. track_disp_all(write_track_cb, NULL, NULL);
  1558. FWRITE_i32(2); /* finalize gdb with empty map segment */
  1559. FWRITE_CSTR("V");
  1560. FWRITE_C(1);
  1561. }
  1562. /*******************************************************************************/
  1563. #define GDB_OPT_VER "ver"
  1564. #define GDB_OPT_VIA "via"
  1565. #define GDB_OPT_CATEGORY "cat"
  1566. #define GDB_OPT_BITCATEGORY "bitscategory"
  1567. #define GDB_OPT_ROADBOOK "roadbook"
  1568. static arglist_t gdb_args[] = {
  1569. {
  1570. GDB_OPT_CATEGORY, &gdb_opt_category,
  1571. "Default category on output (1..16)",
  1572. NULL, ARGTYPE_INT, "1", "16"
  1573. },
  1574. {
  1575. GDB_OPT_BITCATEGORY, &gdb_opt_bitcategory, "Bitmap of categories",
  1576. NULL, ARGTYPE_INT, "1", "65535"
  1577. },
  1578. {
  1579. GDB_OPT_VER, &gdb_opt_ver,
  1580. "Version of gdb file to generate (1..3)",
  1581. "2", ARGTYPE_INT, "1", "3"
  1582. },
  1583. {
  1584. GDB_OPT_VIA, &gdb_opt_via,
  1585. "Drop route points that do not have an equivalent waypoint (hidden points)",
  1586. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  1587. },
  1588. {
  1589. GDB_OPT_ROADBOOK, &gdb_opt_roadbook,
  1590. "Include major turn points (with description) from calculated route",
  1591. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  1592. },
  1593. ARG_TERMINATOR
  1594. };
  1595. ff_vecs_t gdb_vecs = {
  1596. ff_type_file,
  1597. FF_CAP_RW_ALL,
  1598. gdb_rd_init,
  1599. gdb_wr_init,
  1600. gdb_rd_deinit,
  1601. gdb_wr_deinit,
  1602. read_data,
  1603. write_data,
  1604. NULL,
  1605. gdb_args,
  1606. CET_CHARSET_MS_ANSI, 0 /* O.K.: changed to NON-FIXED */
  1607. /* because of utf8 strings since GDB V3 */
  1608. };
  1609. /*******************************************************************************/