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.

mapsource.cc 60KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105
  1. /*
  2. Access to Garmin MapSource files.
  3. Based on information provided by Ian Cowley & Mark Bradley
  4. Copyright (C) 2002 Robert Lipe, robertlipe+source@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. /* #define MPS_DEBUG 0 */
  18. #include "defs.h"
  19. #include "garmin_tables.h"
  20. #include "jeeps/gpsmath.h"
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <QtCore/QFile>
  24. static gbfile* mps_file_in;
  25. static gbfile* mps_file_out;
  26. static gbfile* mps_file_temp;
  27. static short_handle mkshort_handle;
  28. static int mps_ver_in = 0;
  29. static int mps_ver_out = 0;
  30. static int mps_ver_temp = 0;
  31. /* Temporary pathname used when merging gpsbabel output with an existing file */
  32. static QString tempname;
  33. static QString fin_name;
  34. static const Waypoint* prevRouteWpt;
  35. /* Private queues of written out waypoints */
  36. static queue written_wpt_head;
  37. static queue written_route_wpt_head;
  38. static short_handle written_wpt_mkshort_handle;
  39. /* Private queue of read in waypoints assumed to be used only for routes */
  40. static queue read_route_wpt_head;
  41. static short_handle read_route_wpt_mkshort_handle;
  42. #define MPSDEFAULTWPTCLASS 0
  43. #define MPSHIDDENROUTEWPTCLASS 8
  44. #define MYNAME "MAPSOURCE"
  45. #define ISME 0
  46. #define NOTME 1
  47. #define DEFAULTICONDESCR "Waypoint"
  48. #define DEFAULTICONVALUE 18
  49. #define MPSNAMEBUFFERLEN 1024
  50. #define MPSNOTESBUFFERLEN 4096
  51. #define MPSDESCBUFFERLEN 4096
  52. static char* snlen = NULL;
  53. static char* snwhiteopt = NULL;
  54. static char* mpsverout = NULL;
  55. static char* mpsmergeouts = NULL;
  56. static int mpsmergeout;
  57. static char* mpsusedepth = NULL;
  58. static char* mpsuseprox = NULL;
  59. static
  60. arglist_t mps_args[] = {
  61. {
  62. "snlen", &snlen, "Length of generated shortnames", "10", ARGTYPE_INT, "1",
  63. NULL, NULL
  64. },
  65. {
  66. "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames",
  67. NULL, ARGTYPE_BOOL, ARG_NOMINMAX, NULL
  68. },
  69. {
  70. "mpsverout", &mpsverout,
  71. "Version of mapsource file to generate (3,4,5)", NULL,
  72. ARGTYPE_INT, ARG_NOMINMAX, NULL
  73. },
  74. {
  75. "mpsmergeout", &mpsmergeouts, "Merge output with existing file",
  76. NULL, ARGTYPE_BOOL, ARG_NOMINMAX, NULL
  77. },
  78. {
  79. "mpsusedepth", &mpsusedepth,
  80. "Use depth values on output (default is ignore)", NULL,
  81. ARGTYPE_BOOL, ARG_NOMINMAX, NULL
  82. },
  83. {
  84. "mpsuseprox", &mpsuseprox,
  85. "Use proximity values on output (default is ignore)",
  86. NULL, ARGTYPE_BOOL, ARG_NOMINMAX, NULL
  87. },
  88. ARG_TERMINATOR
  89. };
  90. static void
  91. mps_noop(const route_head*)
  92. {
  93. /* no-op */
  94. }
  95. void
  96. mps_wpt_q_init(queue* whichQueue)
  97. {
  98. QUEUE_INIT(whichQueue);
  99. }
  100. void
  101. mps_wpt_q_deinit(queue* whichQueue)
  102. {
  103. queue* elem, *tmp;
  104. QUEUE_FOR_EACH(whichQueue, elem, tmp) {
  105. Waypoint* q = (Waypoint*) dequeue(elem);
  106. delete q;
  107. }
  108. }
  109. /*
  110. * Find a waypoint that we've already written out
  111. *
  112. */
  113. Waypoint*
  114. mps_find_wpt_q_by_name(const queue* whichQueue, const QString& name)
  115. {
  116. queue* elem, *tmp;
  117. Waypoint* waypointp;
  118. QUEUE_FOR_EACH(whichQueue, elem, tmp) {
  119. waypointp = (Waypoint*) elem;
  120. if (waypointp->shortname == name) {
  121. return waypointp;
  122. }
  123. }
  124. return NULL;
  125. }
  126. /*
  127. * Add a waypoint that we've already written out to our list
  128. *
  129. */
  130. void
  131. mps_wpt_q_add(const queue* whichQueue, const Waypoint* wpt)
  132. {
  133. Waypoint* written_wpt = new Waypoint(*wpt);
  134. ENQUEUE_TAIL(whichQueue, &written_wpt->Q);
  135. }
  136. static int
  137. mps_converted_icon_number(const int icon_num, const int mpsver, garmin_formats_e garmin_format)
  138. {
  139. int def_icon = DEFAULTICONVALUE;
  140. switch (garmin_format) {
  141. case MAPSOURCE:
  142. if (mpsver == 5) {
  143. return icon_num;
  144. }
  145. if (mpsver == 4) {
  146. /* Water hydrant */
  147. if (icon_num == 139) {
  148. return def_icon;
  149. } else {
  150. return icon_num;
  151. }
  152. } else {
  153. /* the Contact icons - V3 doesn't have anything like this */
  154. if ((icon_num >= 119) && (icon_num <= 138)) {
  155. return def_icon;
  156. }
  157. /* the Geocache icons - V3 use the Circle with X */
  158. if ((icon_num >= 117) && (icon_num <= 118)) {
  159. return 65;
  160. }
  161. /* Water hydrant */
  162. if (icon_num == 139) {
  163. return def_icon;
  164. }
  165. return icon_num;
  166. }
  167. case PCX:
  168. case GARMIN_SERIAL:
  169. if (mpsver == 5) {
  170. return icon_num;
  171. }
  172. if (mpsver == 4) {
  173. /* Water hydrant */
  174. if (icon_num == 8282) {
  175. return def_icon;
  176. } else {
  177. return icon_num;
  178. }
  179. }
  180. /* the Contact icons - V3 doesn't have anything like this */
  181. if ((icon_num >= 8257) && (icon_num <= 8276)) {
  182. return def_icon;
  183. }
  184. /* the Geocache icons - V3 use the Circle with X */
  185. if ((icon_num >= 8255) && (icon_num <= 8256)) {
  186. return 179;
  187. }
  188. /* Water hydrant */
  189. if (icon_num == 8282) {
  190. return def_icon;
  191. }
  192. return icon_num;
  193. default:
  194. fatal(MYNAME ": unknown garmin format.\n");
  195. }
  196. return def_icon;
  197. }
  198. static void
  199. mps_rd_init(const QString& fname)
  200. {
  201. mps_file_in = gbfopen_le(fname, "rb", MYNAME);
  202. read_route_wpt_mkshort_handle = mkshort_new_handle();
  203. /* initialise the "private" queue of waypoints read for routes */
  204. mps_wpt_q_init(&read_route_wpt_head);
  205. }
  206. static void
  207. mps_rd_deinit(void)
  208. {
  209. gbfclose(mps_file_in);
  210. if (read_route_wpt_mkshort_handle) {
  211. mkshort_del_handle(&read_route_wpt_mkshort_handle);
  212. }
  213. /* flush the "private" queue of waypoints read for routes */
  214. mps_wpt_q_deinit(&read_route_wpt_head);
  215. }
  216. static void
  217. mps_wr_init(const QString& fname)
  218. {
  219. fin_name = fname;
  220. if (mpsmergeouts) {
  221. mpsmergeout = atoi(mpsmergeouts);
  222. }
  223. if (mpsmergeout) {
  224. mps_file_out = gbfopen_le(fname, "rb", MYNAME);
  225. if (mps_file_out == NULL) {
  226. mpsmergeout = 0;
  227. } else {
  228. gbfclose(mps_file_out);
  229. srand((unsigned) current_time().toTime_t());
  230. for (;;) {
  231. /* create a temporary name based on a random char and the existing name */
  232. /* then test if it already exists, if so try again with another rand num */
  233. /* yeah, yeah, so there's probably a library function for this */
  234. tempname = QString("%1.%2").arg(fname).arg(rand(), 8, 16, QChar('0'));
  235. mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
  236. if (mps_file_temp == NULL) {
  237. break;
  238. }
  239. gbfclose(mps_file_temp);
  240. }
  241. QFile::rename(fname, tempname);
  242. mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
  243. }
  244. }
  245. mps_file_out = gbfopen_le(fname, "wb", MYNAME);
  246. written_wpt_mkshort_handle = mkshort_new_handle();
  247. /* initialise the "private" queue of waypoints written */
  248. mps_wpt_q_init(&written_wpt_head);
  249. mps_wpt_q_init(&written_route_wpt_head);
  250. }
  251. static void
  252. mps_wr_deinit(void)
  253. {
  254. gbfclose(mps_file_out);
  255. if (mpsmergeout) {
  256. gbfclose(mps_file_temp);
  257. QFile::remove(tempname);
  258. tempname.clear();
  259. }
  260. if (written_wpt_mkshort_handle) {
  261. mkshort_del_handle(&written_wpt_mkshort_handle);
  262. }
  263. /* flush the "private" queue of waypoints written */
  264. mps_wpt_q_deinit(&written_wpt_head);
  265. mps_wpt_q_deinit(&written_route_wpt_head);
  266. fin_name.clear();
  267. }
  268. /*
  269. * get characters until and including terminating NULL from mps_file_in
  270. * and write into buf.
  271. */
  272. static void
  273. mps_readstr(gbfile* mps_file, char* buf, size_t sz)
  274. {
  275. int c;
  276. while (sz-- && (c = gbfgetc(mps_file)) != EOF) {
  277. *buf++ = c;
  278. if (c == 0) {
  279. return;
  280. }
  281. }
  282. }
  283. /*
  284. * read in from file to check a) valid format b) version of data formating
  285. * MRCB
  286. */
  287. static void
  288. mps_fileHeader_r(gbfile* mps_file, int* mps_ver)
  289. {
  290. char hdr[100];
  291. int reclen;
  292. mps_readstr(mps_file, hdr, sizeof(hdr));
  293. if (strcmp(hdr, "MsRcd")) {
  294. fatal(MYNAME ": This doesn't look like a mapsource file.\n");
  295. }
  296. /* Read record length of "format details" section */
  297. reclen = gbfgetint32(mps_file);
  298. /* Read the "format details" in plus the trailing null */
  299. gbfread(hdr, 3, 1, mps_file);
  300. if (hdr[0] != 'D') {
  301. /* No flag for the "data" section */
  302. fatal(MYNAME ": This doesn't look like a mapsource file.\n");
  303. }
  304. if (hdr[1] == 'd') {
  305. *mps_ver = 3;
  306. } else if ((hdr[1] > 'd') && (hdr[1] <= 'h')) {
  307. *mps_ver = 4;
  308. } else if ((hdr[1] > 'h') && (hdr[1] <= 'i')) {
  309. *mps_ver = 5;
  310. } else {
  311. fatal(MYNAME ": Unsuppported version of mapsource file.\n");
  312. }
  313. /* Skip reliably over the "format details" section */
  314. gbfseek(mps_file, reclen+1-3, SEEK_CUR);
  315. /* Read record length of "program signature" section */
  316. reclen = gbfgetint32(mps_file);
  317. /* Skip reliably over the "program signature" section */
  318. if (reclen >= 0) {
  319. gbfseek(mps_file, reclen+1, SEEK_CUR);
  320. }
  321. }
  322. /*
  323. * write out to file
  324. * MRCB
  325. */
  326. static void
  327. mps_fileHeader_w(gbfile* mps_file, int mps_ver)
  328. {
  329. char hdr[100];
  330. int reclen;
  331. strcpy(hdr, "MsRc");
  332. gbfwrite(hdr, 4, 1, mps_file);
  333. /* Between versions 3 & 5 this value is 'd', but might change in the future */
  334. strcpy(hdr, "d");
  335. gbfwrite(hdr, 2, 1, mps_file); /* include trailing NULL char */
  336. /* Start of a "Data" section */
  337. hdr[0] = 'D';
  338. /* if (mps_ver == 3) */
  339. hdr[1] = 'd'; /* equates to V3.02 */
  340. if (mps_ver == 4) {
  341. hdr[1] = 'g'; /* equates to V4.06 */
  342. }
  343. if (mps_ver == 5) {
  344. hdr[1] = 'i'; /* equates to V5.0 */
  345. }
  346. hdr[2] = 0;
  347. reclen = 2; /* this is 3 byte record */
  348. gbfputint32(reclen, mps_file);
  349. gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
  350. hdr[0] = 'A';
  351. /* if (mps_ver == 3) */
  352. hdr[1] = 0x2E;
  353. hdr[2] = 0x01; /* equates to V3.02 */
  354. hdr[3] = 'S';
  355. hdr[4] = 'Q';
  356. hdr[5] = 'A';
  357. hdr[6] = 0;
  358. strcpy(hdr+7,"Oct 20 1999");
  359. strcpy(hdr+19,"12:50:33");
  360. if (mps_ver == 4) {
  361. hdr[1] = (char) 0x96; /* equates to V4.06 */
  362. strcpy(hdr+7,"Oct 22 2001");
  363. strcpy(hdr+19,"15:45:33");
  364. }
  365. if (mps_ver == 5) {
  366. hdr[1] = (char) 0xF4; /* equates to V5.0 */
  367. strcpy(hdr+7,"Jul 3 2003");
  368. strcpy(hdr+19,"08:35:33");
  369. }
  370. reclen = 27; /* pre measured! */
  371. gbfputint32(reclen, mps_file);
  372. gbfwrite(hdr, 28, 1, mps_file); /* reclen + 1 - can't use this as reclen may be wrongendian now */
  373. }
  374. /*
  375. * read in from file a map segment record
  376. * MRCB
  377. */
  378. static void
  379. mps_mapsegment_r(gbfile* mps_file, int mps_ver)
  380. {
  381. int reclen;
  382. (void)mps_ver;
  383. #if 0
  384. /* At the moment we're not doing anything with map segments, but here's the template code as if we were */
  385. char hdr[100];
  386. gbfread(&CDid, 4, 1, mps_file);
  387. reclen = le_read32(&CDid);
  388. gbfread(&CDSegmentid, 4, 1, mps_file);
  389. reclen = le_read32(&CDSegmentid);
  390. mps_readstr(mps_file, CDName, sizeof(CDName));
  391. mps_readstr(mps_file, CDSegmentName, sizeof(CDSegmentName));
  392. mps_readstr(mps_file, CDAreaName, sizeof(CDAreaName));
  393. gbfread(hdr, 4, 1, mps_file); /* trailing long value */
  394. #endif
  395. gbfseek(mps_file, -5, SEEK_CUR);
  396. reclen = gbfgetint32(mps_file);
  397. if (reclen >= 0) {
  398. gbfseek(mps_file, reclen+1, SEEK_CUR);
  399. }
  400. return;
  401. }
  402. /*
  403. * read in from file a mapsetname record
  404. * there should always be one of these at the end of the file
  405. * MRCB
  406. */
  407. static void
  408. mps_mapsetname_r(gbfile* mps_file, int mps_ver)
  409. {
  410. int reclen;
  411. (void)mps_ver;
  412. /* At the moment we're not doing anything with mapsetnames, but here's the template code as if we were
  413. char hdr[100];
  414. mps_readstr(mps_file, hdr, sizeof(hdr));
  415. char mapsetnamename[very large number?];
  416. strcpy(mapsetnamename,hdr);
  417. char mapsetnameAutonameFlag;
  418. gbfread(&mapsetnameAutonameFlag, 1, 1, mps_file); */
  419. gbfseek(mps_file, -5, SEEK_CUR);
  420. reclen = gbfgetint32(mps_file);
  421. gbfseek(mps_file, reclen+1, SEEK_CUR);
  422. return;
  423. }
  424. /*
  425. * write out to file a mapsetname record
  426. * there should always be one of these at the end of the file
  427. * MRCB
  428. */
  429. static void
  430. mps_mapsetname_w(gbfile* mps_file, int mps_ver)
  431. {
  432. char hdr[100];
  433. int reclen;
  434. (void)mps_ver;
  435. hdr[0] = 'V'; /* mapsetname start of record indicator */
  436. hdr[1] = 0; /* zero length null terminated string */
  437. hdr[2] = 1; /* mapsetname autoname flag set to DO autoname */
  438. reclen = 2; /* three bytes of the V record */
  439. gbfputint32(reclen, mps_file);
  440. gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
  441. }
  442. /*
  443. * read in from file a waypoint record
  444. * MRCB
  445. */
  446. static void
  447. mps_waypoint_r(gbfile* mps_file, int mps_ver, Waypoint** wpt, unsigned int* mpsclass)
  448. {
  449. char tbuf[100];
  450. char wptname[MPSNAMEBUFFERLEN];
  451. int lat;
  452. int lon;
  453. int icon;
  454. Waypoint* thisWaypoint = NULL;
  455. double mps_altitude = unknown_alt;
  456. double mps_proximity = unknown_alt;
  457. double mps_depth = unknown_alt;
  458. thisWaypoint = new Waypoint;
  459. *wpt = thisWaypoint;
  460. mps_readstr(mps_file, wptname, sizeof(wptname));
  461. (*mpsclass) = gbfgetint32(mps_file); /* class */
  462. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
  463. gbfread(tbuf,17, 1, mps_file); /* subclass data (17) */
  464. if ((mps_ver == 4) || (mps_ver == 5)) {
  465. gbfread(tbuf, 5, 1, mps_file); /* additional subclass data (1) & terminator? (4) */
  466. }
  467. lat = gbfgetint32(mps_file);
  468. lon = gbfgetint32(mps_file);
  469. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  470. mps_altitude = gbfgetdbl(mps_file);
  471. } else {
  472. mps_altitude = unknown_alt;
  473. gbfseek(mps_file, 8, SEEK_CUR);
  474. }
  475. QString wptdesc = gbfgetcstr(mps_file);
  476. if (gbfgetc(mps_file) == 1) { /* proximity validity */
  477. mps_proximity = gbfgetdbl(mps_file);
  478. } else {
  479. mps_proximity = unknown_alt;
  480. gbfseek(mps_file, 8, SEEK_CUR);
  481. }
  482. (void) gbfgetint32(mps_file); /* display flag */
  483. (void) gbfgetint32(mps_file); /* colour */
  484. icon = gbfgetint32(mps_file); /* display symbol */
  485. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* city */
  486. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* state */
  487. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /*facility */
  488. gbfread(tbuf, 1, 1, mps_file); /* unknown */
  489. if (gbfgetc(mps_file) == 1) { /* depth validity */
  490. mps_depth = gbfgetdbl(mps_file);
  491. } else {
  492. mps_depth = unknown_alt;
  493. (void) gbfseek(mps_file, 8, SEEK_CUR);
  494. }
  495. if ((mps_ver == 4) || (mps_ver == 5)) {
  496. gbfread(tbuf, 6, 1, mps_file); /* unknown */
  497. thisWaypoint->notes = gbfgetcstr(mps_file);
  498. } else {
  499. gbfread(tbuf, 2, 1, mps_file); /* unknown */
  500. }
  501. thisWaypoint->shortname = wptname;
  502. thisWaypoint->description = wptdesc;
  503. thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
  504. thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
  505. thisWaypoint->altitude = mps_altitude;
  506. if (mps_proximity != unknown_alt) {
  507. WAYPT_SET(thisWaypoint, proximity, mps_proximity);
  508. }
  509. if (mps_depth != unknown_alt) {
  510. WAYPT_SET(thisWaypoint, depth, mps_depth);
  511. }
  512. /* might need to change this to handle version dependent icon handling */
  513. thisWaypoint->icon_descr = gt_find_desc_from_icon_number(icon, MAPSOURCE);
  514. /* The following Now done elsewhere since it can be useful to read in and
  515. perhaps not add to the list */
  516. /* waypt_add(thisWaypoint); */
  517. return;
  518. }
  519. /*
  520. * write out to file a waypoint record
  521. * MRCB
  522. */
  523. static void
  524. mps_waypoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt, const int isRouteWpt)
  525. {
  526. int reclen;
  527. int lat, lon;
  528. int icon;
  529. char* ascii_description;
  530. char zbuf[25];
  531. char ffbuf[25];
  532. int display = 1;
  533. int colour = 0; /* (unknown colour) black is 1, white is 16 */
  534. double mps_altitude = wpt->altitude;
  535. double mps_proximity = (mpsuseprox ? WAYPT_GET(wpt, proximity, unknown_alt) : unknown_alt);
  536. double mps_depth = unknown_alt;
  537. lat = GPS_Math_Deg_To_Semi(wpt->latitude);
  538. lon = GPS_Math_Deg_To_Semi(wpt->longitude);
  539. if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
  540. mps_depth = wpt->depth;
  541. }
  542. QString src;
  543. if (!wpt->description.isEmpty()) {
  544. src = wpt->description;
  545. }
  546. if (!wpt->notes.isEmpty()) {
  547. src = wpt->notes;
  548. }
  549. QString ident = global_opts.synthesize_shortnames ?
  550. mkshort(mkshort_handle, src) :
  551. CSTRc(wpt->shortname);
  552. memset(zbuf, 0, sizeof(zbuf));
  553. memset(ffbuf, 0xff, sizeof(ffbuf));
  554. /* might need to change this to handle version dependent icon handling */
  555. icon = gt_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE);
  556. if (get_cache_icon(wpt)) {
  557. icon = gt_find_icon_number_from_desc(get_cache_icon(wpt), MAPSOURCE);
  558. }
  559. icon = mps_converted_icon_number(icon, mps_ver, MAPSOURCE);
  560. /* two NULL (0x0) bytes at end of each string */
  561. ascii_description = xstrdup(wpt->description);
  562. reclen = ident.length() + strlen(ascii_description) + 2;
  563. if ((mps_ver == 4) || (mps_ver == 5)) {
  564. /* v4.06 & V5.0*/
  565. reclen += 85; /* "W" (1) + strlen(name) + NULL (1) + class(4) + country(sz) +
  566. subclass(18) + unknown(4) + lat(4) + lon(4) + alt(9) + strlen(desc)
  567. + NULL (1) + prox(9) + display(4) + colour(4) + symbol(4) + city(sz) +
  568. state(sz) + facility(sz) + unknown2(1) + depth(9) + unknown3(7) */
  569. /* -1 as reclen is interpreted from zero meaning a reclength of one */
  570. if (!wpt->notes.isEmpty()) {
  571. reclen += strlen(CSTRc(wpt->notes));
  572. }
  573. } else {
  574. /* v3.02 */
  575. reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + + class(4) + country(sz) +
  576. subclass(17) + lat(4) + lon(4) + alt(9) + strlen(desc) +
  577. NULL (1) + prox(9) + display(4) +
  578. colour(4) + symbol(4) + city(sz) + state(sz) + facility(sz) +
  579. unknown2(1) + depth(9) + unknown3(2) */
  580. /* -1 as reclen is interpreted from zero meaning a reclength of one */
  581. }
  582. gbfputint32(reclen, mps_file);
  583. gbfwrite("W", 1, 1, mps_file);
  584. gbfputs(ident, mps_file);
  585. gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
  586. if (isRouteWpt) {
  587. zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
  588. } else {
  589. zbuf[0] = (char)MPSDEFAULTWPTCLASS;
  590. }
  591. gbfwrite(zbuf, 4, 1, mps_file); /* class */
  592. zbuf[0]=0;
  593. gbfwrite(zbuf, 1, 1, mps_file); /* country empty string */
  594. if ((mps_ver == 4) || (mps_ver == 5)) {
  595. gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
  596. gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
  597. gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
  598. gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
  599. } else {
  600. gbfwrite(zbuf, 8, 1, mps_file);
  601. gbfwrite(ffbuf, 8, 1, mps_file);
  602. gbfwrite(zbuf, 1, 1, mps_file);
  603. }
  604. gbfputint32(lat, mps_file);
  605. gbfputint32(lon, mps_file);
  606. if (mps_altitude == unknown_alt) {
  607. gbfwrite(zbuf, 9, 1, mps_file);
  608. } else {
  609. gbfputc(1, mps_file);
  610. gbfputdbl(mps_altitude, mps_file);
  611. }
  612. if (!wpt->description.isEmpty()) {
  613. gbfputs(ascii_description, mps_file);
  614. }
  615. gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination */
  616. xfree(ascii_description);
  617. ascii_description = NULL;
  618. if (mps_proximity == unknown_alt) {
  619. gbfwrite(zbuf, 9, 1, mps_file);
  620. } else {
  621. gbfputc(1, mps_file);
  622. gbfputdbl(mps_proximity, mps_file);
  623. }
  624. gbfputint32(display, mps_file); /* Show waypoint w/ name */
  625. gbfputint32(colour, mps_file);
  626. gbfputint32(icon, mps_file);
  627. gbfwrite(zbuf, 3, 1, mps_file); /* city, state, facility */
  628. gbfwrite(zbuf, 1, 1, mps_file); /* unknown */
  629. if (mps_depth == unknown_alt) {
  630. gbfwrite(zbuf, 9, 1, mps_file);
  631. } else {
  632. gbfputc(1, mps_file);
  633. gbfputdbl(mps_depth, mps_file);
  634. }
  635. gbfwrite(zbuf, 2, 1, mps_file); /* unknown */
  636. if ((mps_ver == 4) || (mps_ver == 5)) {
  637. gbfwrite(zbuf, 4, 1, mps_file); /* unknown */
  638. if (!wpt->notes.isEmpty()) {
  639. gbfputs(wpt->notes, mps_file);
  640. }
  641. gbfwrite(zbuf, 1, 1, mps_file); /* string termination */
  642. }
  643. }
  644. /*
  645. * wrapper to include the mps_ver_out information
  646. * A waypoint is only written if it hasn't been written before
  647. * based on it shortname alone
  648. *
  649. */
  650. static void
  651. mps_waypoint_w_unique_wrapper(const Waypoint* wpt)
  652. {
  653. Waypoint* wptfound = NULL;
  654. /* Search for this waypoint in the ones already written */
  655. wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
  656. /* is the next line necessary? Assumes we know who's called us and in what order */
  657. if (wptfound == NULL) {
  658. wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
  659. }
  660. /* if this waypoint hasn't been written then it is okay to do so */
  661. if (wptfound == NULL) {
  662. mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
  663. /* ensure we record in our "private" queue what has been
  664. written so that we don't write it again */
  665. mps_wpt_q_add(&written_wpt_head, wpt);
  666. }
  667. }
  668. /*
  669. * wrapper to include the mps_ver_out information
  670. * A waypoint is only written if it hasn't been written before
  671. * based on it shortname alone
  672. * Provided as a separate function from above in case we find
  673. * have to do other things
  674. *
  675. */
  676. static void
  677. mps_route_wpt_w_unique_wrapper(const Waypoint* wpt)
  678. {
  679. Waypoint* wptfound = NULL;
  680. /* Search for this waypoint in the ones already written */
  681. wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
  682. if (wptfound == NULL)
  683. /* so, not a real wpt, so must check route wpts already written as reals */
  684. {
  685. wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
  686. }
  687. /* if this waypoint hasn't been written then it is okay to do so
  688. but assume it is only required for the route
  689. */
  690. if (wptfound == NULL) {
  691. /* Although we haven't written one out, this might still be a "real" waypoint
  692. If so, we need to write it out now accordingly */
  693. wptfound = find_waypt_by_name(wpt->shortname);
  694. if (wptfound == NULL) {
  695. /* well, we tried to find: it wasn't written and isn't a real waypoint */
  696. mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==1));
  697. mps_wpt_q_add(&written_route_wpt_head, wpt);
  698. } else {
  699. mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
  700. /* Simulated real user waypoint */
  701. mps_wpt_q_add(&written_wpt_head, wpt);
  702. }
  703. }
  704. }
  705. #if 0
  706. /*
  707. * wrapper to include the mps_ver_out information
  708. * This one always writes a waypoint. If it has been written before
  709. * then generate a unique name before writing
  710. *
  711. */
  712. static void
  713. mps_waypoint_w_uniqloc_wrapper(Waypoint* wpt)
  714. {
  715. Waypoint* wptfound = NULL;
  716. char* newName;
  717. /* Search for this waypoint in the ones already written */
  718. wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
  719. /* is the next line necessary? Assumes we know who's called us and in what order */
  720. if (wptfound == NULL) {
  721. wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
  722. }
  723. if (wptfound != NULL) {
  724. /* check if this is the same waypoint by looking at the lat lon
  725. not ideal, but better then having two same named waypoints
  726. that kills MapSource. If it is the same then don't bother
  727. adding it in. If it isn't, then rename it
  728. */
  729. if (((wpt->latitude - wptfound->latitude) != 0) ||
  730. ((wpt->longitude - wptfound->longitude) != 0)) {
  731. /* Not the same lat lon, so rename and add */
  732. newName = mkshort(written_wpt_mkshort_handle, wpt->shortname);
  733. wptfound = new Waypoint(*wpt);
  734. xfree(wptfound->shortname);
  735. wptfound->shortname = newName;
  736. mps_waypoint_w(mps_file_out, mps_ver_out, wptfound, (1==0));
  737. mps_wpt_q_add(&written_wpt_head, wpt);
  738. }
  739. } else {
  740. mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
  741. /* ensure we record in out "private" queue what has been
  742. written so that we don't write it again */
  743. mps_wpt_q_add(&written_wpt_head, wpt);
  744. }
  745. }
  746. #endif
  747. /*
  748. * read in from file a route record
  749. * MRCB
  750. */
  751. static void
  752. mps_route_r(gbfile* mps_file, int mps_ver, route_head** rte)
  753. {
  754. char tbuf[100];
  755. char wptname[MPSNAMEBUFFERLEN];
  756. int lat = 0;
  757. int lon = 0;
  758. char rte_autoname;
  759. int interlinkStepCount;
  760. int thisInterlinkStep;
  761. unsigned int mpsclass;
  762. route_head* rte_head;
  763. int rte_count;
  764. Waypoint* thisWaypoint;
  765. Waypoint* tempWpt;
  766. double mps_altitude = unknown_alt;
  767. double mps_depth = unknown_alt;
  768. QString rtename = gbfgetcstr(mps_file);
  769. #ifdef MPS_DEBUG
  770. fprintf(stderr, "mps_route_r: reading route %s\n", rtename);
  771. #endif
  772. gbfread(&rte_autoname, 1, 1, mps_file); /* autoname flag */
  773. gbfread(tbuf, 1, 1, mps_file); /* skip min/max values */
  774. if (tbuf[0] == 0) {
  775. lat = gbfgetint32(mps_file); /* max lat of whole route */
  776. lon = gbfgetint32(mps_file); /* max lon of whole route */
  777. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  778. mps_altitude = gbfgetdbl(mps_file);
  779. } else {
  780. mps_altitude = unknown_alt;
  781. gbfseek(mps_file, 8, SEEK_CUR);
  782. }
  783. lat = gbfgetint32(mps_file); /* min lat of whole route */
  784. lon = gbfgetint32(mps_file); /* min lon of whole route */
  785. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  786. mps_altitude = gbfgetdbl(mps_file);
  787. } else {
  788. mps_altitude = unknown_alt;
  789. gbfseek(mps_file, 8, SEEK_CUR);
  790. }
  791. }
  792. rte_count = gbfgetint32(mps_file); /* number of waypoints in route */
  793. /* This might be rather presumptuous, but is it valid in any format to have route with no points? */
  794. /* Let's assume not, so if the route count is zero or less, let's get out of here and allow the */
  795. /* caller to do any file resync */
  796. if (rte_count < 0) {
  797. return;
  798. }
  799. #ifdef MPS_DEBUG
  800. fprintf(stderr, "mps_route_r: route contains %d waypoints\n", rte_count);
  801. #endif
  802. rte_head = route_head_alloc();
  803. rte_head->rte_name = rtename;
  804. route_add_head(rte_head);
  805. *rte = rte_head;
  806. rte_count--; /* need to loop round for one less than the number of waypoints */
  807. while (rte_count--) {
  808. mps_readstr(mps_file, wptname, sizeof(wptname));
  809. #ifdef MPS_DEBUG
  810. fprintf(stderr, "mps_route_r: reading route waypoint %s\n", wptname);
  811. #endif
  812. mpsclass = gbfgetint32(mps_file); /* class */
  813. (void)mpsclass;
  814. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
  815. if ((mps_ver == 4) || (mps_ver == 5)) {
  816. gbfread(tbuf, 22, 1, mps_file); /* subclass data */
  817. /* This is a bit unpleasant. Routes have a variable length of
  818. data (min 22 bytes) terminated by a zero */
  819. do {
  820. gbfread(tbuf, 1, 1, mps_file);
  821. } while (tbuf[0]);
  822. /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
  823. gbfread(tbuf, 18, 1, mps_file);
  824. } else {
  825. gbfread(tbuf, 17, 1, mps_file); /* subclass data */
  826. gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
  827. }
  828. /* link details */
  829. interlinkStepCount = gbfgetint32(mps_file); /* NOT always 2, but will assume > 0 */
  830. #ifdef MPS_DEBUG
  831. fprintf(stderr, "mps_route_r: interlink steps are %d\n", interlinkStepCount);
  832. #endif
  833. /* Basically we're knackered if the step count is less than one since we hard code reading of the */
  834. /* first, so if there isn't one, we'd lose sync on the file and read junk */
  835. /* Given we've already done some route head allocation, do we return or do we die? It'd be good */
  836. /* do some clean up before returning. */
  837. if (interlinkStepCount < 1) {
  838. /* For RJL - are the following lines correct ? */
  839. /* route_free(rte_head);
  840. route_del_head(rte_head); */
  841. return;
  842. }
  843. /* first end of link */
  844. lat = gbfgetint32(mps_file);
  845. lon = gbfgetint32(mps_file);
  846. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  847. mps_altitude = gbfgetdbl(mps_file);
  848. } else {
  849. mps_altitude = unknown_alt;
  850. gbfseek(mps_file, 8, SEEK_CUR);
  851. }
  852. /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
  853. if found. With MapSource, one should consider the real waypoint list as definitive */
  854. tempWpt = find_waypt_by_name(wptname);
  855. if (tempWpt != NULL) {
  856. thisWaypoint = new Waypoint(*tempWpt);
  857. } else {
  858. tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
  859. if (tempWpt != NULL) {
  860. thisWaypoint = new Waypoint(*tempWpt);
  861. } else {
  862. /* should never reach here, but we do need a fallback position */
  863. #ifdef MPS_DEBUG
  864. fprintf(stderr, "mps_route_r: reached the point we never should\n");
  865. #endif
  866. thisWaypoint = new Waypoint;
  867. thisWaypoint->shortname = wptname;
  868. thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
  869. thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
  870. thisWaypoint->altitude = mps_altitude;
  871. if (mps_depth != unknown_alt) {
  872. WAYPT_SET(thisWaypoint, depth, mps_depth);
  873. }
  874. }
  875. }
  876. route_add_wpt(rte_head, thisWaypoint);
  877. /* take two off the count since we separately read the start and end parts of the link */
  878. /* MRCB 2004/09/15 - NOPE, sorry, this needs to one, since interlink steps can be > 0 */
  879. for (thisInterlinkStep = interlinkStepCount - 1; thisInterlinkStep > 0; thisInterlinkStep--) {
  880. /* Could do this by doing a calculation on length of each co-ordinate and just doing one read
  881. but doing it this way makes it easier in the future to make use of this data */
  882. lat = gbfgetint32(mps_file);
  883. lon = gbfgetint32(mps_file);
  884. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  885. mps_altitude = gbfgetdbl(mps_file);
  886. } else {
  887. mps_altitude = unknown_alt;
  888. gbfseek(mps_file, 8, SEEK_CUR);
  889. }
  890. }
  891. gbfread(tbuf, 1, 1, mps_file); /* NULL */
  892. gbfread(tbuf, 4, 1, mps_file); /* link max lat */
  893. gbfread(tbuf, 4, 1, mps_file); /* link max lon */
  894. gbfread(tbuf, 9, 1, mps_file); /* link max alt validity + alt */
  895. gbfread(tbuf, 4, 1, mps_file); /* link min lat */
  896. gbfread(tbuf, 4, 1, mps_file); /* link min lon */
  897. gbfread(tbuf, 9, 1, mps_file); /* link min alt validity + alt */
  898. } /* while (trk_count--) */
  899. /* when the loop is done, there's still one waypoint to read with a small trailer */
  900. /* all we want is the waypoint name; lat, lon and alt are already set from above */
  901. mps_readstr(mps_file, wptname, sizeof(wptname));
  902. #ifdef MPS_DEBUG
  903. fprintf(stderr, "mps_route_r: reading final route waypoint %s\n", wptname);
  904. #endif
  905. mpsclass = gbfgetint32(mps_file); /* class */
  906. mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
  907. if ((mps_ver == 4) || (mps_ver == 5)) {
  908. gbfread(tbuf, 22, 1, mps_file); /* subclass data */
  909. /* This is a bit unpleasant. Routes have a variable length of
  910. data (min 22 bytes) terminated by a zero */
  911. do {
  912. gbfread(tbuf, 1, 1, mps_file);
  913. } while (tbuf[0]);
  914. /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
  915. gbfread(tbuf, 18, 1, mps_file);
  916. } else {
  917. gbfread(tbuf, 17, 1, mps_file); /* subclass data */
  918. gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
  919. }
  920. gbfread(tbuf, 5, 1, mps_file); /* 5 byte trailer */
  921. /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
  922. if found because there is more info held in a real waypoint than in its route counterpart,
  923. e.g. the display symbol (aka icon)
  924. */
  925. tempWpt = find_waypt_by_name(wptname);
  926. if (tempWpt != NULL) {
  927. thisWaypoint = new Waypoint(*tempWpt);
  928. } else {
  929. tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
  930. if (tempWpt != NULL) {
  931. thisWaypoint = new Waypoint(*tempWpt);
  932. } else {
  933. /* should never reach here, but we do need a fallback position */
  934. thisWaypoint = new Waypoint;
  935. thisWaypoint->shortname = wptname;
  936. thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
  937. thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
  938. thisWaypoint->altitude = mps_altitude;
  939. }
  940. }
  941. route_add_wpt(rte_head, thisWaypoint);
  942. return;
  943. }
  944. /*
  945. * write out to file a route header
  946. * MRCB
  947. */
  948. static void
  949. mps_routehdr_w(gbfile* mps_file, int mps_ver, const route_head* rte)
  950. {
  951. unsigned int reclen;
  952. unsigned int rte_datapoints;
  953. int rname_len;
  954. char* rname;
  955. char hdr[20];
  956. char zbuf[20];
  957. Waypoint* testwpt;
  958. time_t uniqueValue = 0;
  959. int allWptNameLengths;
  960. double maxlat=-90.0;
  961. double maxlon=-180.0;
  962. double minlat=90.0;
  963. double minlon=180.0;
  964. double maxalt=unknown_alt;
  965. double minalt=-unknown_alt;
  966. int lat;
  967. int lon;
  968. queue* elem, *tmp;
  969. prevRouteWpt = NULL; /* clear the stateful flag used to know when the start of route wpts happens */
  970. memset(zbuf, 0, sizeof(zbuf));
  971. /* total nodes (waypoints) this route */
  972. rte_datapoints = 0;
  973. allWptNameLengths = 0;
  974. if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
  975. QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) {
  976. testwpt = (Waypoint*)elem;
  977. if (rte_datapoints == 0) {
  978. uniqueValue = testwpt->GetCreationTime().toTime_t();
  979. }
  980. if (testwpt->latitude > maxlat) {
  981. maxlat = testwpt->latitude;
  982. }
  983. if (testwpt->latitude < minlat) {
  984. minlat = testwpt->latitude;
  985. }
  986. if (testwpt->longitude > maxlon) {
  987. maxlon = testwpt->longitude;
  988. }
  989. if (testwpt->longitude < minlon) {
  990. minlon = testwpt->longitude;
  991. }
  992. if (testwpt->altitude != unknown_alt) {
  993. if ((testwpt->altitude > maxalt) ||
  994. (maxalt == unknown_alt)) {
  995. maxalt = testwpt->altitude;
  996. }
  997. if ((testwpt->altitude < minalt) ||
  998. (minalt == -unknown_alt)) {
  999. minalt = testwpt->altitude;
  1000. }
  1001. }
  1002. QString src;
  1003. if (!testwpt->description.isEmpty()) {
  1004. src = testwpt->description;
  1005. }
  1006. if (!testwpt->notes.isEmpty()) {
  1007. src = testwpt->notes;
  1008. }
  1009. QString ident = global_opts.synthesize_shortnames ?
  1010. mkshort(mkshort_handle, src) :
  1011. CSTRc(testwpt->shortname);
  1012. allWptNameLengths += ident.length() + 1;
  1013. rte_datapoints++;
  1014. }
  1015. if (uniqueValue == 0) {
  1016. uniqueValue = current_time().toTime_t();
  1017. }
  1018. /* route name */
  1019. if (rte->rte_name.isEmpty()) {
  1020. sprintf(hdr, "Route%04x", (unsigned) uniqueValue);
  1021. rname = xstrdup(hdr);
  1022. } else {
  1023. rname = xstrdup(rte->rte_name);
  1024. }
  1025. rname_len = strlen(rname);
  1026. reclen = rname_len + 42; /* "T" (1) + strlen(tname) + NULL (1) + autoname flag (2) +
  1027. route lat lon max (2x4) + route max alt (9) +
  1028. route lat lon min (2x4) + route min alt (9) +
  1029. num route datapoints value (4) */
  1030. /* V3 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
  1031. subclass (17) + unknown (18) */
  1032. /* V4,5 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
  1033. subclass (18) + unknown (4) + unknown (19) */
  1034. /* V* - each route link: 0x00000002 (4) + end 1 lat (4) + end 1 lon (4) + end 1 alt (9) +
  1035. end 2 lat (4) + end 2 lon (4) + end 2 alt (9) + NULL (1) +
  1036. link max lat (4) + link max lon (4) + link max alt (9) +
  1037. link min lat (4) + link min lon (4) + link min alt (9) */
  1038. if ((mps_ver == 4) || (mps_ver == 5)) {
  1039. reclen += allWptNameLengths + rte_datapoints * 46 +
  1040. (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
  1041. } else {
  1042. reclen += allWptNameLengths + rte_datapoints * 40 +
  1043. (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
  1044. }
  1045. gbfputint32(reclen, mps_file);
  1046. gbfputc('R', mps_file);
  1047. gbfwrite(rname, 1, rname_len, mps_file);
  1048. xfree(rname);
  1049. hdr[0] = 0; /* NULL of string termination */
  1050. hdr[1] = 0; /* don't autoname */
  1051. hdr[2] = 0; /* MSB of don't autoname */
  1052. gbfwrite(hdr, 3, 1, mps_file); /* NULL string terminator + route autoname flag */
  1053. lat = GPS_Math_Deg_To_Semi(maxlat);
  1054. lon = GPS_Math_Deg_To_Semi(maxlon);
  1055. gbfputint32(lat, mps_file);
  1056. gbfputint32(lon, mps_file);
  1057. if (maxalt == unknown_alt) {
  1058. gbfwrite(zbuf, 9, 1, mps_file);
  1059. } else {
  1060. gbfputc(1, mps_file);
  1061. gbfputdbl(maxalt, mps_file);
  1062. }
  1063. lat = GPS_Math_Deg_To_Semi(minlat);
  1064. lon = GPS_Math_Deg_To_Semi(minlon);
  1065. gbfputint32(lat, mps_file);
  1066. gbfputint32(lon, mps_file);
  1067. if (minalt == -unknown_alt) {
  1068. gbfwrite(zbuf, 9, 1, mps_file);
  1069. } else {
  1070. gbfputc(1, mps_file);
  1071. gbfputdbl(minalt, mps_file);
  1072. }
  1073. gbfputint32(rte_datapoints, mps_file);
  1074. }
  1075. }
  1076. static void
  1077. mps_routehdr_w_wrapper(const route_head* rte)
  1078. {
  1079. mps_routehdr_w(mps_file_out, mps_ver_out, rte);
  1080. }
  1081. /*
  1082. * write out to file a route datapoint
  1083. * MRCB
  1084. */
  1085. static void
  1086. mps_routedatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* rtewpt)
  1087. {
  1088. int lat;
  1089. int lon;
  1090. char zbuf[20];
  1091. char ffbuf[20];
  1092. int reclen;
  1093. int maxlat;
  1094. int maxlon;
  1095. int minlat;
  1096. int minlon;
  1097. double maxalt=unknown_alt;
  1098. double minalt=-unknown_alt;
  1099. double mps_altitude;
  1100. Waypoint* wptfound;
  1101. memset(zbuf, 0, sizeof(zbuf));
  1102. memset(ffbuf, 0xff, sizeof(ffbuf));
  1103. if (prevRouteWpt != NULL) {
  1104. /* output the route link details */
  1105. reclen = 2;
  1106. gbfputint32(reclen, mps_file);
  1107. /* output end point 1 */
  1108. lat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
  1109. lon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
  1110. gbfputint32(lat, mps_file);
  1111. gbfputint32(lon, mps_file);
  1112. mps_altitude = prevRouteWpt->altitude;
  1113. if (mps_altitude == unknown_alt) {
  1114. gbfwrite(zbuf, 9, 1, mps_file);
  1115. } else {
  1116. gbfputc(1, mps_file);
  1117. gbfputdbl(mps_altitude, mps_file);
  1118. }
  1119. /* output end point 2 */
  1120. lat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
  1121. lon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
  1122. gbfputint32(lat, mps_file);
  1123. gbfputint32(lon, mps_file);
  1124. mps_altitude = rtewpt->altitude;
  1125. if (mps_altitude == unknown_alt) {
  1126. gbfwrite(zbuf, 9, 1, mps_file);
  1127. } else {
  1128. gbfputc(1, mps_file);
  1129. gbfputdbl(mps_altitude, mps_file);
  1130. }
  1131. if (rtewpt->latitude > prevRouteWpt->latitude) {
  1132. maxlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
  1133. minlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
  1134. } else {
  1135. minlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
  1136. maxlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
  1137. }
  1138. if (rtewpt->longitude > prevRouteWpt->longitude) {
  1139. maxlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
  1140. minlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
  1141. } else {
  1142. minlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
  1143. maxlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
  1144. }
  1145. if (rtewpt->altitude != unknown_alt) {
  1146. maxalt = rtewpt->altitude;
  1147. }
  1148. if (rtewpt->altitude != unknown_alt) {
  1149. minalt = rtewpt->altitude;
  1150. }
  1151. if (prevRouteWpt->altitude != unknown_alt) {
  1152. if ((prevRouteWpt->altitude > maxalt) ||
  1153. (maxalt == unknown_alt)) {
  1154. maxalt = prevRouteWpt->altitude;
  1155. }
  1156. if ((prevRouteWpt->altitude < minalt) ||
  1157. (minalt == -unknown_alt)) {
  1158. minalt = prevRouteWpt->altitude;
  1159. }
  1160. }
  1161. gbfwrite(zbuf, 1, 1, mps_file);
  1162. /* output max coords of the link */
  1163. gbfputint32(maxlat, mps_file);
  1164. gbfputint32(maxlon, mps_file);
  1165. if (maxalt == unknown_alt) {
  1166. gbfwrite(zbuf, 9, 1, mps_file);
  1167. } else {
  1168. gbfputc(1, mps_file);
  1169. gbfputdbl(maxalt, mps_file);
  1170. }
  1171. /* output min coords of the link */
  1172. gbfputint32(minlat, mps_file);
  1173. gbfputint32(minlon, mps_file);
  1174. if (minalt == -unknown_alt) {
  1175. gbfwrite(zbuf, 9, 1, mps_file);
  1176. } else {
  1177. gbfputc(1, mps_file);
  1178. gbfputdbl(minalt, mps_file);
  1179. }
  1180. }
  1181. QString src;
  1182. if (!rtewpt->description.isEmpty()) {
  1183. src = rtewpt->description;
  1184. }
  1185. if (!rtewpt->notes.isEmpty()) {
  1186. src = rtewpt->notes;
  1187. }
  1188. QString ident = global_opts.synthesize_shortnames ?
  1189. mkshort(mkshort_handle, src) :
  1190. CSTRc(rtewpt->shortname);
  1191. gbfputs(ident, mps_file);
  1192. gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
  1193. wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, ident);
  1194. if (wptfound != NULL) {
  1195. zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
  1196. } else {
  1197. zbuf[0] = (char)MPSDEFAULTWPTCLASS;
  1198. }
  1199. gbfwrite(zbuf, 4, 1, mps_file); /* class */
  1200. zbuf[0]=0;
  1201. gbfwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */
  1202. if ((mps_ver == 4) || (mps_ver == 5)) {
  1203. gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
  1204. gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
  1205. gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
  1206. gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
  1207. gbfwrite(zbuf, 1, 1, mps_file);
  1208. gbfputc(3, mps_file);
  1209. gbfwrite(zbuf, 17, 1, mps_file);
  1210. } else {
  1211. gbfwrite(zbuf, 8, 1, mps_file); /* subclass part 1 */
  1212. gbfwrite(ffbuf, 8, 1, mps_file); /* subclass part 2 */
  1213. gbfwrite(zbuf, 1, 1, mps_file); /* subclass part 3 */
  1214. /* unknown */
  1215. gbfwrite(zbuf, 1, 1, mps_file);
  1216. gbfputc(3, mps_file);
  1217. gbfwrite(zbuf, 16, 1, mps_file);
  1218. }
  1219. prevRouteWpt = rtewpt;
  1220. }
  1221. static void
  1222. mps_routedatapoint_w_wrapper(const Waypoint* rte)
  1223. {
  1224. mps_routedatapoint_w(mps_file_out, mps_ver_out, rte);
  1225. }
  1226. /*
  1227. * write out to file a route trailer
  1228. * MRCB
  1229. */
  1230. static void
  1231. mps_routetrlr_w(gbfile* mps_file, int mps_ver, const route_head* rte)
  1232. {
  1233. char hdr[2];
  1234. int value = 0;
  1235. (void)mps_ver;
  1236. hdr[0] = 1;
  1237. if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
  1238. gbfwrite(&value, 4, 1, mps_file);
  1239. gbfwrite(hdr, 1, 1, mps_file);
  1240. }
  1241. }
  1242. static void
  1243. mps_routetrlr_w_wrapper(const route_head* rte)
  1244. {
  1245. mps_routetrlr_w(mps_file_out, mps_ver_out, rte);
  1246. }
  1247. /*
  1248. * read in from file a track record
  1249. * MRCB
  1250. */
  1251. static void
  1252. mps_track_r(gbfile* mps_file, int mps_ver, route_head** trk)
  1253. {
  1254. int lat;
  1255. int lon;
  1256. int dateTime = 0;
  1257. route_head* track_head;
  1258. int trk_count;
  1259. Waypoint* thisWaypoint;
  1260. double mps_altitude = unknown_alt;
  1261. double mps_depth = unknown_alt;
  1262. (void)mps_ver;
  1263. QString trkname = gbfgetcstr(mps_file);
  1264. #ifdef MPS_DEBUG
  1265. fprintf(stderr, "mps_track_r: reading track %s\n", trkname);
  1266. #endif
  1267. (void) gbfgetc(mps_file); /* display flag */
  1268. (void) gbfgetint32(mps_file); /* colour */
  1269. trk_count = gbfgetint32(mps_file); /* number of datapoints in tracklog */
  1270. /* I don't know, but perhaps it's valid to have a track with no waypoints */
  1271. /* Seems dumb, but truth is stranger than fiction. Of course, it could be */
  1272. /* that there are more than MAXINT / 2 waypoints, yeah sure */
  1273. /* Allow the caller the perform the file resync caused by bombing out early */
  1274. if (trk_count < 0) {
  1275. return;
  1276. }
  1277. #ifdef MPS_DEBUG
  1278. fprintf(stderr, "mps_track_r: there are %d track waypoints %d\n", trk_count);
  1279. #endif
  1280. track_head = route_head_alloc();
  1281. track_head->rte_name = trkname;
  1282. track_add_head(track_head);
  1283. *trk = track_head;
  1284. while (trk_count--) {
  1285. lat = gbfgetint32(mps_file);
  1286. lon = gbfgetint32(mps_file);
  1287. if (gbfgetc(mps_file) == 1) { /* altitude validity */
  1288. mps_altitude = gbfgetdbl(mps_file);
  1289. } else {
  1290. mps_altitude = unknown_alt;
  1291. gbfseek(mps_file, 8, SEEK_CUR);
  1292. }
  1293. if (gbfgetc(mps_file) == 1) { /* date/time validity */
  1294. dateTime = gbfgetint32(mps_file);
  1295. } else {
  1296. (void) gbfgetint32(mps_file);
  1297. }
  1298. if (gbfgetc(mps_file) == 1) { /* depth validity */
  1299. mps_depth = gbfgetdbl(mps_file);
  1300. } else {
  1301. mps_depth = unknown_alt;
  1302. gbfseek(mps_file, 8, SEEK_CUR);
  1303. }
  1304. thisWaypoint = new Waypoint;
  1305. thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
  1306. thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
  1307. thisWaypoint->SetCreationTime(dateTime);
  1308. thisWaypoint->altitude = mps_altitude;
  1309. if (mps_depth != unknown_alt) {
  1310. WAYPT_SET(thisWaypoint, depth, mps_depth);
  1311. }
  1312. track_add_wpt(track_head, thisWaypoint);
  1313. } /* while (trk_count--) */
  1314. return;
  1315. }
  1316. /*
  1317. * write out to file a tracklog header
  1318. * MRCB
  1319. */
  1320. static void
  1321. mps_trackhdr_w(gbfile* mps_file, int mps_ver, const route_head* trk)
  1322. {
  1323. unsigned int reclen;
  1324. unsigned int trk_datapoints;
  1325. unsigned int colour = 0; /* unknown colour */
  1326. int tname_len;
  1327. char* tname;
  1328. char hdr[20];
  1329. Waypoint* testwpt;
  1330. time_t uniqueValue = 0;
  1331. queue* elem, *tmp;
  1332. (void)mps_ver;
  1333. /* total nodes (waypoints) this track */
  1334. trk_datapoints = 0;
  1335. if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */
  1336. QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) {
  1337. if (trk_datapoints == 0) {
  1338. testwpt = (Waypoint*)elem;
  1339. uniqueValue = testwpt->GetCreationTime().toTime_t();
  1340. }
  1341. trk_datapoints++;
  1342. }
  1343. if (uniqueValue == 0) {
  1344. uniqueValue = current_time().toTime_t();
  1345. }
  1346. /* track name */
  1347. if (trk->rte_name.isEmpty()) {
  1348. sprintf(hdr, "Track%04x", (unsigned) uniqueValue);
  1349. tname = xstrdup(hdr);
  1350. } else {
  1351. tname = xstrdup(trk->rte_name);
  1352. }
  1353. tname_len = strlen(tname);
  1354. reclen = tname_len + 11; /* "T" (1) + strlen(tname) + NULL (1) + display flag (1) + colour (4) +
  1355. num track datapoints value (4) */
  1356. reclen += (trk_datapoints * 31) - 1; /* lat (4) + lon (4) + alt (9) + date (5) + depth (9) ;*/
  1357. /* -1 is because reclen starts from 0 which means a length of 1 */
  1358. gbfputint32(reclen, mps_file);
  1359. gbfputc('T', mps_file);
  1360. gbfwrite(tname, 1, tname_len, mps_file);
  1361. xfree(tname);
  1362. hdr[0] = 0;
  1363. hdr[1] = 1;
  1364. gbfwrite(hdr, 2, 1, mps_file); /* NULL string terminator + display flag */
  1365. gbfputint32(colour, mps_file);
  1366. gbfputint32(trk_datapoints, mps_file);
  1367. }
  1368. }
  1369. static void
  1370. mps_trackhdr_w_wrapper(const route_head* trk)
  1371. {
  1372. mps_trackhdr_w(mps_file_out, mps_ver_out, trk);
  1373. }
  1374. /*
  1375. * write out to file a tracklog datapoint
  1376. * MRCB
  1377. */
  1378. static void
  1379. mps_trackdatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt)
  1380. {
  1381. int lat, lon;
  1382. time_t t = wpt->GetCreationTime().toTime_t();
  1383. char zbuf[10];
  1384. double mps_altitude = wpt->altitude;
  1385. double mps_depth = unknown_alt;
  1386. (void)mps_ver;
  1387. lat = GPS_Math_Deg_To_Semi(wpt->latitude);
  1388. lon = GPS_Math_Deg_To_Semi(wpt->longitude);
  1389. if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
  1390. mps_depth = wpt->depth;
  1391. }
  1392. memset(zbuf, 0, sizeof(zbuf));
  1393. gbfputint32(lat, mps_file);
  1394. gbfputint32(lon, mps_file);
  1395. if (mps_altitude == unknown_alt) {
  1396. gbfwrite(zbuf, 9, 1, mps_file);
  1397. } else {
  1398. gbfputc(1, mps_file);
  1399. gbfputdbl(mps_altitude, mps_file);
  1400. }
  1401. if (t > 0) { /* a valid time is assumed to > 0 */
  1402. gbfputc(1, mps_file);
  1403. gbfputint32(t, mps_file);
  1404. } else {
  1405. gbfwrite(zbuf, 5, 1, mps_file);
  1406. }
  1407. if (mps_depth == unknown_alt) {
  1408. gbfwrite(zbuf, 9, 1, mps_file);
  1409. } else {
  1410. gbfputc(1, mps_file);
  1411. gbfputdbl(mps_depth, mps_file);
  1412. }
  1413. }
  1414. static void
  1415. mps_trackdatapoint_w_wrapper(const Waypoint* wpt)
  1416. {
  1417. mps_trackdatapoint_w(mps_file_out, mps_ver_out, wpt);
  1418. }
  1419. static void
  1420. mps_read(void)
  1421. {
  1422. Waypoint* wpt;
  1423. route_head* rte;
  1424. route_head* trk;
  1425. char recType;
  1426. int reclen;
  1427. int morework;
  1428. unsigned int mpsWptClass;
  1429. long mpsFileInPos;
  1430. mps_ver_in = 0; /* although initialised at declaration, what happens if there are two mapsource
  1431. input files? */
  1432. mps_fileHeader_r(mps_file_in, &mps_ver_in);
  1433. #ifdef DUMP_ICON_TABLE
  1434. printf("static icon_mapping_t garmin_icon_table[] = {\n");
  1435. #endif
  1436. morework = 1;
  1437. while (morework && !gbfeof(mps_file_in)) {
  1438. /* Read record length of next section */
  1439. reclen = gbfgetint32(mps_file_in);
  1440. if (reclen < 0) {
  1441. fatal(MYNAME ": a record length read from the input file is invalid. \nEither the file is corrupt or unsupported.\n");
  1442. }
  1443. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1444. gbfread(&recType, 1, 1, mps_file_in);
  1445. mpsFileInPos = gbftell(mps_file_in);
  1446. switch (recType) {
  1447. case 'W':
  1448. /* Waypoint record */
  1449. /* With routes, we need the waypoint info that reveals, for example, the symbol type */
  1450. mps_waypoint_r(mps_file_in, mps_ver_in, &wpt, &mpsWptClass);
  1451. #ifdef MPS_DEBUG
  1452. fprintf(stderr,"Read a waypoint - %s\n", wpt->shortname);
  1453. #endif
  1454. if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
  1455. /* should junk this record and not save it since we're out of sync with the file */
  1456. /* Should and how do we warn the user? */
  1457. #ifdef MPS_DEBUG
  1458. fprintf(stderr,"Lost sync with the file reading waypoint - %s\n", wpt->shortname);
  1459. #endif
  1460. gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
  1461. delete wpt;
  1462. } else {
  1463. /* only add to the "real" list if a "user" waypoint otherwise add to the private list */
  1464. if (mpsWptClass == MPSDEFAULTWPTCLASS) {
  1465. waypt_add(wpt);
  1466. } else {
  1467. mps_wpt_q_add(&read_route_wpt_head, wpt);
  1468. delete wpt;
  1469. }
  1470. #ifdef DUMP_ICON_TABLE
  1471. printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname);
  1472. #endif
  1473. }
  1474. break;
  1475. case 'R':
  1476. /* Route record */
  1477. mps_route_r(mps_file_in, mps_ver_in, &rte);
  1478. if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
  1479. /* should junk this record and not save it since we're out of sync with the file */
  1480. /* Should and how do we warn the user? */
  1481. #ifdef MPS_DEBUG
  1482. fprintf(stderr,"Lost sync with the file reading route - %s\n", rte->rte_name);
  1483. #endif
  1484. gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
  1485. }
  1486. break;
  1487. case 'T':
  1488. /* Track record */
  1489. mps_track_r(mps_file_in, mps_ver_in, &trk);
  1490. if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
  1491. /* should junk this record and not save it since we're out of sync with the file */
  1492. /* Should and how do we warn the user? */
  1493. #ifdef MPS_DEBUG
  1494. fprintf(stderr,"Lost sync with the file reading track - %s\n", trk->rte_name);
  1495. #endif
  1496. gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
  1497. }
  1498. break;
  1499. case 'L':
  1500. /* Map segment record */
  1501. mps_mapsegment_r(mps_file_in, mps_ver_in);
  1502. if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
  1503. /* should junk this record and not save it since we're out of sync with the file */
  1504. /* Should and how do we warn the user? */
  1505. gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
  1506. }
  1507. break;
  1508. case 'V':
  1509. /* Mapset record */
  1510. mps_mapsetname_r(mps_file_in, mps_ver_in);
  1511. /* Last record in the file */
  1512. morework = 0;
  1513. break;
  1514. default:
  1515. /* Unknown record type. Skip over it. */
  1516. gbfseek(mps_file_in, reclen, SEEK_CUR);
  1517. }
  1518. } /* while (!gbfeof(mps_file_in)) */
  1519. #ifdef DUMP_ICON_TABLE
  1520. printf("\t{ -1, NULL },\n");
  1521. printf("};\n");
  1522. #endif
  1523. return ;
  1524. }
  1525. void
  1526. mps_write(void)
  1527. {
  1528. int short_length;
  1529. Waypoint* wpt;
  1530. route_head* rte;
  1531. route_head* trk;
  1532. char recType = -1;
  1533. int reclen;
  1534. /* TODO: This kills a compiler warning but I'm not sure it's right */
  1535. int reclen2 = 0;
  1536. unsigned int tocopy;
  1537. unsigned int block;
  1538. long tempFilePos;
  1539. unsigned int mpsWptClass;
  1540. unsigned char copybuf[8192];
  1541. short_length = atoi(snlen);
  1542. if (mpsmergeout) {
  1543. /* need to skip over the merging header and test merge version */
  1544. mps_fileHeader_r(mps_file_temp, &mps_ver_temp);
  1545. if (mpsverout) {
  1546. if (mps_ver_temp != atoi(mpsverout)) {
  1547. /* Need to clean up after a junk version specified */
  1548. /* close the real output file + renamed original output file */
  1549. /* then delete the "real" file and rename the temporarily renamed file back */
  1550. gbfclose(mps_file_temp);
  1551. gbfclose(mps_file_out);
  1552. QFile::remove(fin_name);
  1553. QFile::rename(tempname, fin_name);
  1554. fatal(MYNAME ": merge source version is %d, requested out version is %d\n", mps_ver_temp, atoi(mpsverout));
  1555. }
  1556. } else {
  1557. mpsverout = (char*) xmalloc(10);
  1558. sprintf(mpsverout,"%d", mps_ver_temp);
  1559. }
  1560. }
  1561. if (mpsverout) {
  1562. mps_ver_out = atoi(mpsverout);
  1563. } else {
  1564. mps_ver_out = 5;
  1565. }
  1566. mkshort_handle = mkshort_new_handle();
  1567. setshort_length(mkshort_handle, short_length);
  1568. if (snwhiteopt) {
  1569. setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt));
  1570. } else {
  1571. setshort_whitespace_ok(mkshort_handle, 0);
  1572. }
  1573. mps_fileHeader_w(mps_file_out, mps_ver_out);
  1574. /* .mps file order is wpts, rtes, trks then mapsets. If we've not been asked to write
  1575. wpts, but we are merging, then read in the waypoints from the original file and
  1576. write them out, prior to doing rtes.
  1577. */
  1578. /* if ((mpsmergeout) && (global_opts.objective != wptdata)) { */
  1579. if ((mpsmergeout) && (! doing_wpts)) {
  1580. while (!gbfeof(mps_file_temp)) {
  1581. reclen2 = gbfgetint32(mps_file_temp);
  1582. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1583. gbfread(&recType, 1, 1, mps_file_temp);
  1584. if (recType == 'W') {
  1585. gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
  1586. gbfwrite(&recType, 1, 1, mps_file_out);
  1587. tempFilePos = gbftell(mps_file_temp);
  1588. /* need to read in the waypoint info only because later we may need to check for uniqueness
  1589. since we're here because the user didn't request waypoints, this should be acceptable */
  1590. mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
  1591. mps_wpt_q_add(&written_wpt_head, wpt);
  1592. delete wpt;
  1593. /* now return to the start of the waypoint data to do a "clean" copy */
  1594. gbfseek(mps_file_temp, tempFilePos, SEEK_SET);
  1595. /* copy the data using a "reasonably" sized buffer */
  1596. for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
  1597. block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
  1598. gbfread(copybuf, block, 1, mps_file_temp);
  1599. gbfwrite(copybuf, block, 1, mps_file_out);
  1600. }
  1601. } else {
  1602. break;
  1603. }
  1604. } /* while (!gbfeof(mps_file_temp)) */
  1605. } /* if (mpsmergeout) */
  1606. /* irrespective of merging, now write out any waypoints */
  1607. /* if (global_opts.objective == wptdata) { */
  1608. if (doing_wpts) {
  1609. if (mpsmergeout) {
  1610. /* since we're processing waypoints, we should read in from whatever version and write out */
  1611. /* in the selected version */
  1612. while (!gbfeof(mps_file_temp)) {
  1613. reclen2 = gbfgetint32(mps_file_temp);
  1614. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1615. gbfread(&recType, 1, 1, mps_file_temp);
  1616. if (recType == 'W') {
  1617. /* need to be careful that we aren't duplicating a wpt defined from elsewhere */
  1618. mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
  1619. if (mpsWptClass == MPSDEFAULTWPTCLASS) {
  1620. waypt_add(wpt);
  1621. } else {
  1622. delete wpt;
  1623. }
  1624. } else {
  1625. break;
  1626. }
  1627. }
  1628. }
  1629. waypt_disp_all(mps_waypoint_w_unique_wrapper);
  1630. }
  1631. /* prior to writing any tracks as requested, if we're doing a merge, read in the rtes
  1632. from the original file and then write them out, ready for tracks to follow
  1633. */
  1634. /* if ((mpsmergeout) && (global_opts.objective != rtedata)) { */
  1635. if ((mpsmergeout) && (! doing_rtes)) {
  1636. while (!gbfeof(mps_file_temp)) {
  1637. /* this might all fail if the relevant waypoints haven't been written */
  1638. if (recType == 'R') {
  1639. gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
  1640. gbfwrite(&recType, 1, 1, mps_file_out);
  1641. /* copy the data using a "reasonably" sized buffer */
  1642. for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
  1643. block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
  1644. gbfread(copybuf, block, 1, mps_file_temp);
  1645. gbfwrite(copybuf, block, 1, mps_file_out);
  1646. }
  1647. } else {
  1648. break;
  1649. }
  1650. reclen2 = gbfgetint32(mps_file_temp);
  1651. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1652. gbfread(&recType, 1, 1, mps_file_temp);
  1653. } /* while (!gbfeof(mps_file_temp)) */
  1654. } /* if (mpsmergeout) */
  1655. /* routes are next in the wpts, rtes, trks, mapset sequence */
  1656. /* if (global_opts.objective == rtedata) { */
  1657. if (doing_rtes) {
  1658. if (mpsmergeout) {
  1659. /* since we're processing routes, we should read in from whatever version and write out */
  1660. /* in the selected version */
  1661. while (!gbfeof(mps_file_temp)) {
  1662. if (recType == 'R') {
  1663. mps_route_r(mps_file_temp, mps_ver_temp, &rte);
  1664. } else {
  1665. break;
  1666. }
  1667. reclen2 = gbfgetint32(mps_file_temp);
  1668. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1669. gbfread(&recType, 1, 1, mps_file_temp);
  1670. }
  1671. }
  1672. /* need to make sure there is a "real" waypoint for each route waypoint
  1673. Need to be careful about creating duplicate wpts as MapSource chokes on these
  1674. so, if the user requested waypoints to be output too, then write the route
  1675. waypoints only if unique in the total list of waypoints ("real" and route derived)
  1676. If the user didn't request waypoints to be output, then output the route derived
  1677. waypoints without consideration for uniqueness for "real" waypoints that haven't
  1678. been output (phew!)
  1679. */
  1680. route_disp_all(mps_noop, mps_noop, mps_route_wpt_w_unique_wrapper);
  1681. route_disp_all(mps_routehdr_w_wrapper, mps_routetrlr_w_wrapper, mps_routedatapoint_w_wrapper);
  1682. }
  1683. /* If merging but we haven't been requested to write out tracks, then read in tracks from
  1684. the original file and write these out prior to any mapset writes later on
  1685. */
  1686. /* if ((mpsmergeout) && (global_opts.objective != trkdata)) { */
  1687. if ((mpsmergeout) && (! doing_trks)) {
  1688. while (!gbfeof(mps_file_temp)) {
  1689. if (recType == 'T') {
  1690. gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
  1691. gbfwrite(&recType, 1, 1, mps_file_out);
  1692. /* copy the data using a "reasonably" sized buffer */
  1693. for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
  1694. block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
  1695. gbfread(copybuf, block, 1, mps_file_temp);
  1696. gbfwrite(copybuf, block, 1, mps_file_out);
  1697. }
  1698. } else {
  1699. break;
  1700. }
  1701. reclen2 = gbfgetint32(mps_file_temp);
  1702. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1703. gbfread(&recType, 1, 1, mps_file_temp);
  1704. } /* while (!gbfeof(mps_file_temp)) */
  1705. } /* if (mpsmergeout) */
  1706. /* tracks are next in the wpts, rte, trks, mapset sequence in .mps files */
  1707. /* if (global_opts.objective == trkdata) { */
  1708. if (doing_trks) {
  1709. if (mpsmergeout) {
  1710. /* since we're processing tracks, we should read in from whatever version and write out
  1711. in the selected version */
  1712. while (!gbfeof(mps_file_temp)) {
  1713. if (recType == 'T') {
  1714. mps_track_r(mps_file_temp, mps_ver_temp, &trk);
  1715. } else {
  1716. break;
  1717. }
  1718. reclen2 = gbfgetint32(mps_file_temp);
  1719. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1720. gbfread(&recType, 1, 1, mps_file_temp);
  1721. }
  1722. }
  1723. track_disp_all(mps_trackhdr_w_wrapper, mps_noop, mps_trackdatapoint_w_wrapper);
  1724. }
  1725. if (mpsmergeout) {
  1726. /* should now be reading a either a map segment or a mapset - since we would write out an empty one,
  1727. let's use the one from the merge file which may well have decent data in */
  1728. for (;;) {
  1729. gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
  1730. gbfwrite(&recType, 1, 1, mps_file_out);
  1731. /* copy the data using a "reasonably" sized buffer */
  1732. for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
  1733. block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
  1734. gbfread(copybuf, block, 1, mps_file_temp);
  1735. gbfwrite(copybuf, block, 1, mps_file_out);
  1736. }
  1737. if (recType != 'V') {
  1738. reclen2 = gbfgetint32(mps_file_temp);
  1739. /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
  1740. gbfread(&recType, 1, 1, mps_file_temp);
  1741. } else {
  1742. break;
  1743. }
  1744. }
  1745. } else {
  1746. mps_mapsetname_w(mps_file_out, mps_ver_out);
  1747. }
  1748. mkshort_del_handle(&mkshort_handle);
  1749. }
  1750. ff_vecs_t mps_vecs = {
  1751. ff_type_file,
  1752. FF_CAP_RW_ALL,
  1753. mps_rd_init,
  1754. mps_wr_init,
  1755. mps_rd_deinit,
  1756. mps_wr_deinit,
  1757. mps_read,
  1758. mps_write,
  1759. NULL,
  1760. mps_args,
  1761. CET_CHARSET_MS_ANSI, 0, /* CET-REVIEW */
  1762. NULL_POS_OPS,
  1763. NULL,
  1764. };