1 /*
2 Support for GPS TrackMaker data file.
3
4 Copyright (C) 2005 Gustavo Niemeyer <gustavo@niemeyer.net>.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 /*
22 * Documentation can be found at
23 * https://www.trackmaker.com/download/ref_guide_eng.pdf
24 * https://www.trackmaker.com/download/GTM211_format.pdf
25 */
26
27 #include "defs.h"
28 #include "jeeps/gpsmath.h"
29 #include <QtCore/QList>
30
31 static gbfile* file_in, *file_out;
32 static int indatum;
33 static int wp_count;
34 static int ws_count;
35 static int tr_count;
36 static int ts_count;
37 static int rt_count;
38 static int im_count;
39 static const route_head* rte_active;
40 static int start_new;
41
42 #define MYNAME "GTM"
43 #define EPOCH89DIFF 631065600
44 /* was 631076400 but that seems to include a three-hour bias */
45 #define WAYPOINTSTYLES \
46 "\xf5\xff\xff\xff\x0f\x00Times New Roman\x00\x00\x00\x00\x00\x90\x01"\
47 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
48 "\xf5\xff\xff\xff\x0f\x00Times New Roman\x01\x00\x00\x00\x00\x90\x01"\
49 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
50 "\xf5\xff\xff\xff\x0f\x00Times New Roman\x02\x00\x00\x00\x00\x90\x01"\
51 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
52 "\xf5\xff\xff\xff\x0f\x00Times New Roman\x03\x00\x00\x00\x00\x90\x01"\
53 "\x00\x00\x00\x00\x00\x00\x8b\xff\xff\xff\xff\x00\x00\x00\x00\x00\x01"
54
55 #define unknown_alt_gtm -10000000
56
57 /* Read functions, according to specification. */
58
59 #define fread_discard(a,b) gbfseek(a, (b), SEEK_CUR)
60 #define fread_byte(a) (unsigned char) gbfgetc(a)
61
62 #if 0
63 /* not used */
64 static short int
65 fread_bool(gbfile* fd)
66 {
67 char buf[2];
68 gbfread(buf, 2, 1, fd);
69 return le_read16(buf) ? 1 : 0;
70 }
71 #endif
72
73 #define fread_integer(a) gbfgetint16(a)
74 #define fread_long(a) gbfgetint32(a)
75 #define fread_single(a) gbfgetflt(a)
76 #define fread_double(a) gbfgetdbl(a)
77
78 static QString
fread_string(gbfile * fd)79 fread_string(gbfile* fd)
80 {
81 int len = fread_integer(fd);
82
83 if (len == 0) {
84 return nullptr;
85 }
86
87 char* val = (char*) xmalloc(len+1);
88 gbfread(val, 1, len, fd);
89 while (len != 0 && val[len-1] == ' ') {
90 len--;
91 }
92 val[len] = 0;
93 QString v(val);
94 xfree(val);
95 return v;
96 }
97
98 static void
fread_string_discard(gbfile * fd)99 fread_string_discard(gbfile* fd)
100 {
101 fread_string(fd);
102 }
103
104 static QString
fread_fixedstring(gbfile * fd,int len)105 fread_fixedstring(gbfile* fd, int len)
106 {
107 char* val = (char*) xmalloc(len+1);
108
109 gbfread(val, 1, len, fd);
110 while (len != 0 && val[len-1] == ' ') {
111 len--;
112 }
113 val[len] = 0;
114 QString v(val);
115 xfree(val);
116
117 return v;
118 }
119
120 /* Write functions, according to specification. */
121
122 static void
fwrite_null(gbfile * fd,int len)123 fwrite_null(gbfile* fd, int len)
124 {
125 char buf[1024];
126
127 memset(buf, 0, len);
128 gbfwrite(buf, 1, len, fd);
129 }
130
131 #define fwrite_byte(a,b) gbfputc((signed char)(b), a)
132 #define fwrite_bool(a,b) gbfputuint16((b) ? 0xffff : 0, a)
133 #define fwrite_integer(a,b) gbfputint16((b), a)
134 #define fwrite_long(a,b) gbfputint32((b), a)
135 #define fwrite_single(a,b) gbfputflt((b), a)
136 #define fwrite_double(a,b) gbfputdbl((b), a)
137
138 static void
fwrite_string(gbfile * fd,const char * str)139 fwrite_string(gbfile* fd, const char* str)
140 {
141 if (str && str[0]) {
142 int len = strlen(str);
143 fwrite_integer(fd, len);
144 gbfwrite(str, 1, len, fd);
145 } else {
146 fwrite_integer(fd, 0);
147 }
148 }
149 static void
fwrite_string(gbfile * fd,const QString & str)150 fwrite_string(gbfile* fd, const QString& str)
151 {
152 if (str.isEmpty()) {
153 fwrite_integer(fd, 0);
154 } else {
155 fwrite_integer(fd, str.length());
156 gbfwrite(CSTRc(str), 1, str.length(), fd);
157 }
158 }
159
160 static void
fwrite_fixedstring(gbfile * fd,const char * str,int fieldlen)161 fwrite_fixedstring(gbfile* fd, const char* str, int fieldlen)
162 {
163 int len = str ? strlen(str) : 0;
164
165 if (len > fieldlen) {
166 len = fieldlen;
167 }
168 if (str) {
169 gbfwrite(str, 1, len, fd);
170 }
171 for (; len != fieldlen; len++) {
172 gbfputc(' ', fd);
173 }
174 }
175
176 static void
fwrite_fixedstring(gbfile * fd,const QString & str,int fieldlen)177 fwrite_fixedstring(gbfile* fd, const QString& str, int fieldlen)
178 {
179 fwrite_fixedstring(fd, CSTR(str), fieldlen);
180 }
181
182 /* Auxiliary functions */
183
184 #define MAX_INDATUM_INDEX 263
185
186 static const int indatum_array[MAX_INDATUM_INDEX] = {
187 -1, // < 1
188 0, 0, 0, 0, 0, 0, 0, // < 8 : Adindan
189 1, // < 9 : Afgooye
190 2, // < 10 : Ain el Abd
191 -1, -1, -1, -1, // < 14
192 6, 6, 6, 6, 6, 6, 6, 6, 6, // < 23 : ARC 1950
193 7, 7, 7, // < 26 : ARC 1960
194 8, // < 27 : Ascension Island 58
195 -1, -1, -1, -1, -1, // < 32
196 13, // < 33 : Australian Geo 84
197 -1, // < 34
198 15, // < 35 : Bellevue IGN
199 16, // < 36 : Bermuda 1957
200 -1, -1, // < 38
201 17, // < 39 : Bukit Rimpah
202 18, // < 40 : Camp Area Astro
203 19, // < 41 : Campo Inchauspe
204 22, // < 42 : Canton Islan 1966
205 23, // < 43 : Cape
206 24, // < 44 : Cape Canaveral
207 26, // < 45 : Carthe
208 28, // < 46 : Chatham
209 29, // < 47 : Chua Astro
210 30, // < 48 : Corrego Alegre
211 -1, -1, // < 50
212 33, // < 51 : Djakarta (Batavia)
213 34, // < 52 : DOS 1968
214 35, // < 53 : Easter Island 1967
215 -1, // < 54
216 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, // < 69 : European 1950 Mean
217 39, // < 70 : European 1979 Mean
218 -1, // < 71
219 41, // < 72 : Gandajika
220 42, // < 73 : Geodetic Datum 49
221 -1, // < 74
222 45, // < 75 : Guam 1963
223 46, // < 76 : Gunung Segara
224 -1, // < 77
225 49, // < 78 : Hearth North
226 -1, // < 79
227 50, // < 80 : Hjorsey 1955
228 51, // < 81 : Hong Kong 1963
229 52, // < 82 : Hu-Tzu-Shan
230 53, 53, 53, 53, 53, 53, 53, // < 89 : Indian
231 -1, // < 90
232 55, // < 91 : Ireland 1965
233 -1, // < 92
234 56, // < 93 : ISTS 073 69
235 57, // < 94 : Johnston Island 61
236 58, // < 95 : Kandawala
237 59, // < 96 : Kerguelen Island
238 60, // < 97 : Kertau 48
239 -1, -1, // < 99
240 61, // < 100 : L.C. 5 Astro
241 -1, // < 101
242 63, // < 102 : Liberia 1964
243 64, 64, // < 104 : Luzon
244 -1, // < 105
245 65, // < 106 : Mahe 1971
246 -1, // < 107
247 69, // < 108 : Merchich
248 71, // < 109 : Midway Astro 61
249 73, 73, // < 111 : Minna
250 -1, // < 112
251 75, 75, 75, // < 115 : Nahrwan
252 76, // < 116 : Naparima BWI
253 3, 3, 3, // < 119 : Alaska NAD27
254 14, 14, // < 121 : Bahamas NAD27
255 20, 20, 20, 20, 20, // < 126 : Canada Mean NAD27
256 21, // < 127 : Canal Zone NAD27
257 31, // < 128 : Cuba NAD27
258 44, // < 129 : Greenland NAD27
259 -1, -1, // < 131
260 20, // < 132 : Canada Mean NAD27
261 -1, -1, -1, // < 135
262 70, // < 136 : Mexico NAD27
263 -1, -1, -1, -1, -1, -1, -1, -1, // < 144
264 80, // < 145 : Old Egyptian
265 81, // < 146 : Old Hawaiian
266 82, // < 147 : Old Hawaiian Kauai
267 83, // < 148 : Old Hawaiian Maui
268 81, // < 149 : Old Hawaiian Mean
269 84, // < 150 : Old Hawaiian Oahu
270 85, // < 151 : Oman
271 86, 86, 86, 86, 86, // < 156 : OSG Britain
272 87, // < 157 : Pico de Las Nieves
273 88, // < 158 : Pitcairn Astro 67
274 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // < 171
275 91, // < 172 : Puerto Rico
276 92, // < 173 : Pulkovo 1942
277 94, // < 174 : Quatar National
278 -1, -1, // < 176
279 95, // < 177 : Rome 1940
280 96, 96, 96, 96, 96, 96, 96, // < 184 : S-42 (Pulkovo 1942)
281 -1, // < 185
282 100, // < 186 : Santo DOS
283 99, // < 187 : Sao Braz
284 -1, -1, -1, -1, // < 191
285 105, 105, // < 193 : SAD-69/Mean
286 98, // < 194 : SAD-69/Brazil
287 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, // < 204 : SAD-69/Mean
288 106, // < 205 : South Asia
289 109, // < 206 : Tananarive 1926
290 111, // < 207 : Timbalai 1948
291 112, 112, 112, 112, // < 211 : Tokyo mean
292 113, // < 212 : Tristan Astro 1968
293 115, // < 213 : Viti Levu 1916
294 -1, -1, // < 215
295 116, // < 216 : Wake Eniwetok 1960
296 117, // < 217 : WGS 72
297 118, // < 218 : WGS 84
298 119, // < 219 : Yacare
299 120, // < 220 : Zanderij
300 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // < 231
301 98, // < 232 : SAD-69/Brazil
302 -1, -1, // < 234
303 117, // < 235 : WGS 72
304 0, // < 236 : Adindan
305 2, // < 237 : Ain el Abd
306 7, // < 238 : ARC 1960
307 8, // < 239 : Ascension Island 58
308 -1, -1, // < 241
309 52, // < 242 : Hu-Tzu-Shan
310 53, 53, 53, // < 245 : Indian
311 -1, // < 246
312 57, // < 247 : Johnston Island 61
313 64, // < 248 : Luzon
314 -1, // < 249
315 75, // < 250 : Nahrwan
316 76, // < 251 : Naparima BWI
317 -1, -1, -1, // < 254
318 82, // < 255 : Old Hawaiian Kauai
319 83, // < 256 : Old Hawaiian Maui
320 84, // < 257 : Old Hawaiian Oahu
321 -1, -1, // < 259
322 101, // < 260 : Sapper Hill 43
323 111, // < 261 : Timbalai 1948
324 112, // < 262 : Tokyo mean
325 116 // < 263 : Wake Eniwetok 1960
326 };
327
set_datum(int n)328 static void set_datum(int n)
329 {
330 indatum = -1;
331 if (n > 0 && n < MAX_INDATUM_INDEX) {
332 indatum = indatum_array[n];
333 }
334
335 if (indatum == -1) {
336 warning(MYNAME ": Unsupported datum (%d), won't convert to WGS84\n", n);
337 }
338 }
339
340 static const char* icon_descr[] = {
341 "", "Airport", "Ball Park", "Bank", "Bar", "Boat Ramp", "Campground", "Car",
342 "City (Large)", "City (Medium)", "City (Small)", "Dam", "Danger Area",
343 "Drinking Water", "Fishing Area", "Gas Station", "Glider Area", "Golf Course",
344 "Heliport", "Hotel", "Animals", "Information", "Man Overboard", "Marina",
345 "Mine", "Medical Facility", "Parachute Area", "Park", "Parking Area",
346 "Picnic Area", "Private Field", "Residence", "Restaurant", "Restroom",
347 "Scenic Area", "School", "Seaplane Base", "Shipwreck", "Shopping Center",
348 "Short Tower", "Policy Station", "Ski Resort", "Soft Field", "Swimming Area",
349 "Tall Tower", "Telephone", "Tracback Point", "Ultralight Area", "Waypoint",
350 "Boat", "Exit", "Flag", "Duck", "Buoy", "Back Track", "Beach", "Bridge",
351 "Building", "Car Repair", "Cemetery", "Church", "Civil", "Convenience Store",
352 "Crossing", "Fast Food", "Forest", "Ghost Town", "Levee", "Military",
353 "Oil Field", "Post Office", "Rv Park", "Scales", "Summit", "Toll Booth",
354 "Trail Head", "Truck Stop", "Tunnel", "Highway", "Gate", "Fall", "Fence",
355 "Mata-Burro", "Fitness Center", "Movie Theater", "Live Theater", "Zoo", "Horn",
356 "Bowling", "Car Rental", "City (Capitol)", "Controlled Area", "Stadium",
357 "Museum", "Amusement Park", "Skull", "Department Store", "Pharmacy", "Pizza",
358 "Diver Down Flag 1", "Light", "Pin", "", "Pigsty", "Tree", "Bamboo",
359 "Banana Plant", "Arrow-Down", "Bifurcation", "Cavern", "River", "Rock",
360 "Arrow-Up", "Trunk", "Soccer Field", "Sporting Court", "Flag, Green", "Trench",
361 "Ship-Yellow", "Green Sign", "Swamp", "Lake", "Stop!",
362 "Fishing Hot Spot Facility", "Speed Reducer", "Stairway", "Cactus", "Ship-Red",
363 "Letter - S", "Letter - D", "Letter - N",
364 "Crossing", "Cross", "Flag, Red", "Curve1", "Curve2", "Curve3", "Curve4",
365 "Letter - W", "Letter - L", "Letter - R", "Radio Beacon", "Road Sign",
366 "Geocache", "Geocache Found", "Traffic Light", "Bus Station", "Train Station",
367 "School", "Mile Marker", "Conservation Area", "Waypoint", "Box", "Aerial",
368 "Auto Repair", "Boat", "Exit Ramp", "Fixed Nav Aid", "Floating Buoy", "Garden",
369 "Fish Farm", "Lighthouse", "Truck Service", "Resort", "Scuba", "Shooting",
370 "Sight Seeing", "Sounding", "Winery", "Navaid, Amber", "Navaid, Black",
371 "Navaid, Blue", "Navaid, Green", "Navaid, Green/Red", "Navaid, Green/White",
372 "Navaid, Orange", "Navaid, Red", "Navaid, Red/Green", "Navaid, Red/White",
373 "Navaid, Violet", "Navaid, White", "Navaid, White/Green", "Navaid, White/Red",
374 "Buoy, White", "Dot, White", "Red Square", "Red Diamond", "Green Square",
375 "Green Diamond", "Restricted Area", "Navaid (unlit)", "Dot (Small)", "Libraries", "Waypoint", "Waypoint1",
376 "Waypoint2", "Mark (1)", "Mark (2)", "Mark (3)", "Cross (Red)", "Store",
377 "Exclamation", "Flag (EUA)", "Flag (CAN)", "Flag (BRA)", "Man", "Animals",
378 "Deer Tracks", "Tree Stand", "Bridge", "Fence", "Intersection",
379 "Non Direct Beacon", "VHF Omni Range", "Vor/Tacan", "Vor-Dme",
380 "1st Approach Fix", "Localizer Outer", "Missed Appr. Pt", "Tacan",
381 "CheckPoint", nullptr
382 };
383
384
convert_datum(double * lat,double * lon)385 static void convert_datum(double* lat, double* lon)
386 {
387 double amt;
388 if (indatum != -1 && indatum != 118) {
389 GPS_Math_Known_Datum_To_WGS84_M(*lat, *lon, 0.0,
390 lat, lon, &amt, indatum);
391 }
392 }
393
394 /* Callbacks */
395
396 static void
gtm_rd_init(const QString & fname)397 gtm_rd_init(const QString& fname)
398 {
399 file_in = gbfopen_le(fname, "rb", MYNAME);
400 int version = fread_integer(file_in);
401 QString name = fread_fixedstring(file_in, 10);
402 if (version == -29921) {
403 fatal(MYNAME ": Uncompress the file first\n");
404 }
405 if (name != "TrackMaker") {
406 fatal(MYNAME ": Invalid file format\n");
407 }
408 if (version != 211) {
409 fatal(MYNAME ": Invalid format version\n");
410 }
411
412 /* Header */
413 fread_discard(file_in, 15);
414 ws_count = fread_long(file_in);
415 fread_discard(file_in, 4);
416 wp_count = fread_long(file_in);
417 tr_count = fread_long(file_in);
418 rt_count = fread_long(file_in);
419 fread_discard(file_in, 16);
420 im_count = fread_long(file_in);
421 ts_count = fread_long(file_in);
422 fread_discard(file_in, 28);
423 fread_string_discard(file_in);
424 fread_string_discard(file_in);
425 fread_string_discard(file_in);
426 fread_string_discard(file_in);
427
428 /* User Grid and Datum */
429 fread_discard(file_in, 34);
430 set_datum(fread_integer(file_in));
431 fread_discard(file_in, 22);
432 }
433
434 static void
gtm_rd_deinit()435 gtm_rd_deinit()
436 {
437 gbfclose(file_in);
438 }
439
count_track_styles(const route_head * rte)440 static void count_track_styles(const route_head* rte)
441 {
442 if (rte->rte_waypt_ct > 0) {
443 ts_count++;
444 }
445 }
446
447 static void
gtm_wr_init(const QString & fname)448 gtm_wr_init(const QString& fname)
449 {
450 // Count the number of track style entires.
451 // We don't output a track style for any track that doesn't have any
452 // waypoints.
453 // Note that it is impossible to store a track without any waypoints
454 // in this format as every tracklog entry represents a waypoint,
455 // and a new track is defined by a tracklog entry with the tracklog flag set.
456 ts_count = 0;
457 track_disp_all(count_track_styles, nullptr, nullptr);
458
459 file_out = gbfopen_le(fname, "wb", MYNAME); /* little endian */
460
461 /* Header */
462 fwrite_integer(file_out, 211);
463 fwrite_fixedstring(file_out, "TrackMaker", 10);
464 fwrite_byte(file_out, 0);
465 fwrite_byte(file_out, 0);
466 fwrite_byte(file_out, 8);
467 fwrite_byte(file_out, 0);
468 fwrite_byte(file_out, 0);
469 fwrite_byte(file_out, 0);
470 fwrite_byte(file_out, 0);
471 fwrite_long(file_out, 0);
472 fwrite_long(file_out, 16777215);
473 fwrite_long(file_out, waypt_count() ? 4 : 0); /* num waypoint styles */
474 fwrite_long(file_out, 0);
475 fwrite_long(file_out, waypt_count()); /* num waypoints */
476 fwrite_long(file_out, track_waypt_count());
477 fwrite_long(file_out, route_waypt_count());
478 fwrite_single(file_out, 0); /* maxlon */
479 fwrite_single(file_out, 0); /* minlon */
480 fwrite_single(file_out, 0); /* maxlat */
481 fwrite_single(file_out, 0); /* minlat */
482 fwrite_long(file_out, 0);
483 fwrite_long(file_out, ts_count); /* num tracklog styles */
484 fwrite_single(file_out, 0);
485 fwrite_single(file_out, 0);
486 fwrite_bool(file_out, 0);
487 fwrite_bool(file_out, 0);
488 fwrite_bool(file_out, 0);
489 fwrite_bool(file_out, 0);
490 fwrite_bool(file_out, 0);
491 fwrite_bool(file_out, 0);
492 fwrite_bool(file_out, 0);
493 fwrite_bool(file_out, 0);
494 fwrite_bool(file_out, 0);
495 fwrite_bool(file_out, 0);
496 fwrite_string(file_out, "Times New Roman");
497 fwrite_string(file_out, "");
498 fwrite_string(file_out, "");
499 fwrite_string(file_out, "");
500
501 /* User Grid and Datum */
502 fwrite_null(file_out, 34);
503 fwrite_integer(file_out, 217); /* WGS84 */
504 fwrite_null(file_out, 22);
505 }
506
507 static void
gtm_wr_deinit()508 gtm_wr_deinit()
509 {
510 gbfclose(file_out);
511 }
512
513 static void
gtm_read()514 gtm_read()
515 {
516 route_head* trk_head = nullptr;
517 route_head* rte_head = nullptr;
518 Waypoint* wpt;
519 QList<route_head*> real_track_list;
520 unsigned int icon;
521 int i;
522
523 /* Image information */
524 for (i = 0; i != im_count; i++) {
525 fread_string_discard(file_in);
526 fread_string_discard(file_in);
527 fread_discard(file_in, 30);
528 }
529
530 /* Waypoints */
531 for (i = 0; i != wp_count; i++) {
532 wpt = new Waypoint;
533 wpt->latitude = fread_double(file_in);
534 wpt->longitude = fread_double(file_in);
535 convert_datum(&wpt->latitude, &wpt->longitude);
536 wpt->shortname = fread_fixedstring(file_in, 10);
537 wpt->description = fread_string(file_in);
538 icon = fread_integer(file_in);
539 if (icon < sizeof(icon_descr)/sizeof(char*)) {
540 wpt->icon_descr = icon_descr[icon];
541 }
542 fread_discard(file_in, 1);
543 wpt->SetCreationTime(fread_long(file_in));
544 if (wpt->creation_time.isValid()) {
545 wpt->creation_time = wpt->creation_time.addSecs(EPOCH89DIFF);
546 }
547 fread_discard(file_in, 2);
548 wpt->altitude = fread_single(file_in);
549 if (wpt->altitude == unknown_alt_gtm) {
550 wpt->altitude = unknown_alt;
551 }
552 fread_discard(file_in, 2);
553 waypt_add(wpt);
554 }
555
556 /* Waypoint Styles */
557 if (wp_count) {
558 for (i = 0; i != ws_count; i++) {
559 fread_discard(file_in, 4);
560 fread_string_discard(file_in);
561 fread_discard(file_in, 24);
562 }
563 }
564
565 /* Tracklogs */
566 for (i = 0; i != tr_count; i++) {
567 wpt = new Waypoint;
568 wpt->latitude = fread_double(file_in);
569 wpt->longitude = fread_double(file_in);
570 convert_datum(&wpt->latitude, &wpt->longitude);
571 wpt->SetCreationTime(fread_long(file_in));
572 if (wpt->creation_time.isValid()) {
573 wpt->creation_time = wpt->creation_time.addSecs(EPOCH89DIFF);
574 }
575 start_new = fread_byte(file_in);
576 wpt->altitude = fread_single(file_in);
577 if (wpt->altitude == unknown_alt_gtm) {
578 wpt->altitude = unknown_alt;
579 }
580 if (start_new || !trk_head) {
581 trk_head = new route_head;
582 track_add_head(trk_head);
583 real_track_list.append(trk_head);
584 }
585 track_add_wpt(trk_head, wpt);
586 }
587
588 /* Tracklog styles */
589 // TODO: The format document states there are ts_count tracklog style entries,
590 // and tr_count tracklog entries.
591 // Some tracklog entries may be continuation entries, so we turn these
592 // into real_track_list.size() <= tr_count tracks.
593 // If ts_count != real_track_list.size() we don't know how to line up
594 // the tracklogs, and the real tracks, with the tracklog styles.
595 if (ts_count != real_track_list.size()) {
596 warning(MYNAME ": The number of tracklog entries with the new flag "
597 "set doesn't match the number of tracklog style entries.\n"
598 " This is unexpected and may indicate a malformed input file.\n"
599 " As a result the track names may be incorrect.\n");
600 }
601 // Read the entire tracklog styles section whether we use it or not.
602 for (i = 0; i != ts_count; i++) {
603 QString tname = fread_string(file_in);
604 fread_discard(file_in, 12);
605 if (i < real_track_list.size()) {
606 trk_head = real_track_list.at(i);
607 trk_head->rte_name = tname;
608 }
609 }
610
611 /* Routes */
612 for (i = 0; i != rt_count; i++) {
613 wpt = new Waypoint;
614 wpt->latitude = fread_double(file_in);
615 wpt->longitude = fread_double(file_in);
616 convert_datum(&wpt->latitude, &wpt->longitude);
617 wpt->shortname = fread_fixedstring(file_in, 10);
618 wpt->description = fread_string(file_in);
619 QString route_name = fread_string(file_in);
620 icon = fread_integer(file_in);
621 if (icon < sizeof(icon_descr)/sizeof(char*)) {
622 wpt->icon_descr = icon_descr[icon];
623 }
624 fread_discard(file_in, 1);
625 start_new = fread_byte(file_in);
626 fread_discard(file_in, 6);
627 wpt->altitude = fread_single(file_in);
628 if (wpt->altitude == unknown_alt_gtm) {
629 wpt->altitude = unknown_alt;
630 }
631 fread_discard(file_in, 2);
632
633 if (start_new || !rte_head) {
634 rte_head = new route_head;
635 rte_head->rte_name = route_name;
636 route_add_head(rte_head);
637 }
638 route_add_wpt(rte_head, wpt);
639 }
640 }
641
icon_from_descr(const QString & descr)642 static int icon_from_descr(const QString& descr)
643 {
644 for (int i = 0; icon_descr[i]; i++) {
645 if (descr.compare(icon_descr[i]) == 0) {
646 return i;
647 }
648 }
649 return 48;
650 }
651
write_waypt(const Waypoint * wpt)652 static void write_waypt(const Waypoint* wpt)
653 {
654 fwrite_double(file_out, wpt->latitude);
655 fwrite_double(file_out, wpt->longitude);
656 fwrite_fixedstring(file_out, wpt->shortname, 10);
657 fwrite_string(file_out, wpt->description);
658 fwrite_integer(file_out, icon_from_descr(wpt->icon_descr));
659 fwrite_byte(file_out, 3);
660 if (wpt->creation_time.isValid()) {
661 fwrite_long(file_out, wpt->GetCreationTime().toTime_t()-EPOCH89DIFF);
662 } else {
663 fwrite_long(file_out, 0);
664 }
665 fwrite_integer(file_out, 0);
666 if (wpt->altitude == unknown_alt) {
667 fwrite_single(file_out, unknown_alt_gtm);
668 } else {
669 fwrite_single(file_out, wpt->altitude);
670 }
671 fwrite_integer(file_out, 0);
672 }
673
start_rte(const route_head * rte)674 static void start_rte(const route_head* rte)
675 {
676 rte_active = rte;
677 start_new = 1;
678 }
679
write_trk_waypt(const Waypoint * wpt)680 static void write_trk_waypt(const Waypoint* wpt)
681 {
682 fwrite_double(file_out, wpt->latitude);
683 fwrite_double(file_out, wpt->longitude);
684 fwrite_long(file_out, wpt->GetCreationTime().toTime_t()-EPOCH89DIFF);
685 fwrite_byte(file_out, start_new);
686 if (wpt->altitude == unknown_alt) {
687 fwrite_single(file_out, unknown_alt_gtm);
688 } else {
689 fwrite_single(file_out, wpt->altitude);
690 }
691 start_new = 0;
692 }
693
write_trk_style(const route_head * trk)694 static void write_trk_style(const route_head* trk)
695 {
696 if (trk->rte_waypt_ct > 0) {
697 fwrite_string(file_out, trk->rte_name);
698 fwrite_byte(file_out, 1);
699 fwrite_long(file_out, 0);
700 fwrite_single(file_out, 0);
701 fwrite_byte(file_out, 0);
702 fwrite_integer(file_out, 0);
703 }
704 }
705
write_rte_waypt(const Waypoint * wpt)706 static void write_rte_waypt(const Waypoint* wpt)
707 {
708 fwrite_double(file_out, wpt->latitude);
709 fwrite_double(file_out, wpt->longitude);
710 fwrite_fixedstring(file_out, wpt->shortname, 10);
711 fwrite_string(file_out, wpt->description);
712 fwrite_string(file_out, rte_active->rte_name);
713 fwrite_integer(file_out, icon_from_descr(wpt->icon_descr));
714 fwrite_byte(file_out, 3);
715 fwrite_byte(file_out, start_new);
716 fwrite_long(file_out, 0);
717 fwrite_integer(file_out, 0);
718 if (wpt->altitude == unknown_alt) {
719 fwrite_single(file_out, unknown_alt_gtm);
720 } else {
721 fwrite_single(file_out, wpt->altitude);
722 }
723 fwrite_integer(file_out, 0);
724 start_new = 0;
725 }
726
727 static void
gtm_write()728 gtm_write()
729 {
730 waypt_disp_all(write_waypt);
731 if (waypt_count()) {
732 gbfwrite(WAYPOINTSTYLES, 1, sizeof(WAYPOINTSTYLES)-1, file_out);
733 }
734 track_disp_all(start_rte, nullptr, write_trk_waypt);
735 track_disp_all(write_trk_style, nullptr, nullptr);
736 route_disp_all(start_rte, nullptr, write_rte_waypt);
737 }
738
739 static
740 QVector<arglist_t> gtm_args = {
741 };
742
743 ff_vecs_t gtm_vecs = {
744 ff_type_file,
745 FF_CAP_RW_ALL,
746 gtm_rd_init,
747 gtm_wr_init,
748 gtm_rd_deinit,
749 gtm_wr_deinit,
750 gtm_read,
751 gtm_write,
752 nullptr,
753 >m_args,
754 CET_CHARSET_ASCII, 0, /* CET-REVIEW */
755 NULL_POS_OPS,
756 nullptr
757 };
758