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.

tpo.cc 58KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960
  1. /*
  2. National Geographic Topo! TPO file support.
  3. 2.x support contributed to gpsbabel by Steve Chamberlin.
  4. 3.x support contributed to gpsbabel by Curt Mills.
  5. Topo! version 2.x: Tracks are implemented.
  6. Topo! version 3.x: Reading of Tracks/Waypoints/Routes is
  7. implemented. Also extracts Map Notes/
  8. Symbols/Text Labels as Waypoints.
  9. Copyright (C) 2005 Steve Chamberlin, slc at alum.mit.edu
  10. Portions Copyright (C) 2006 Curtis E. Mills, archer at eskimo dot com
  11. This program is free software; you can redistribute it and/or modify
  12. it under the terms of the GNU General Public License as published by
  13. the Free Software Foundation; either version 2 of the License, or
  14. (at your option) any later version.
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  22. */
  23. /*
  24. ***** This format has problems and the author hasn't returned emails
  25. * on it, so we've set the format type to 'ff_type_internal' to make it
  26. * disappear from the various lists...
  27. */
  28. /*
  29. TPO format notes:
  30. -----------------
  31. Most of the ASCII strings embedded in the text will have a
  32. byte-count prepended to the string. Unknown yet whether other
  33. fields have this same byte-count, but so far it doesn't look like
  34. it.
  35. New format (3.x and later) files begin with a string byte-count
  36. byte and then a string starting with "TOPO! Ver. 3.", like "TOPO!
  37. Ver. 3.3.4". Can contain routes/tracks/waypoints, embedded
  38. images, Map Notes, Symbols, Text Labels, Compass symbols, and
  39. several others.
  40. Older (pre-3.0) format does not have the above string. Contains
  41. only tracks. Waypoints are saved in a separate .TPG file.
  42. May contain these strings:
  43. Frmt: String:
  44. ----- --------------------------------
  45. 2.x "CTopoAzimuth"
  46. 2.x "CTopoBookmark"
  47. 2.x "CTopoGpsRoute". Saved in .tpg files (see tpg.c)
  48. 2.x "CTopoRoute". The actual tracks we parse here.
  49. 2.x "CTopoSymbol"
  50. 2.x/3.x "CTopoText"
  51. 2.x "CTopoWaypoint". Saved in .tpg files (see tpg.c)
  52. 3.x "Notes"
  53. 3.x "PNG." Embedded PNG image containing 2 rows of 40
  54. symbols each. Starts with signature: 89 50 4e 47 0d
  55. 0a 1a 0a, ends with signature 49 45 4e 44 ae 42 60 82.
  56. 3.x "shapes"
  57. 3.x "arrows"
  58. 3.x "recreation"
  59. */
  60. #include "defs.h"
  61. #include "jeeps/gpsmath.h" /* for datum conversions */
  62. #include <cmath>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <vector>
  66. #include <QtCore/QScopedArrayPointer> // Wish we could use c++11...
  67. #define MYNAME "TPO"
  68. static char* dumpheader = NULL;
  69. static char* output_state = NULL;
  70. /*
  71. static
  72. arglist_t tpo2_args[] = {
  73. { "dumpheader", &dumpheader, "Display the file header bytes",
  74. "0", ARGTYPE_BOOL, ARG_NOMINMAX} ,
  75. { "state", &output_state, "State map format to write, default=CA",
  76. "CA", ARGTYPE_STRING, ARG_NOMINMAX} ,
  77. ARG_TERMINATOR
  78. };
  79. */
  80. //
  81. // Note that we've disabled the write capabilites for the tpo2
  82. // format at present. The "testo" tests were failing on some
  83. // platforms and there wasn't anyone willing to work on the problem.
  84. // If this is fixed in the future we can go back to the tpo2_args[]
  85. // above.
  86. //
  87. static
  88. arglist_t tpo2_args[] = {
  89. ARG_TERMINATOR
  90. };
  91. static
  92. arglist_t tpo3_args[] = {
  93. ARG_TERMINATOR
  94. };
  95. static gbfile* tpo_file_in;
  96. static gbfile* tpo_file_out;
  97. //static short_handle mkshort_handle;
  98. static double output_track_lon_scale;
  99. static double output_track_lat_scale;
  100. static unsigned int track_out_count;
  101. static double first_track_waypoint_lat;
  102. static double first_track_waypoint_lon;
  103. static double track_length;
  104. static double last_waypoint_x;
  105. static double last_waypoint_y;
  106. static double last_waypoint_z;
  107. /*******************************************************************************/
  108. /* READ */
  109. /*******************************************************************************/
  110. /* Define a global here that we can query from multiple places */
  111. float tpo_version = 0.0;
  112. /* tpo_check_version_string()
  113. Check the first bytes of the file for a version 3.0 header. */
  114. static void
  115. tpo_check_version_string()
  116. {
  117. unsigned char string_size;
  118. char* string_buffer;
  119. const char* v3_id_string = "TOPO! Ver";
  120. /* read the id string */
  121. gbfread(&string_size, 1, 1, tpo_file_in);
  122. string_buffer = (char*) xmalloc(string_size+1);
  123. gbfread(string_buffer, 1, string_size, tpo_file_in);
  124. /* terminate the string */
  125. string_buffer[string_size] = 0;
  126. /* check for the presence of a 3.0-style id string */
  127. /* Note this check also finds version 4 id strings, e.g. "TOPO! Ver. 4.5.0" */
  128. if (strncmp(v3_id_string, string_buffer, strlen(v3_id_string)) == 0) {
  129. /* fatal(MYNAME ": gpsbabel can only read TPO version 2.7.7 or below; this file is %s\n", string_buffer); */
  130. //fprintf(stderr,"gpsbabel can only read TPO version 2.7.7 or below; this file is %s\n", string_buffer);
  131. gbfseek(tpo_file_in, -(string_size+1), SEEK_CUR);
  132. xfree(string_buffer);
  133. tpo_version = 3.0; /* Really any 3.x version */
  134. return;
  135. } else {
  136. /* We found a version 1.x or 2.x file */
  137. /* seek back to the beginning of the file */
  138. gbfseek(tpo_file_in, -(string_size+1), SEEK_CUR);
  139. xfree(string_buffer);
  140. tpo_version = 2.0; /* Really any 1.x or 2.x version */
  141. return;
  142. }
  143. }
  144. static void
  145. /* tpo_dump_header_bytes(int header_size)
  146. Write the first header_size bytes of the file to standard output
  147. as a C array definition. */
  148. tpo_dump_header_bytes(int header_size)
  149. {
  150. int i;
  151. unsigned char* buffer = (unsigned char*) xmalloc(header_size);
  152. gbfread(buffer, 1, header_size, tpo_file_in);
  153. printf("unsigned char header_bytes[] = {\n");
  154. for (i=0; i<header_size; i++) {
  155. if (i%8 == 0) {
  156. printf(" ");
  157. }
  158. printf("0x%02X", buffer[i]);
  159. if (i != header_size-1) {
  160. printf(", ");
  161. }
  162. if (i%8 == 7) {
  163. printf("\n");
  164. }
  165. }
  166. printf("};\n");
  167. xfree(buffer);
  168. }
  169. /* tpo_read_until_section()
  170. Keep reading bytes from the file until the section name is encountered,
  171. then go seek_bytes forwards (+) or backwards (-) to the start of
  172. the section data. */
  173. static void
  174. tpo_read_until_section(const char* section_name, int seek_bytes)
  175. {
  176. char byte;
  177. unsigned int match_index = 0;
  178. int header_size = 0;
  179. while (1) {
  180. if (gbfread(&byte, 1, 1, tpo_file_in) < 1) {
  181. fatal(MYNAME ": malformed input file - attempt to read past end");
  182. }
  183. header_size++;
  184. if (byte == section_name[match_index]) {
  185. match_index++;
  186. if (match_index == strlen(section_name)) {
  187. /*fprintf(stderr,"Found %s\n", section_name);*/
  188. gbfseek(tpo_file_in, seek_bytes, SEEK_CUR);
  189. header_size += seek_bytes;
  190. if (dumpheader && dumpheader[0] == '1') {
  191. gbfseek(tpo_file_in, -header_size, SEEK_CUR);
  192. tpo_dump_header_bytes(header_size);
  193. }
  194. return;
  195. }
  196. } else {
  197. match_index = 0;
  198. }
  199. }
  200. }
  201. //-------------------------------------------------------------------
  202. //-------------------------------------------------------------------
  203. // Decoder for version 2.x files. This one does tracks only, as
  204. // that is the only type of data available in the version 2.x TPO
  205. // files.
  206. //
  207. void tpo_read_2_x(void)
  208. {
  209. char buff[16];
  210. short track_count, waypoint_count;
  211. double first_lat, first_lon, lat_scale, lon_scale, amt;
  212. int i, j;
  213. route_head* track_temp;
  214. Waypoint* waypoint_temp;
  215. /* track count */
  216. track_count = gbfgetint16(tpo_file_in);
  217. /*fprintf(stderr,"track_count:%d\n", track_count);*/
  218. /* 4 unknown bytes */
  219. gbfread(&buff[0], 1, 4, tpo_file_in);
  220. /* chunk name: "CTopoRoute" */
  221. gbfread(&buff[0], 1, 12, tpo_file_in);
  222. for (i=0; i<track_count; i++) {
  223. track_temp = route_head_alloc();
  224. track_add_head(track_temp);
  225. /* generate a generic track name */
  226. sprintf(buff, "Track %d", i+1);
  227. track_temp->rte_name = buff;
  228. /* zoom level 1-5 visibility flags */
  229. gbfread(&buff[0], 1, 10, tpo_file_in);
  230. /* 8 bytes of zeros, meaning unknown */
  231. gbfread(&buff[0], 1, 8, tpo_file_in);
  232. /* 4 more unknown bytes, possibly sign flags for the longitude and latitude? */
  233. gbfread(&buff[0], 1, 4, tpo_file_in);
  234. /* read the position of the initial track point */
  235. /* for some very odd reason, signs on longitude are swapped */
  236. /* coordinates are in NAD27/CONUS datum */
  237. /* 8 bytes - longitude, sign swapped */
  238. first_lon = gbfgetdbl(tpo_file_in);
  239. /* 8 bytes - latitude */
  240. first_lat = gbfgetdbl(tpo_file_in);
  241. /* swap sign before we do datum conversions */
  242. first_lon *= -1.0;
  243. /* 8 unknown bytes: seems to be some kind of bounding box info */
  244. gbfread(&buff[0], 1, 8, tpo_file_in);
  245. /* number of route points */
  246. waypoint_count = gbfgetint16(tpo_file_in);
  247. /* allocate temporary memory for the waypoint deltas */
  248. std::vector<short> lat_delta(waypoint_count);
  249. std::vector<short> lon_delta(waypoint_count);
  250. for (j = 0; j < waypoint_count; j++) {
  251. /* get this point's longitude delta from the first waypoint */
  252. lon_delta[j] = gbfgetint16(tpo_file_in);
  253. /* get this point's latitude delta from the first waypoint */
  254. lat_delta[j] = gbfgetint16(tpo_file_in);
  255. }
  256. /* 8 bytes - longitude delta to degrees scale */
  257. lon_scale = gbfgetdbl(tpo_file_in);
  258. /* 8 bytes - latitude delta to degrees scale */
  259. lat_scale = gbfgetdbl(tpo_file_in);
  260. /* 4 bytes: the total length of the route in feet*/
  261. gbfread(&buff[0], 1, 4, tpo_file_in);
  262. /* 2 unknown bytes */
  263. gbfread(&buff[0], 1, 2, tpo_file_in);
  264. /* 2 bytes: continuation marker */
  265. gbfread(&buff[0], 1, 2, tpo_file_in);
  266. /* multiply all the deltas by the scaling factors to determine the waypoint positions */
  267. for (j = 0; j < waypoint_count; j++) {
  268. waypoint_temp = new Waypoint;
  269. /* convert incoming NAD27/CONUS coordinates to WGS84 */
  270. GPS_Math_Known_Datum_To_WGS84_M(
  271. first_lat-lat_delta[j]*lat_scale,
  272. first_lon+lon_delta[j]*lon_scale,
  273. 0.0,
  274. &waypoint_temp->latitude,
  275. &waypoint_temp->longitude,
  276. &amt,
  277. 78);
  278. /* there is no elevation data for the waypoints */
  279. /* this is unecessary, the constructor will do this anyway. */
  280. waypoint_temp->altitude = unknown_alt;
  281. track_add_wpt(track_temp, waypoint_temp);
  282. }
  283. }
  284. }
  285. //-------------------------------------------------------------------
  286. //-------------------------------------------------------------------
  287. // This will read 8/16/32 bits in little-endian format depending
  288. // upon the value of the first byte.
  289. //
  290. // For version 3.x files.
  291. //
  292. int tpo_read_int()
  293. {
  294. unsigned char val;
  295. val = (unsigned char) gbfgetc(tpo_file_in);
  296. switch (val) {
  297. case 0xff: // 32-bit value
  298. //printf("Found 32-bit value indicator: %x\n", val);
  299. return(gbfgetint32(tpo_file_in));
  300. break;
  301. case 0xfe: // 16-bit value
  302. //printf("Found 16-bit value indicator: %x\n", val);
  303. return(gbfgetuint16(tpo_file_in));
  304. break;
  305. default: // 8-bit value
  306. //printf("Found 8-bit value: %x\n", val);
  307. return((int)val);
  308. break;
  309. }
  310. }
  311. // Find variable block of interest in the file. Leaves the file
  312. // pointer pointing after the two 4-byte type/pointer bytes. The
  313. // file pointer should be pointing at the first data byte of the
  314. // block after calling this, which is normally an 8/16/32-bit value
  315. // specifying the number of elements in the block.
  316. //
  317. // Returns -1 if block not found
  318. // 0 if block found
  319. //
  320. // For version 3.x files.
  321. //
  322. int tpo_find_block(unsigned int block_desired)
  323. {
  324. unsigned int block_type;
  325. unsigned int block_offset;
  326. // Skip 512 byte fixed-length header
  327. block_offset = 512;
  328. do {
  329. // Seek to offset from start of file
  330. gbfseek(tpo_file_in, block_offset, SEEK_SET);
  331. // Read record type
  332. block_type = gbfgetint32(tpo_file_in);
  333. // printf("Block: %08x\tat offset: %08x\n", block_type, block_offset);
  334. // Read offset to next record
  335. block_offset = gbfgetint32(tpo_file_in);
  336. } while (block_type != block_desired && block_offset != 0);
  337. if (block_type == block_desired) {
  338. return(0);
  339. } else {
  340. return(-1);
  341. }
  342. }
  343. // Convert lat/long to normal values, save in waypoint struct
  344. //
  345. // For version 3.x files.
  346. //
  347. Waypoint* tpo_convert_ll(int lat, int lon)
  348. {
  349. double latitude;
  350. double longitude;
  351. Waypoint* waypoint_temp;
  352. waypoint_temp = new Waypoint;
  353. latitude = (double)lat / 0x800000;
  354. longitude = (double)lon / 0x800000;
  355. //printf("lat: %f\tlon: %f\n", latitude, longitude);
  356. /*
  357. // Note: We shouldn't need this section of code as the version
  358. // 3.x files are already in WGS84 datum.
  359. //
  360. // Convert incoming NAD27/CONUS coordinates to WGS84, Molodensky
  361. // transform.
  362. //
  363. GPS_Math_Known_Datum_To_WGS84_M(
  364. latitude, // Source latitude
  365. longitude, // Source longitude
  366. 0.0, // Source height (meters)
  367. &waypoint_temp->latitude, // Dest latitude
  368. &waypoint_temp->longitude, // Dest longitude
  369. &height, // Dest height (meters)
  370. 78);
  371. */
  372. waypoint_temp->latitude = latitude;
  373. waypoint_temp->longitude = longitude;
  374. //printf("lat: %f\tlon: %f\tNew Height: %f\n", waypoint_temp->latitude, waypoint_temp->longitude, height);
  375. return(waypoint_temp);
  376. }
  377. #define TRACKNAMELENGTH 256
  378. class StyleInfo {
  379. public:
  380. StyleInfo() {
  381. name[0] = 0;
  382. color[0] = 0;
  383. color[1] = 0;
  384. color[2] = 0;
  385. wide = dash = 0;
  386. }
  387. char name[TRACKNAMELENGTH]; // some huge value
  388. uint8_t color[3]; // keep R/G/B values separate because line_color needs BGR
  389. uint8_t wide;
  390. uint8_t dash;
  391. };
  392. // Track decoder for version 3.x files. This block contains tracks
  393. // (called "freehand routes" or just "routes" in Topo).
  394. //
  395. void tpo_process_tracks(void)
  396. {
  397. unsigned int track_count, track_style_count;
  398. unsigned int xx,ii,tmp;
  399. const int DEBUG = 0;
  400. if (DEBUG) {
  401. printf("Processing Track Styles... (added in 2012 by SRE)\n");
  402. }
  403. // Find block 0x050000 (definitions of styles for free-hand routes)
  404. if (tpo_find_block(0x050000)) {
  405. // printf("Found no track styles, skipping tracks\n");
  406. return;
  407. }
  408. // Read the number of track styles.
  409. track_style_count = tpo_read_int(); // 8 bit value
  410. if (DEBUG) {
  411. printf("Unpacking %d track styles...\n",track_style_count);
  412. }
  413. QScopedArrayPointer<StyleInfo> styles(new StyleInfo[track_style_count]);
  414. for (ii = 0; ii < track_style_count; ii++) {
  415. // clumsy way to skip two undefined bytes (compiler should unwind this)
  416. for (xx = 0; xx < 2; xx++) {
  417. tmp = (unsigned char) gbfgetc(tpo_file_in);
  418. // printf("Skipping unknown (visibility?) byte 0x%x\n",tmp);
  419. }
  420. // next three bytes are RGB color, fourth is unknown
  421. // Topo and web uses rrggbb, also need line_color.bbggrr for KML
  422. for (xx = 0; xx < 3; xx++) {
  423. int col = (int)gbfgetc(tpo_file_in);
  424. if ((col < 0) || (col >255)) {
  425. col = 0; // assign black if out of range 0x00 to 0xff
  426. }
  427. styles[ii].color[xx] = (uint8_t)col;
  428. }
  429. tmp = (unsigned char) gbfgetc(tpo_file_in);
  430. // printf("Skipping unknown byte 0x%x after color\n",tmp);
  431. // byte for name length, then name
  432. tmp = (unsigned char) gbfgetc(tpo_file_in);
  433. // wrong byte order?? tmp = tpo_read_int(); // 16 bit value
  434. // printf("Track %d has %d-byte (0x%x) name\n",ii,tmp,tmp);
  435. if (tmp >= TRACKNAMELENGTH) {
  436. printf("ERROR! Found track style over TRACKNAMELENGTH chars, skipping all tracks!\n");
  437. return;
  438. }
  439. if (tmp) {
  440. styles[ii].name[0] = '\0';
  441. gbfread(styles[ii].name, 1, tmp, tpo_file_in);
  442. styles[ii].name[tmp] = '\0'; // Terminator
  443. } else { // Assign a generic style name
  444. sprintf(styles[ii].name, "STYLE %d", ii);
  445. }
  446. //TBD: Should this be TRACKNAMELENGTH?
  447. for (xx = 0; xx < 3; xx++) {
  448. if (styles[ii].name[xx] == (char) ',') {
  449. styles[ii].name[xx] = (char) '_';
  450. }
  451. if (styles[ii].name[xx] == (char) '=') {
  452. styles[ii].name[xx] = (char) '_';
  453. }
  454. }
  455. // one byte for line width (value 1-4), one byte for 'dashed' boolean
  456. styles[ii].wide = (uint8_t) gbfgetc(tpo_file_in);
  457. styles[ii].dash = (uint8_t) gbfgetc(tpo_file_in);
  458. // clumsy way to skip two undefined bytes
  459. for (xx = 0; xx < 2; xx++) {
  460. tmp = (unsigned char) gbfgetc(tpo_file_in);
  461. // printf("Skipping final byte 0x%x\n",tmp);
  462. }
  463. if (DEBUG) {
  464. printf("Track style %d: color=#%02x%02x%02x, width=%d, dashed=%d, name=%s\n",ii,styles[ii].color[0],styles[ii].color[1],styles[ii].color[2],styles[ii].wide,styles[ii].dash,styles[ii].name);
  465. }
  466. }
  467. if (DEBUG) {
  468. printf("Processing Tracks... found %d track styles\n",track_style_count);
  469. }
  470. // Find block 0x060000 (free-hand routes) (original track code, pre-2012, without styles)
  471. if (tpo_find_block(0x060000)) {
  472. return;
  473. }
  474. // Read the number of tracks. Can be 8/16/32-bit value.
  475. track_count = tpo_read_int();
  476. if (DEBUG) {
  477. printf("Total Tracks: %d\n", track_count);
  478. }
  479. if (track_count == 0) {
  480. return;
  481. }
  482. // Read/process each track in the file
  483. //
  484. for (ii = 0; ii < track_count; ii++) {
  485. unsigned int line_type;
  486. unsigned int track_style;
  487. unsigned int name_length;
  488. unsigned int track_byte_count;
  489. int llvalid;
  490. unsigned char* buf;
  491. int lonscale;
  492. int latscale;
  493. int waypoint_count = 0;
  494. int lat = 0;
  495. int lon = 0;
  496. unsigned int jj;
  497. route_head* track_temp;
  498. char rgb[7],bgr[7];
  499. int bbggrr = 0;
  500. // Allocate the track struct
  501. track_temp = route_head_alloc();
  502. track_add_head(track_temp);
  503. //UNKNOWN DATA LENGTH
  504. line_type = tpo_read_int(); // always zero??
  505. // Can be 8/16/32-bit value (defined in 2012, ignored before then)
  506. track_style = tpo_read_int(); // index into freehand route styles defined in this .tpo file
  507. track_style -= 1; // STARTS AT 1, whereas style arrays start at 0
  508. // Can be 8/16/32-bit value - never used?
  509. track_length = tpo_read_int();
  510. //UNKNOWN DATA LENGTH
  511. name_length = tpo_read_int();
  512. QString track_name;
  513. if (name_length) {
  514. gbfread(track_name, 1, name_length, tpo_file_in);
  515. } else { // Assign a generic track name
  516. track_name = "TRK ";
  517. track_name += QString::number(ii + 1);
  518. }
  519. track_temp->rte_name = track_name;
  520. // RGB line_color expressed for html=rrggbb and kml=bbggrr - not assigned before 2012
  521. sprintf(rgb,"%02x%02x%02x",styles[track_style].color[0],styles[track_style].color[1],styles[track_style].color[2]);
  522. sprintf(bgr,"%02x%02x%02x",styles[track_style].color[2],styles[track_style].color[1],styles[track_style].color[0]);
  523. bbggrr = styles[track_style].color[2] << 16 | styles[track_style].color[1] << 8 | styles[track_style].color[0];
  524. track_temp->line_color.bbggrr = bbggrr;
  525. // track texture (dashed=1, solid=0) mapped into opacity - not assigned before 2012
  526. track_temp->line_color.opacity = 0xff; // 255
  527. if (styles[track_style].dash) {
  528. track_temp->line_color.opacity = 0x50;
  529. }
  530. // track width, from 1=hairline to 4=thick in Topo - not assigned before 2012
  531. // (what are correct values for KML or other outputs??)
  532. track_temp->line_width = styles[track_style].wide;
  533. if (DEBUG) printf("Track Name: %s, ?Type?: %d, Style Name: %s, Width: %d, Dashed: %d, Color: #%s\n",
  534. qPrintable(track_name), line_type, styles[track_style].name, styles[track_style].wide, styles[track_style].dash,rgb);
  535. // Track description
  536. track_temp->rte_desc =
  537. QString().sprintf("Style=%s, Width=%d, Dashed=%d, Color=#%s",
  538. styles[track_style].name, styles[track_style].wide,
  539. styles[track_style].dash, rgb);
  540. // Route number
  541. track_temp->rte_num = ii + 1;
  542. //UNKNOWN DATA LENGTH
  543. track_byte_count = tpo_read_int();
  544. // Read the number of bytes specified for the track. These
  545. // contain scaling factors, long/lat's, and offsets from
  546. // those long/lat's. First will be a long/lat (8 bytes).
  547. // Keep track of the bytes as we go so that we know how many
  548. // we've read. We need to do this so that we start at the
  549. // proper place for the next track.
  550. // Read the track bytes into a buffer
  551. buf = (unsigned char*) xmalloc(track_byte_count);
  552. gbfread(buf, 1, track_byte_count, tpo_file_in);
  553. latscale=0;
  554. lonscale=0;
  555. // Process the track bytes
  556. llvalid = 0;
  557. for (jj = 0; jj < track_byte_count;) {
  558. Waypoint* waypoint_temp;
  559. // Time to read a new latlong?
  560. if (!llvalid) {
  561. lon = le_read32(buf+jj);
  562. jj+=4;
  563. lat = le_read32(buf+jj);
  564. jj+=4;
  565. //printf("L");
  566. // Peek to see if next is a lonscale. Note that it
  567. // can begin with 0x88, which is confusing. Here we
  568. // allow up to 16-bits of offset, so two of the
  569. // bytes must be 0x00 for us to recognize it.
  570. if (jj+3<track_byte_count
  571. && !buf[jj+3]
  572. && !buf[jj+2]) {
  573. lonscale = le_read32(buf+jj);
  574. //printf(" LONSCALE:");
  575. //printf("%02x%02x%02x%02x", buf[jj], buf[jj+1], buf[jj+2], buf[jj+3]);
  576. jj+=4;
  577. }
  578. // Peek to see if next is a latscale. Note that it
  579. // can begin with 0x88, which is confusing. Here we
  580. // allow up to 16-bits of offset, so two of the
  581. // bytes must be 0x00 for us to recognize it.
  582. if (jj+3<track_byte_count
  583. && !buf[jj+3]
  584. && !buf[jj+2]) {
  585. latscale = le_read32(buf+jj);
  586. //printf(" LATSCALE:");
  587. //printf("%02x%02x%02x%02x ", buf[jj], buf[jj+1], buf[jj+2], buf[jj+3]);
  588. jj+=4;
  589. }
  590. llvalid = 1;
  591. waypoint_temp = tpo_convert_ll(lat, lon);
  592. track_add_wpt(track_temp, waypoint_temp);
  593. waypoint_count++;
  594. }
  595. // Check whether there's a lonlat coming up instead of
  596. // offsets.
  597. else if (buf[jj] == 0x88) {
  598. jj++;
  599. llvalid = 0;
  600. }
  601. // Check whether there's a lonlat + lonscale/latscale
  602. // combo embedded in this track next.
  603. else if (buf[jj] == 0x00) {
  604. //printf(" ZERO ");
  605. jj++;
  606. llvalid = 0;
  607. }
  608. // Process the delta
  609. else {
  610. int scarray[] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};
  611. if (buf[jj] == 0) {
  612. printf("Found unexpected ZERO\n");
  613. exit(1);
  614. }
  615. if (latscale == 0 || lonscale == 0) {
  616. printf("Found bad scales lonscale=0x%x latscale=0x%x\n", lonscale, latscale);
  617. exit(1);
  618. }
  619. lon+=lonscale*scarray[buf[jj]>>4];
  620. lat+=latscale*scarray[(buf[jj]&0xf)];
  621. //printf(".");
  622. jj++;
  623. waypoint_temp = tpo_convert_ll(lat, lon);
  624. track_add_wpt(track_temp, waypoint_temp);
  625. waypoint_count++;
  626. }
  627. }
  628. xfree(buf);
  629. }
  630. }
  631. // Global index to waypoints, needed for routes, filled in by
  632. // tpo_process_waypoints.
  633. //
  634. // For version 3.x files.
  635. //
  636. Waypoint** tpo_wp_index;
  637. unsigned int tpo_index_ptr;
  638. // Waypoint decoder for version 3.x files.
  639. //
  640. void tpo_process_waypoints(void)
  641. {
  642. unsigned int waypoint_count;
  643. unsigned int ii;
  644. //printf("Processing Waypoints...\n");
  645. // Find block 0x0e0000 (GPS-Waypoints)
  646. if (tpo_find_block(0x0e0000)) {
  647. return;
  648. }
  649. // Read the number of waypoints. 8/16/32-bit value.
  650. waypoint_count = tpo_read_int();
  651. //printf("Total Waypoints: %d\n", waypoint_count);
  652. // Fetch storage for the waypoint index (needed later for
  653. // routes)
  654. tpo_wp_index = (Waypoint**) xmalloc(sizeof(Waypoint*) * waypoint_count);
  655. tpo_index_ptr = 0;
  656. if (waypoint_count == 0) {
  657. return;
  658. }
  659. // Read/process each waypoint in the file
  660. for (ii = 0; ii < waypoint_count; ii++) {
  661. Waypoint* waypoint_temp;
  662. Waypoint* waypoint_temp2;
  663. unsigned int name_length;
  664. int lat;
  665. int lon;
  666. int altitude;
  667. //UNKNOWN DATA LENGTH
  668. (void)tpo_read_int(); // 0x00
  669. //UNKNOWN DATA LENGTH
  670. (void)tpo_read_int(); // 0x00
  671. //UNKNOWN DATA LENGTH
  672. // Fetch name length
  673. name_length = tpo_read_int();
  674. QString waypoint_name;
  675. if (name_length) {
  676. gbfread(waypoint_name, 1, name_length, tpo_file_in);
  677. } else { // Assign a generic waypoint name
  678. waypoint_name = "WPT ";
  679. waypoint_name += QString::number(ii + 1);
  680. }
  681. //UNKNOWN DATA LENGTH
  682. (void)tpo_read_int();
  683. lon = gbfgetint32(tpo_file_in);
  684. lat = gbfgetint32(tpo_file_in);
  685. // Allocate space for waypoint and store lat/lon
  686. waypoint_temp = tpo_convert_ll(lat, lon);
  687. // Assign the waypoint name
  688. waypoint_temp->shortname = waypoint_name;
  689. // Grab the altitude in centimeters
  690. altitude = gbfgetint32(tpo_file_in);
  691. // The original untested check for unknown altitude was for 0xfffd000c (-196596 cm),
  692. // but a test case submitted later used 0xffce0000 (-3276800 cm).
  693. if (altitude == -3276800) { // Unknown altitude
  694. /* this is unecessary, the constructor will do this anyway. */
  695. waypoint_temp->altitude = unknown_alt;
  696. } else {
  697. waypoint_temp->altitude = (double) altitude / 100.0; // Meters
  698. }
  699. //printf("\tAltitude: %1.2f meters\n", waypoint_temp->altitude);
  700. //UNKNOWN DATA LENGTH
  701. // Fetch comment length
  702. name_length = tpo_read_int();
  703. //printf("\tComment length: %d\n", name_length);
  704. if (name_length) {
  705. char* comment;
  706. comment = (char*) xmalloc(name_length+1);
  707. comment[0] = '\0';
  708. gbfread(comment, 1, name_length, tpo_file_in);
  709. comment[name_length] = '\0'; // Terminator
  710. waypoint_temp->description = comment;
  711. xfree(comment);
  712. }
  713. // waypoint_temp->notes = NULL;
  714. // waypoint_temp->url = NULL;
  715. // waypoint_temp->url_link_text = NULL;
  716. // For routes (later), we need a duplicate of each waypoint
  717. // indexed by the order we read them in.
  718. waypoint_temp2 = new Waypoint(*waypoint_temp);
  719. // Attach the copy to our index
  720. tpo_wp_index[tpo_index_ptr++] = waypoint_temp2;
  721. // Add the original waypoint to the chain of waypoints
  722. waypt_add(waypoint_temp);
  723. //UNKNOWN DATA LENGTH
  724. // (void)tpo_read_int();
  725. (void) gbfgetc(tpo_file_in);
  726. //UNKNOWN DATA LENGTH
  727. // (void)tpo_read_int();
  728. (void) gbfgetc(tpo_file_in);
  729. //UNKNOWN DATA LENGTH
  730. // (void)tpo_read_int();
  731. (void) gbfgetc(tpo_file_in);
  732. //UNKNOWN DATA LENGTH
  733. // (void)tpo_read_int();
  734. (void) gbfgetc(tpo_file_in);
  735. }
  736. }
  737. // Map Notes decoder for version 3.x files.
  738. //
  739. void tpo_process_map_notes(void)
  740. {
  741. unsigned int waypoint_count;
  742. unsigned int ii;
  743. //printf("Processing Map Notes...\n");
  744. // Find block 0x090000 (Map Notes)
  745. if (tpo_find_block(0x090000)) {
  746. return;
  747. }
  748. // Read the number of waypoints. 8/16/32-bit value.
  749. waypoint_count = tpo_read_int();
  750. //printf("Elements: %d\n", waypoint_count);
  751. if (!waypoint_count) {
  752. return;
  753. }
  754. // Process each waypoint
  755. for (ii = 0; ii < waypoint_count; ii++) {
  756. int lat;
  757. int lon;
  758. unsigned int name_length;
  759. Waypoint* waypoint_temp;
  760. unsigned int num_bytes;
  761. unsigned int jj;
  762. //UNKNOWN DATA LENGTH
  763. (void)tpo_read_int();
  764. lon = gbfgetint32(tpo_file_in);
  765. lat = gbfgetint32(tpo_file_in);
  766. // Allocate space for waypoint and store lat/lon
  767. waypoint_temp = tpo_convert_ll(lat, lon);
  768. // Assign a generic waypoint name
  769. waypoint_temp->shortname = QString().sprintf("NOTE %d", ii + 1);
  770. //UNKNOWN DATA LENGTH
  771. (void)tpo_read_int();
  772. //UNKNOWN DATA LENGTH
  773. (void)tpo_read_int();
  774. //UNKNOWN DATA LENGTH
  775. (void)tpo_read_int();
  776. //UNKNOWN DATA LENGTH
  777. // Fetch comment length
  778. name_length = tpo_read_int();
  779. if (name_length) {
  780. char* comment;
  781. comment = (char*) xmalloc(name_length+1);
  782. comment[0] = '\0';
  783. gbfread(comment, 1, name_length, tpo_file_in);
  784. comment[name_length] = '\0'; // Terminator
  785. waypoint_temp->description = comment;
  786. xfree(comment);
  787. //printf("Comment: %s\n", comment);
  788. } else {
  789. // waypoint_temp->description = NULL;
  790. }
  791. // waypoint_temp->url_link_text = NULL;
  792. // Length of text for external path. If non-zero, skip past
  793. // the text.
  794. //UNKNOWN DATA LENGTH
  795. name_length = tpo_read_int();
  796. //printf("name_length: %x\n", name_length);
  797. if (name_length) {
  798. char* notes;
  799. notes = (char*) xmalloc(name_length+1);
  800. notes[0] = '\0';
  801. gbfread(notes, 1, name_length, tpo_file_in);
  802. notes[name_length] = '\0'; // Terminator
  803. waypoint_temp->AddUrlLink(notes);
  804. //printf("Notes: %s\n", notes);
  805. xfree(notes);
  806. }
  807. // Length of text for image path. If non-zero, skip past
  808. // the text.
  809. //UNKNOWN DATA LENGTH
  810. name_length = tpo_read_int();
  811. if (name_length) {
  812. char* notes;
  813. notes = (char*) xmalloc(name_length+1);
  814. notes[0] = '\0';
  815. gbfread(notes, 1, name_length, tpo_file_in);
  816. notes[name_length] = '\0'; // Terminator
  817. waypoint_temp->AddUrlLink(notes);
  818. //printf("Notes: %s\n", notes);
  819. xfree(notes);
  820. }
  821. //UNKNOWN DATA LENGTH
  822. (void)tpo_read_int();
  823. //UNKNOWN DATA LENGTH
  824. (void)tpo_read_int();
  825. // Number of bytes to skip until next element or end of
  826. // block. May be 8/16/32 bits.
  827. num_bytes = tpo_read_int();
  828. //printf("num_bytes: %x\n", num_bytes);
  829. for (jj = 0; jj < num_bytes; jj++) {
  830. (void) gbfgetc(tpo_file_in); // Skip bytes
  831. }
  832. // Can be 8/16/32 bits
  833. (void)tpo_read_int();
  834. //UNKNOWN DATA LENGTH
  835. (void)tpo_read_int();
  836. // Add the waypoint to the chain of waypoints
  837. waypt_add(waypoint_temp);
  838. }
  839. }
  840. // Symbols decoder for version 3.x files.
  841. //
  842. void tpo_process_symbols(void)
  843. {
  844. unsigned int waypoint_count;
  845. unsigned int ii;
  846. //printf("Processing Symbols...\n");
  847. // Find block 0x040000 (Symbols)
  848. if (tpo_find_block(0x040000)) {
  849. return;
  850. }
  851. // Read the number of waypoints. 8/16/32-bit value.
  852. waypoint_count = tpo_read_int();
  853. //printf("Elements: %d\n", waypoint_count);
  854. if (!waypoint_count) {
  855. return;
  856. }
  857. // Process each waypoint
  858. for (ii = 0; ii < waypoint_count; ii++) {
  859. int lat;
  860. int lon;
  861. Waypoint* waypoint_temp;
  862. //UNKNOWN DATA LENGTH
  863. (void)tpo_read_int();
  864. //UNKNOWN DATA LENGTH
  865. (void)tpo_read_int();
  866. lon = gbfgetint32(tpo_file_in);
  867. lat = gbfgetint32(tpo_file_in);
  868. // Allocate space for waypoint and store lat/lon
  869. waypoint_temp = tpo_convert_ll(lat, lon);
  870. // Assign a generic waypoint name
  871. waypoint_temp->shortname = QString().sprintf("SYM %d", ii + 1);
  872. // waypoint_temp->description = NULL;
  873. // waypoint_temp->notes = NULL;
  874. // waypoint_temp->url = NULL;
  875. // waypoint_temp->url_link_text = NULL;
  876. // Add the waypoint to the chain of waypoints
  877. waypt_add(waypoint_temp);
  878. }
  879. }
  880. // Text Labels decoder for version 3.x files.
  881. //
  882. void tpo_process_text_labels(void)
  883. {
  884. unsigned int waypoint_count;
  885. unsigned int ii;
  886. //printf("Processing Text Labels...\n");
  887. // Find block 0x080000 (Text Labels)
  888. if (tpo_find_block(0x080000)) {
  889. return;
  890. }
  891. // Read the number of waypoints. 8/16/32-bit value.
  892. waypoint_count = tpo_read_int();
  893. //printf("Elements: %d\n", waypoint_count);
  894. if (!waypoint_count) {
  895. return;
  896. }
  897. // Process each waypoint
  898. for (ii = 0; ii < waypoint_count; ii++) {
  899. int jj;
  900. int lat;
  901. int lon;
  902. unsigned int name_length;
  903. Waypoint* waypoint_temp;
  904. //UNKNOWN DATA LENGTH
  905. (void)tpo_read_int();
  906. //UNKNOWN DATA LENGTH
  907. (void)tpo_read_int();
  908. lon = gbfgetint32(tpo_file_in);
  909. lat = gbfgetint32(tpo_file_in);
  910. // Allocate space for waypoint and store lat/lon
  911. waypoint_temp = tpo_convert_ll(lat, lon);
  912. // Assign a generic waypoint name
  913. waypoint_temp->shortname = QString().sprintf("TXT %d", ii + 1);
  914. for (jj = 0; jj < 16; jj++) {
  915. //UNKNOWN DATA LENGTH
  916. (void) gbfgetc(tpo_file_in);
  917. }
  918. // Fetch comment length
  919. //UNKNOWN DATA LENGTH
  920. name_length = tpo_read_int();
  921. if (name_length) {
  922. char* comment;
  923. comment = (char*) xmalloc(name_length+1);
  924. comment[0] = '\0';
  925. gbfread(comment, 1, name_length, tpo_file_in);
  926. comment[name_length] = '\0'; // Terminator
  927. waypoint_temp->description = comment;
  928. xfree(comment);
  929. //printf("Comment: %s\n", comment);
  930. } else {
  931. // waypoint_temp->description = NULL;
  932. }
  933. // waypoint_temp->notes = NULL;
  934. // waypoint_temp->url = NULL;
  935. // waypoint_temp->url_link_text = NULL;
  936. // Add the waypoint to the chain of waypoints
  937. waypt_add(waypoint_temp);
  938. }
  939. }
  940. // Route decoder for version 3.x files.
  941. //
  942. // We depend on tpo_wp_index[] having been malloc'ed and filled-in
  943. // with pointers to waypoint objects by tpo_process_waypoints()
  944. // function above.
  945. //
  946. void tpo_process_routes(void)
  947. {
  948. unsigned int route_count;
  949. unsigned int ii;
  950. //printf("Processing Routes...\n");
  951. // Find block 0x0f0000 (GPS-Routes)
  952. if (tpo_find_block(0x0f0000)) {
  953. return;
  954. }
  955. // Read the number of routes. 8/16/32-bit value
  956. route_count = tpo_read_int();
  957. //printf("Total Routes: %d\n", route_count);
  958. if (route_count == 0) {
  959. return;
  960. }
  961. // Read/process each route in the file
  962. //
  963. for (ii = 0; ii < route_count; ii++) {
  964. unsigned int name_length = 0;
  965. unsigned int jj;
  966. unsigned int waypoint_cnt;
  967. route_head* route_temp;
  968. // Allocate the route struct
  969. route_temp = route_head_alloc();
  970. route_add_head(route_temp);
  971. //UNKNOWN DATA LENGTH
  972. (void)tpo_read_int();
  973. //UNKNOWN DATA LENGTH
  974. (void)tpo_read_int();
  975. //UNKNOWN DATA LENGTH
  976. // Fetch name length
  977. name_length = tpo_read_int();
  978. QString route_name;
  979. if (name_length) {
  980. //route_name = (char*) xmalloc(name_length+1);
  981. //route_name[0] = '\0';
  982. gbfread(route_name, 1, name_length, tpo_file_in);
  983. //route_name[name_length] = '\0'; // Terminator
  984. } else { // Assign a generic route name
  985. route_name = "RTE ";
  986. route_name += QString::number(ii + 1);
  987. }
  988. route_temp->rte_name = route_name;
  989. //printf("Route Name: %s\n", route_name);
  990. //UNKNOWN DATA LENGTH
  991. // Comment?
  992. (void)tpo_read_int();
  993. // gbfgetc(tpo_file_in);
  994. // route_temp->rte_desc = NULL;
  995. route_temp->rte_num = ii + 1;
  996. // Fetch the number of waypoints in this route. 8/16/32-bit
  997. // value.
  998. waypoint_cnt = tpo_read_int();
  999. // Run through the list of waypoints, look up each in our
  1000. // index, then add the waypoint to this route.
  1001. //
  1002. for (jj = 0; jj < waypoint_cnt; jj++) {
  1003. Waypoint* waypoint_temp;
  1004. unsigned int val;
  1005. //UNKNOWN DATA LENGTH
  1006. // Fetch the index to the waypoint
  1007. val = tpo_read_int();
  1008. //printf("val: %x\t\t", val);
  1009. // Duplicate a waypoint from our index of waypoints.
  1010. waypoint_temp = new Waypoint(*tpo_wp_index[val-1]);
  1011. // Add the waypoint to the route
  1012. route_add_wpt(route_temp, waypoint_temp);
  1013. }
  1014. //printf("\n");
  1015. }
  1016. }
  1017. // Compass decoder for version 3.x files.
  1018. //
  1019. void tpo_process_compass(void)
  1020. {
  1021. // Not implemented yet
  1022. }
  1023. // Decoder for version 3.x files. These files have "tracks"
  1024. // (called "freehand routes" or just "routes" in Topo), "waypoints",
  1025. // and "gps-routes". We intend to read all three types.
  1026. //
  1027. void tpo_read_3_x(void)
  1028. {
  1029. if (doing_trks) {
  1030. //printf("Processing Tracks\n");
  1031. tpo_process_tracks();
  1032. }
  1033. if (doing_wpts || doing_rtes) {
  1034. //printf("Processing Waypoints\n");
  1035. tpo_process_waypoints();
  1036. }
  1037. if (doing_rtes) {
  1038. //
  1039. // Note: To process routes we _MUST_ process waypoints
  1040. // first! This creates the index of waypoints that we need
  1041. // for routes.
  1042. //
  1043. //printf("Processing Routes\n");
  1044. tpo_process_routes();
  1045. }
  1046. if (doing_wpts) {
  1047. //
  1048. // Other blocks in the file have waypoint-type information
  1049. // in them. Map Notes, Symbols, and Text Labels. We
  1050. // process those here and add them to the end of the
  1051. // waypoint list.
  1052. //
  1053. //printf("Processing Map Notes\n");
  1054. tpo_process_map_notes();
  1055. //printf("Processing Symbols\n");
  1056. tpo_process_symbols();
  1057. //printf("Processing Text Labels\n");
  1058. tpo_process_text_labels();
  1059. //printf("Processing Compass Symbols\n");
  1060. // tpo_process_compass();
  1061. }
  1062. }
  1063. //-------------------------------------------------------------------
  1064. //-------------------------------------------------------------------
  1065. static void
  1066. tpo_rd_init(const QString& fname)
  1067. {
  1068. // preprare for an attempt to deallocate memory that may or may not get allocated
  1069. // depending on the options used.
  1070. tpo_index_ptr = 0;
  1071. tpo_wp_index = NULL;
  1072. tpo_file_in = gbfopen_le(fname, "rb", MYNAME);
  1073. tpo_check_version_string();
  1074. if (tpo_version == 2.0) {
  1075. if (doing_wpts || doing_rtes) {
  1076. fatal(MYNAME ": this file format only supports tracks, not waypoints or routes.\n");
  1077. }
  1078. /*fprintf(stderr,"Version 2.x, Looking for CTopoRoute\n"); */
  1079. /* Back up 18 bytes if this section found */
  1080. tpo_read_until_section("CTopoRoute", -18);
  1081. } else if (tpo_version == 3.0) {
  1082. /*fprintf(stderr,"Version 3.x, Looking for 'Red Without Arrow'\n"); */
  1083. /* Go forward four more bytes if this section found. "IEND"
  1084. * plus four bytes is the end of the embedded PNG image */
  1085. tpo_read_until_section("Red Without Arrow", 17);
  1086. } else {
  1087. fatal(MYNAME ": gpsbabel can only read TPO versions through 3.x.x\n");
  1088. }
  1089. }
  1090. static void
  1091. tpo_rd_deinit(void)
  1092. {
  1093. unsigned int i;
  1094. // Free the waypoint index, we don't need it anymore.
  1095. for (i = 0; i < tpo_index_ptr; i++) {
  1096. delete tpo_wp_index[i];
  1097. }
  1098. tpo_index_ptr = 0;
  1099. // Free the index array itself
  1100. if (tpo_wp_index) {
  1101. xfree(tpo_wp_index);
  1102. tpo_wp_index = NULL;
  1103. }
  1104. gbfclose(tpo_file_in);
  1105. }
  1106. static void
  1107. tpo_read(void)
  1108. {
  1109. if (tpo_version == 2.0) {
  1110. //printf("\nFound a version 2.x file\n");
  1111. tpo_read_2_x();
  1112. } else if (tpo_version == 3.0) {
  1113. //printf("\nFound a version 3.x file\n");
  1114. tpo_read_3_x();
  1115. } else {
  1116. fatal(MYNAME ": gpsbabel can only read TPO versions through 3.x.x\n");
  1117. }
  1118. }
  1119. /*******************************************************************************/
  1120. /* WRITE */
  1121. /*******************************************************************************/
  1122. /* tpo_write_file_header()
  1123. Write the appropriate header for the desired TOPO! state.
  1124. National Geographic sells about 75 different state and regional software
  1125. programs called TOPO! that use the TPO format. Each one uses a different
  1126. header data sequence. The header contains the name of the state maps, as well
  1127. as some map scaling information and other data. In most cases, you can't open
  1128. a TPO file created by a different state/regional version of TOPO! than the one
  1129. you're using yourself. When writing a TPO file, it is therefore necessary to
  1130. specify what TOPO! state product to create the file for. I believe that the
  1131. TOPO! regional products can open TPO files created by the TOPO! state products
  1132. as long as the track data is within the area covered by the regional product.
  1133. As a result, it's only necessary to decide what state product output format to
  1134. use.
  1135. TO ADD SUPPORT FOR ANOTHER STATE:
  1136. 1. Obtain an example .tpo file generated by the state product for which you wish
  1137. to add support. National Geographic MapXchange (http://maps.nationalgeographic.com/topo/search.cfm)
  1138. is a good source of .tpo files.
  1139. 2. Run gpsbabel using the "dumpheader" option of the TPO format converter, and
  1140. specifying a dummy output file. For example:
  1141. gpsbabel -t -i tpo,dumpheader=1 -f sample_file.tpo -o csv -F dummy.txt
  1142. This will write a snippet of C code containing the header bytes to the shell window.
  1143. 3. Add a new if() clause to tpo_write_file_header(). Copy the header bytes definition
  1144. from the previous step.
  1145. 4. Recompile gpsbabel.
  1146. 5. You should now be able write TPO ouput in the new state's format. For example, if
  1147. you added support for Texas:
  1148. gpsbabel -t -i gpx -f input.gpx -o tpo,state="TX" -F output.tpo */
  1149. static void
  1150. tpo_write_file_header()
  1151. {
  1152. /* force upper-case state name */
  1153. strupper(output_state);
  1154. if (strncmp("CA", output_state, 2) == 0) {
  1155. unsigned char header_bytes[] = {
  1156. 0x18, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72,
  1157. 0x6E, 0x69, 0x61, 0x20, 0x53, 0x68, 0x61, 0x64,
  1158. 0x65, 0x64, 0x20, 0x52, 0x65, 0x6C, 0x69, 0x65,
  1159. 0x66, 0x03, 0x43, 0x41, 0x31, 0x05, 0x00, 0x00,
  1160. 0x00, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x40, 0x00,
  1161. 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x00,
  1162. 0x00, 0x00, 0x00, 0x00, 0x80, 0x5C, 0x40, 0x00,
  1163. 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00,
  1164. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1165. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1166. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1167. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1168. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1169. 0x00, 0x00, 0x00, 0x00, 0x27, 0x43, 0x3A, 0x5C,
  1170. 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20,
  1171. 0x46, 0x69, 0x6C, 0x65, 0x73, 0x5C, 0x54, 0x4F,
  1172. 0x50, 0x4F, 0x21, 0x5C, 0x54, 0x50, 0x4F, 0x5F,
  1173. 0x44, 0x41, 0x54, 0x41, 0x5C, 0x43, 0x41, 0x5F,
  1174. 0x44, 0x30, 0x31, 0x5C, 0x20, 0x43, 0x3A, 0x5C,
  1175. 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20,
  1176. 0x46, 0x69, 0x6C, 0x65, 0x73, 0x5C, 0x54, 0x4F,
  1177. 0x50, 0x4F, 0x21, 0x5C, 0x54, 0x50, 0x4F, 0x5F,
  1178. 0x44, 0x41, 0x54, 0x41, 0x5C, 0x12, 0x43, 0x3A,
  1179. 0x5C, 0x54, 0x4F, 0x50, 0x4F, 0x21, 0x5C, 0x54,
  1180. 0x50, 0x4F, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5C,
  1181. 0x00, 0x00, 0x00, 0xDC, 0x30, 0x32, 0x30, 0x32,
  1182. 0x30, 0x32, 0x30, 0x33, 0x30, 0x33, 0x30, 0x30,
  1183. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1184. 0x30, 0x30, 0x30, 0x32, 0x30, 0x32, 0x30, 0x32,
  1185. 0x30, 0x33, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
  1186. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1187. 0x30, 0x34, 0x30, 0x34, 0x30, 0x34, 0x30, 0x34,
  1188. 0x30, 0x36, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30,
  1189. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1190. 0x30, 0x35, 0x30, 0x35, 0x30, 0x34, 0x30, 0x36,
  1191. 0x30, 0x36, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30,
  1192. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x35,
  1193. 0x30, 0x35, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37,
  1194. 0x30, 0x37, 0x30, 0x38, 0x30, 0x30, 0x30, 0x30,
  1195. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x35,
  1196. 0x30, 0x35, 0x30, 0x37, 0x30, 0x37, 0x30, 0x37,
  1197. 0x30, 0x38, 0x30, 0x38, 0x30, 0x39, 0x30, 0x30,
  1198. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x35,
  1199. 0x31, 0x30, 0x30, 0x38, 0x30, 0x38, 0x30, 0x38,
  1200. 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x30, 0x30,
  1201. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30,
  1202. 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31,
  1203. 0x30, 0x39, 0x30, 0x39, 0x30, 0x30, 0x30, 0x30,
  1204. 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30,
  1205. 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
  1206. 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1207. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31,
  1208. 0x31, 0x31, 0x31, 0x31, 0x30, 0x39, 0x30, 0x39,
  1209. 0x0D, 0x55, 0x6E, 0x69, 0x74, 0x65, 0x64, 0x20,
  1210. 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x00, 0x00,
  1211. 0x00, 0x00, 0x00, 0x40, 0x5F, 0x40, 0xBC, 0x23,
  1212. 0x63, 0xB5, 0xF9, 0x3A, 0x50, 0x40, 0x00, 0x00,
  1213. 0x00, 0x00, 0x00, 0x80, 0x50, 0x40, 0x22, 0xE2,
  1214. 0xE6, 0x54, 0x32, 0x28, 0x22, 0x40, 0x0A, 0x43,
  1215. 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69,
  1216. 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5F,
  1217. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45,
  1218. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5C,
  1219. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
  1220. 0x40, 0x16, 0x2A, 0x47, 0x65, 0x6E, 0x65, 0x72,
  1221. 0x61, 0x6C, 0x20, 0x52, 0x65, 0x66, 0x65, 0x72,
  1222. 0x65, 0x6E, 0x63, 0x65, 0x20, 0x4D, 0x61, 0x70,
  1223. 0x00, 0x09, 0x3D, 0x00, 0x0C, 0x43, 0x41, 0x31,
  1224. 0x5F, 0x4D, 0x41, 0x50, 0x31, 0x5C, 0x53, 0x31,
  1225. 0x4C, 0xAF, 0x02, 0x15, 0x03, 0x00, 0x00, 0x00,
  1226. 0x00, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x00,
  1227. 0x00, 0x00, 0x00, 0x24, 0x40, 0x84, 0x00, 0x78,
  1228. 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16,
  1229. 0x2A, 0x4E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x61,
  1230. 0x6C, 0x20, 0x41, 0x74, 0x6C, 0x61, 0x73, 0x20,
  1231. 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0xE8, 0x32,
  1232. 0x0D, 0x00, 0x02, 0x44, 0x41, 0x23, 0x01, 0x6C,
  1233. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
  1234. 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
  1235. 0x3F, 0x3C, 0x00, 0x3C, 0x00, 0x01, 0x00, 0x00,
  1236. 0x00, 0x01, 0x00, 0x10, 0x2A, 0x35, 0x30, 0x30,
  1237. 0x4B, 0x20, 0x4D, 0x61, 0x70, 0x20, 0x53, 0x65,
  1238. 0x72, 0x69, 0x65, 0x73, 0xC0, 0xFE, 0x04, 0x00,
  1239. 0x02, 0x44, 0x46, 0x00, 0x01, 0x40, 0x01, 0xB5,
  1240. 0x2B, 0x4C, 0x55, 0x55, 0x55, 0xD5, 0x3F, 0xB5,
  1241. 0x2B, 0x4C, 0x55, 0x55, 0x55, 0xD5, 0x3F, 0x28,
  1242. 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
  1243. 0x00, 0x10, 0x2A, 0x31, 0x30, 0x30, 0x4B, 0x20,
  1244. 0x4D, 0x61, 0x70, 0x20, 0x53, 0x65, 0x72, 0x69,
  1245. 0x65, 0x73, 0x50, 0xC3, 0x00, 0x00, 0x02, 0x44,
  1246. 0x4B, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x00,
  1247. 0x00, 0x00, 0x00, 0xB0, 0x3F, 0x00, 0x00, 0x00,
  1248. 0x00, 0x00, 0x00, 0xB0, 0x3F, 0x2D, 0x00, 0x2D,
  1249. 0x00, 0x0C, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x10,
  1250. 0x2A, 0x37, 0x2E, 0x35, 0x27, 0x20, 0x4D, 0x61,
  1251. 0x70, 0x20, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73,
  1252. 0x0F, 0x3C, 0x00, 0x00, 0x02, 0x44, 0x51, 0x00,
  1253. 0x00, 0x00, 0x01, 0x9A, 0x99, 0x99, 0x99, 0x99,
  1254. 0x99, 0x99, 0x3F, 0x9A, 0x99, 0x99, 0x99, 0x99,
  1255. 0x99, 0x89, 0x3F, 0x5A, 0x00, 0x2D, 0x00, 0x0D,
  1256. 0x00, 0x01, 0x00, 0x28, 0x00
  1257. };
  1258. gbfwrite(header_bytes, sizeof(header_bytes), 1, tpo_file_out);
  1259. } else if (strncmp("CT", output_state, 2) == 0 ||
  1260. strncmp("MA", output_state, 2) == 0 ||
  1261. strncmp("ME", output_state, 2) == 0 ||
  1262. strncmp("NJ", output_state, 2) == 0 ||
  1263. strncmp("NH", output_state, 2) == 0 ||
  1264. strncmp("NY", output_state, 2) == 0 ||
  1265. strncmp("RI", output_state, 2) == 0 ||
  1266. strncmp("VT", output_state, 2) == 0) {
  1267. /* These 8 states are all covered in a single "Northeast" title */
  1268. unsigned char header_bytes[] = {
  1269. 0x1E, 0x4E, 0x6F, 0x72, 0x74, 0x68, 0x65, 0x61,
  1270. 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x55, 0x53,
  1271. 0x41, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x64,
  1272. 0x20, 0x52, 0x65, 0x6C, 0x69, 0x65, 0x66, 0x03,
  1273. 0x4E, 0x45, 0x31, 0x05, 0x00, 0x00, 0x00, 0x00,
  1274. 0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00,
  1275. 0x00, 0x00, 0x00, 0x48, 0x40, 0x00, 0x00, 0x00,
  1276. 0x00, 0x00, 0x80, 0x50, 0x40, 0x00, 0x00, 0x00,
  1277. 0x00, 0x00, 0x00, 0x43, 0x40, 0x00, 0x00, 0x00,
  1278. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1279. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1280. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1281. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1282. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1283. 0x00, 0x00, 0x0B, 0x44, 0x3A, 0x5C, 0x4E, 0x45,
  1284. 0x31, 0x5F, 0x44, 0x30, 0x31, 0x5C, 0x12, 0x43,
  1285. 0x3A, 0x5C, 0x54, 0x4F, 0x50, 0x4F, 0x21, 0x5C,
  1286. 0x54, 0x50, 0x4F, 0x5F, 0x44, 0x41, 0x54, 0x41,
  1287. 0x5C, 0x12, 0x45, 0x3A, 0x5C, 0x54, 0x4F, 0x50,
  1288. 0x4F, 0x21, 0x5C, 0x54, 0x50, 0x4F, 0x5F, 0x44,
  1289. 0x41, 0x54, 0x41, 0x5C, 0x00, 0x00, 0x00, 0xFF,
  1290. 0x18, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1291. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1292. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37,
  1293. 0x30, 0x37, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30,
  1294. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1295. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1296. 0x30, 0x37, 0x30, 0x37, 0x30, 0x37, 0x30, 0x37,
  1297. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1298. 0x30, 0x30, 0x30, 0x30, 0x30, 0x34, 0x30, 0x34,
  1299. 0x30, 0x35, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37,
  1300. 0x30, 0x37, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30,
  1301. 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0x33,
  1302. 0x30, 0x34, 0x30, 0x34, 0x30, 0x35, 0x30, 0x35,
  1303. 0x30, 0x36, 0x30, 0x36, 0x30, 0x36, 0x30, 0x36,
  1304. 0x30, 0x36, 0x30, 0x32, 0x30, 0x32, 0x30, 0x32,
  1305. 0x30, 0x33, 0x30, 0x33, 0x30, 0x34, 0x30, 0x34,
  1306. 0x30, 0x35, 0x30, 0x35, 0x30, 0x36, 0x30, 0x36,
  1307. 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32,
  1308. 0x30, 0x32, 0x30, 0x32, 0x30, 0x33, 0x30, 0x33,
  1309. 0x30, 0x38, 0x30, 0x38, 0x30, 0x38, 0x30, 0x39,
  1310. 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1311. 0x30, 0x30, 0x30, 0x32, 0x30, 0x32, 0x30, 0x32,
  1312. 0x30, 0x33, 0x31, 0x30, 0x31, 0x30, 0x30, 0x38,
  1313. 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x30, 0x39,
  1314. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1315. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30,
  1316. 0x31, 0x30, 0x31, 0x30, 0x30, 0x39, 0x30, 0x30,
  1317. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1318. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1319. 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
  1320. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1321. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1322. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1323. 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1324. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  1325. 0x30, 0x30, 0x0D, 0x55, 0x6E, 0x69, 0x74, 0x65,
  1326. 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73,
  1327. 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x40,
  1328. 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x4E, 0x40,
  1329. 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x50, 0x40,
  1330. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x40,
  1331. 0x10, 0x4E, 0x6F, 0x72, 0x74, 0x68, 0x65, 0x61,
  1332. 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x55, 0x53,
  1333. 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
  1334. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x48,
  1335. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x50,
  1336. 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42,
  1337. 0x40, 0x16, 0x2A, 0x47, 0x65, 0x6E, 0x65, 0x72,
  1338. 0x61, 0x6C, 0x20, 0x52, 0x65, 0x66, 0x65, 0x72,
  1339. 0x65, 0x6E, 0x63, 0x65, 0x20, 0x4D, 0x61, 0x70,
  1340. 0x00, 0x09, 0x3D, 0x00, 0x0C, 0x4E, 0x45, 0x31,
  1341. 0x5F, 0x4D, 0x41, 0x50, 0x31, 0x5C, 0x53, 0x31,
  1342. 0x4C, 0x68, 0x03, 0x16, 0x03, 0x00, 0x00, 0x00,
  1343. 0x00, 0x00, 0x00, 0x2C, 0x40, 0x00, 0x00, 0x00,
  1344. 0x00, 0x00, 0x00, 0x24, 0x40, 0x8C, 0x00, 0x64,
  1345. 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16,
  1346. 0x2A, 0x4E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x61,
  1347. 0x6C, 0x20, 0x41, 0x74, 0x6C, 0x61, 0x73, 0x20,
  1348. 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0xE8, 0x32,
  1349. 0x0D, 0x00, 0x02, 0x44, 0x41, 0x0B, 0x01, 0x6C,
  1350. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
  1351. 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
  1352. 0x3F, 0x3C, 0x00, 0x3C, 0x00, 0x01, 0x00, 0x00,
  1353. 0x00, 0x01, 0x00, 0x10, 0x2A, 0x35, 0x30, 0x30,
  1354. 0x4B, 0x20, 0x4D, 0x61, 0x70, 0x20, 0x53, 0x65,
  1355. 0x72, 0x69, 0x65, 0x73, 0xC0, 0xFE, 0x04, 0x00,
  1356. 0x02, 0x44, 0x46, 0xEA, 0x00, 0x40, 0x01, 0xB5,
  1357. 0x2B, 0x4C, 0x55, 0x55, 0x55, 0xD5, 0x3F, 0xB5,
  1358. 0x2B, 0x4C, 0x55, 0x55, 0x55, 0xD5, 0x3F, 0x28,
  1359. 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
  1360. 0x00, 0x10, 0x2A, 0x31, 0x30, 0x30, 0x4B, 0x20,
  1361. 0x4D, 0x61, 0x70, 0x20, 0x53, 0x65, 0x72, 0x69,
  1362. 0x65, 0x73, 0x50, 0xC3, 0x00, 0x00, 0x02, 0x44,
  1363. 0x4B, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x00,
  1364. 0x00, 0x00, 0x00, 0xB0, 0x3F, 0x00, 0x00, 0x00,
  1365. 0x00, 0x00, 0x00, 0xB0, 0x3F, 0x2D, 0x00, 0x2D,
  1366. 0x00, 0x0C, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x10,
  1367. 0x2A, 0x37, 0x2E, 0x35, 0x27, 0x20, 0x4D, 0x61,
  1368. 0x70, 0x20, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73,
  1369. 0x0F, 0x3C, 0x00, 0x00, 0x02, 0x44, 0x51, 0x00,
  1370. 0x00, 0x00, 0x01, 0x9A, 0x99, 0x99, 0x99, 0x99,
  1371. 0x99, 0x99, 0x3F, 0x9A, 0x99, 0x99, 0x99, 0x99,
  1372. 0x99, 0x89, 0x3F, 0x5A, 0x00, 0x2D, 0x00, 0x0D,
  1373. 0x00, 0x01, 0x00, 0x28, 0x00
  1374. };
  1375. gbfwrite(header_bytes, sizeof(header_bytes), 1, tpo_file_out);
  1376. }
  1377. else {
  1378. fatal(MYNAME ": writing ouput for state \"%s\" is not currently supported.\n", output_state);
  1379. }
  1380. }
  1381. static void
  1382. tpo_track_hdr(const route_head* rte)
  1383. {
  1384. double amt;
  1385. unsigned char temp_buffer[8];
  1386. unsigned char visibility_flags[] = { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 };
  1387. unsigned char unknown1[] = { 0xFF, 0x00, 0x00, 0x00 };
  1388. unsigned char bounding_box[8] = { 0x00, 0x80, 0x00, 0x80, 0xFF, 0x7F, 0xFF, 0x7F };
  1389. Waypoint* first_track_waypoint = (Waypoint*) QUEUE_FIRST(&rte->waypoint_list);
  1390. /* zoom level 1-5 visibility flags */
  1391. gbfwrite(visibility_flags, 1, sizeof(visibility_flags), tpo_file_out);
  1392. /* 8 bytes of zeros, meaning unknown */
  1393. memset(temp_buffer, 0, sizeof(temp_buffer));
  1394. gbfwrite(temp_buffer, 1, sizeof(temp_buffer), tpo_file_out);
  1395. /* 4 more unknown bytes, possibly sign flags for the longitude and latitude? */
  1396. gbfwrite(unknown1, 1, sizeof(unknown1), tpo_file_out);
  1397. /* the starting point of the route */
  1398. /* convert lat/long to NAD27/CONUS datum */
  1399. GPS_Math_WGS84_To_Known_Datum_M(
  1400. first_track_waypoint->latitude,
  1401. first_track_waypoint->longitude,
  1402. first_track_waypoint->altitude,
  1403. &first_track_waypoint_lat,
  1404. &first_track_waypoint_lon,
  1405. &amt,
  1406. 78);
  1407. /* swap the sign back *after* the datum conversion */
  1408. first_track_waypoint_lon *= -1.0;
  1409. /* Compute this track's scaling factors: Used for scaling each track point and then
  1410. later written out to the track footer. These are approximately the ratios between
  1411. pixels and degrees when viewing the 1:24000 map in TOPO!. In practice, it doesn't
  1412. appear to be necessary that they be correct, as long as the same values are used
  1413. for doing the scaling and for writing into the track footer data. */
  1414. output_track_lat_scale = 4.8828125e-005; /* TOPO! appears to use a constant lat scale */
  1415. output_track_lon_scale = output_track_lat_scale / cos(GPS_Math_Deg_To_Rad(first_track_waypoint_lat));
  1416. /* 8 bytes - longitude */
  1417. gbfputdbl(first_track_waypoint_lon, tpo_file_out);
  1418. /* 8 bytes - latitude */
  1419. gbfputdbl(first_track_waypoint_lat, tpo_file_out);
  1420. /* 8 bytes: seems to be bounding box info */
  1421. gbfwrite(bounding_box, 1, sizeof(bounding_box), tpo_file_out);
  1422. /* number of route points */
  1423. gbfputint16(rte->rte_waypt_ct, tpo_file_out);
  1424. /* initialize the track length computation */
  1425. track_length = 0;
  1426. GPS_Math_WGS84LatLonH_To_XYZ(
  1427. first_track_waypoint->latitude,
  1428. first_track_waypoint->longitude,
  1429. 0.0,
  1430. &last_waypoint_x,
  1431. &last_waypoint_y,
  1432. &last_waypoint_z);
  1433. }
  1434. static void
  1435. tpo_track_disp(const Waypoint* waypointp)
  1436. {
  1437. double lat, lon, amt, x, y, z;
  1438. short lat_delta, lon_delta;
  1439. /* fprintf(stderr, "%f/%f\n", waypointp->latitude, waypointp->longitude); */
  1440. /* convert lat/lon position to XYZ meters */
  1441. GPS_Math_WGS84LatLonH_To_XYZ(
  1442. waypointp->latitude,
  1443. waypointp->longitude,
  1444. 0.0,
  1445. &x,
  1446. &y,
  1447. &z);
  1448. /* increase the track length by the 3D length of last track segment in feet */
  1449. track_length += METERS_TO_FEET(sqrt(
  1450. (x - last_waypoint_x) * (x - last_waypoint_x) +
  1451. (y - last_waypoint_y) * (y - last_waypoint_y) +
  1452. (z - last_waypoint_z) * (z - last_waypoint_z)));
  1453. last_waypoint_x = x;
  1454. last_waypoint_y = y;
  1455. last_waypoint_z = z;
  1456. /* convert lat/long to NAD27/CONUS datum */
  1457. GPS_Math_WGS84_To_Known_Datum_M(
  1458. waypointp->latitude,
  1459. waypointp->longitude,
  1460. waypointp->altitude,
  1461. &lat,
  1462. &lon,
  1463. &amt,
  1464. 78);
  1465. /* swap the sign back *after* the datum conversion */
  1466. lon *= -1.0;
  1467. /* longitude delta from first route point */
  1468. lon_delta = (short)((first_track_waypoint_lon - lon) / output_track_lon_scale);
  1469. gbfputint16(lon_delta, tpo_file_out);
  1470. /* latitude delta from first route point */
  1471. lat_delta = (short)((first_track_waypoint_lat - lat) / output_track_lat_scale);
  1472. gbfputint16(lat_delta, tpo_file_out);
  1473. /*
  1474. fprintf(stderr, "%f %f: %x %x - %f %f %f / %f\n", lon, lat, lon_delta, lat_delta, first_track_waypoint_lat, lat, output_track_lat_scale, (first_track_waypoint_lat - lat) );
  1475. */
  1476. }
  1477. static void
  1478. tpo_track_tlr(const route_head* rte)
  1479. {
  1480. unsigned char unknown1[] = { 0x06, 0x00 };
  1481. unsigned char continue_marker[] = { 0x01, 0x80 };
  1482. unsigned char end_marker[] = { 0x00, 0x00 };
  1483. /* pixel to degree scaling factors */
  1484. gbfputdbl(output_track_lon_scale, tpo_file_out);
  1485. gbfputdbl(output_track_lat_scale, tpo_file_out);
  1486. /* 4 bytes: the total length of the route */
  1487. gbfputint32(track_length, tpo_file_out);
  1488. /* 2 unknown bytes */
  1489. gbfwrite(unknown1, 1, sizeof(unknown1), tpo_file_out);
  1490. /* the last track ends with 0x0000 instead of 0x0180 */
  1491. track_out_count++;
  1492. if (track_out_count == track_count()) {
  1493. gbfwrite(end_marker, 1, sizeof(end_marker), tpo_file_out);
  1494. } else {
  1495. gbfwrite(continue_marker, 1, sizeof(continue_marker), tpo_file_out);
  1496. }
  1497. }
  1498. static void
  1499. tpo_wr_init(const QString& fname)
  1500. {
  1501. if (doing_wpts || doing_rtes) {
  1502. fatal(MYNAME ": this file format only supports tracks, not waypoints or routes.\n");
  1503. }
  1504. tpo_file_out = gbfopen_le(fname, "wb", MYNAME);
  1505. tpo_write_file_header();
  1506. }
  1507. static void
  1508. tpo_wr_deinit(void)
  1509. {
  1510. /* the file footer is six bytes of zeroes */
  1511. unsigned char file_footer_bytes[6];
  1512. memset(file_footer_bytes, 0, sizeof(file_footer_bytes));
  1513. gbfwrite(file_footer_bytes, 1, sizeof(file_footer_bytes), tpo_file_out);
  1514. gbfclose(tpo_file_out);
  1515. }
  1516. static void
  1517. tpo_write(void)
  1518. {
  1519. unsigned char unknown1[] = { 0xFF, 0xFF, 0x01, 0x00 };
  1520. const char* chunk_name = "CTopoRoute";
  1521. int chunk_name_length = strlen(chunk_name);
  1522. /* write the total number of tracks */
  1523. gbfputint16(track_count(), tpo_file_out);
  1524. /* 4 unknown bytes */
  1525. gbfwrite(unknown1, 1, 4, tpo_file_out);
  1526. /* chunk name: "CTopoRoute" */
  1527. gbfputint16(chunk_name_length, tpo_file_out);
  1528. gbfwrite(chunk_name, 1, chunk_name_length, tpo_file_out);
  1529. track_out_count = 0;
  1530. track_disp_all(tpo_track_hdr, tpo_track_tlr, tpo_track_disp);
  1531. }
  1532. /* TPO 2.x format can read tracks only */
  1533. ff_vecs_t tpo2_vecs = {
  1534. ff_type_file, /* ff_type_internal */
  1535. /* { ff_cap_none | ff_cap_none, ff_cap_read | ff_cap_write, ff_cap_none | ff_cap_none }, */
  1536. { ff_cap_none, ff_cap_read, ff_cap_none },
  1537. tpo_rd_init,
  1538. tpo_wr_init,
  1539. tpo_rd_deinit,
  1540. tpo_wr_deinit,
  1541. tpo_read,
  1542. tpo_write,
  1543. NULL,
  1544. tpo2_args,
  1545. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  1546. };
  1547. /* TPO 3.x format can read waypoints/tracks/routes */
  1548. ff_vecs_t tpo3_vecs = {
  1549. ff_type_file, /* ff_type_internal */
  1550. { ff_cap_read, ff_cap_read, ff_cap_read },
  1551. tpo_rd_init,
  1552. tpo_wr_init,
  1553. tpo_rd_deinit,
  1554. tpo_wr_deinit,
  1555. tpo_read,
  1556. tpo_write,
  1557. NULL,
  1558. tpo3_args,
  1559. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  1560. };