2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 static void a_gpspoint_write_track ( const gchar
*name
, VikTrack
*t
, FILE *f
);
41 static void a_gpspoint_write_trackpoint ( VikTrackpoint
*tp
, FILE *f
);
42 static void a_gpspoint_write_waypoint ( const gchar
*name
, VikWaypoint
*wp
, FILE *f
);
45 /* outline for file gpspoint.c
50 get first tag, if not type, skip it.
51 if type, record type. if waypoint list, etc move on. if track, make a new track, make it current track, add it, etc.
52 if waypoint, read on and store to the waypoint.
53 if trackpoint, make trackpoint, store to current track (error / skip if none)
57 /* Thanks to etrex-cache's gpsbabel's gpspoint.c for starting me off! */
59 static char line_buffer
[2048];
61 #define GPSPOINT_TYPE_NONE 0
62 #define GPSPOINT_TYPE_WAYPOINT 1
63 #define GPSPOINT_TYPE_TRACKPOINT 2
64 /* #define GPSPOINT_TYPE_ROUTEPOINT 3 */
65 #define GPSPOINT_TYPE_TRACK 4
67 /* #define GPSPOINT_TYPE_ROUTE 5 */
69 static VikTrack
*current_track
; /* pointer to pointer to first GList */
71 static gint line_type
= GPSPOINT_TYPE_NONE
;
72 static struct LatLon line_latlon
;
73 static gchar
*line_name
;
74 static gchar
*line_comment
;
75 static gchar
*line_image
;
76 static gchar
*line_symbol
;
77 static gboolean line_newsegment
= FALSE
;
78 static gboolean line_has_timestamp
= FALSE
;
79 static time_t line_timestamp
= 0;
80 static gdouble line_altitude
= VIK_DEFAULT_ALTITUDE
;
81 static gboolean line_visible
= TRUE
;
83 static gboolean line_extended
= FALSE
;
84 static gdouble line_speed
= NAN
;
85 static gdouble line_course
= NAN
;
86 static gint line_sat
= 0;
87 static gint line_fix
= 0;
88 /* other possible properties go here */
91 static void gpspoint_process_tag ( const gchar
*tag
, gint len
);
92 static void gpspoint_process_key_and_value ( const gchar
*key
, gint key_len
, const gchar
*value
, gint value_len
);
94 static gchar
*slashdup(const gchar
*str
)
96 guint16 len
= strlen(str
);
97 guint16 need_bs_count
, i
, j
;
99 for ( i
= 0, need_bs_count
= 0; i
< len
; i
++ )
100 if ( str
[i
] == '\\' || str
[i
] == '"' )
102 rv
= g_malloc ( (len
+need_bs_count
+1) * sizeof(gchar
) );
103 for ( i
= 0, j
= 0; i
< len
; i
++, j
++ )
105 if ( str
[i
] == '\\' || str
[i
] == '"' )
113 static gchar
*deslashndup ( const gchar
*str
, guint16 len
)
115 guint16 i
,j
, bs_count
, new_len
;
116 gboolean backslash
= FALSE
;
122 for ( i
= 0, bs_count
= 0; i
< len
; i
++ )
123 if ( str
[i
] == '\\' )
129 if ( str
[i
-1] == '\\' && (len
== 1 || str
[i
-2] != '\\') )
132 new_len
= len
- bs_count
;
133 rv
= g_malloc ( (new_len
+1) * sizeof(gchar
) );
134 for ( i
= 0, j
= 0; i
< len
&& j
< new_len
; i
++ )
135 if ( str
[i
] == '\\' && !backslash
)
147 void a_gpspoint_read_file(VikTrwLayer
*trw
, FILE *f
) {
148 VikCoordMode coord_mode
= vik_trw_layer_get_coord_mode ( trw
);
149 gchar
*tag_start
, *tag_end
;
150 g_assert ( f
!= NULL
&& trw
!= NULL
);
153 line_newsegment
= FALSE
;
157 current_track
= NULL
;
158 while (fgets(line_buffer
, 2048, f
))
160 gboolean inside_quote
= 0;
161 gboolean backslash
= 0;
163 line_buffer
[strlen(line_buffer
)-1] = '\0'; /* chop off newline */
165 /* for gpspoint files wrapped inside */
166 if ( strlen(line_buffer
) >= 13 && strncmp ( line_buffer
, "~EndLayerData", 13 ) == 0 )
169 /* each line: nullify stuff, make thing if nes, free name if ness */
170 tag_start
= line_buffer
;
173 /* my addition: find first non-whitespace character. if the null, skip line. */
174 while (*tag_start
!= '\0' && isspace(*tag_start
))
176 if (tag_start
== '\0')
179 if (*tag_start
== '#')
184 inside_quote
= !inside_quote
;
185 while (*tag_end
!= '\0' && (!isspace(*tag_end
) || inside_quote
)) {
187 if (*tag_end
== '\\' && !backslash
)
191 else if (*tag_end
== '"')
192 inside_quote
= !inside_quote
;
195 gpspoint_process_tag ( tag_start
, tag_end
- tag_start
);
197 if (*tag_end
== '\0' )
200 tag_start
= tag_end
+1;
202 if (line_type
== GPSPOINT_TYPE_WAYPOINT
&& line_name
)
204 VikWaypoint
*wp
= vik_waypoint_new();
205 wp
->visible
= line_visible
;
206 wp
->altitude
= line_altitude
;
208 vik_coord_load_from_latlon ( &(wp
->coord
), coord_mode
, &line_latlon
);
210 vik_trw_layer_filein_add_waypoint ( trw
, line_name
, wp
);
211 g_free ( line_name
);
216 vik_waypoint_set_comment ( wp
, line_comment
);
222 vik_waypoint_set_image ( wp
, line_image
);
228 vik_waypoint_set_symbol ( wp
, line_symbol
);
232 else if (line_type
== GPSPOINT_TYPE_TRACK
&& line_name
)
234 VikTrack
*pl
= vik_track_new();
236 /* Thanks to Peter Jones for this Fix */
237 if (!line_name
) line_name
= g_strdup("UNK");
239 pl
->visible
= line_visible
;
243 vik_track_set_comment ( pl
, line_comment
);
247 pl
->trackpoints
= NULL
;
248 vik_trw_layer_filein_add_track ( trw
, line_name
, pl
);
249 g_free ( line_name
);
254 else if (line_type
== GPSPOINT_TYPE_TRACKPOINT
&& current_track
)
256 VikTrackpoint
*tp
= vik_trackpoint_new();
257 vik_coord_load_from_latlon ( &(tp
->coord
), coord_mode
, &line_latlon
);
258 tp
->newsegment
= line_newsegment
;
259 tp
->has_timestamp
= line_has_timestamp
;
260 tp
->timestamp
= line_timestamp
;
261 tp
->altitude
= line_altitude
;
264 tp
->speed
= line_speed
;
265 tp
->course
= line_course
;
266 tp
->nsats
= line_sat
;
267 tp
->fix_mode
= line_fix
;
270 tp
->extended
= FALSE
;
272 current_track
->trackpoints
= g_list_append ( current_track
->trackpoints
, tp
);
276 g_free ( line_name
);
279 g_free ( line_comment
);
281 g_free ( line_image
);
283 g_free ( line_symbol
);
287 line_type
= GPSPOINT_TYPE_NONE
;
288 line_newsegment
= FALSE
;
289 line_has_timestamp
= FALSE
;
291 line_altitude
= VIK_DEFAULT_ALTITUDE
;
295 line_extended
= FALSE
;
303 /* Tag will be of a few defined forms:
309 So we must determine end of tag name, start of value, end of value.
311 static void gpspoint_process_tag ( const gchar
*tag
, gint len
)
313 const gchar
*key_end
, *value_start
, *value_end
;
315 /* Searching for key end */
318 while (++key_end
- tag
< len
)
322 if (key_end
- tag
== len
)
323 return; /* no good */
325 if (key_end
- tag
== len
+ 1)
326 value_start
= value_end
= 0; /* size = 0 */
329 value_start
= key_end
+ 1; /* equal_sign plus one */
331 if (*value_start
== '"')
334 if (*value_start
== '"')
335 value_start
= value_end
= 0; /* size = 0 */
338 if (*(tag
+len
-1) == '"')
339 value_end
= tag
+ len
- 1;
345 value_end
= tag
+ len
; /* value start really IS value start. */
347 gpspoint_process_key_and_value(tag
, key_end
- tag
, value_start
, value_end
- value_start
);
352 value = NULL for none
354 static void gpspoint_process_key_and_value ( const gchar
*key
, gint key_len
, const gchar
*value
, gint value_len
)
356 if (key_len
== 4 && strncasecmp( key
, "type", key_len
) == 0 )
359 line_type
= GPSPOINT_TYPE_NONE
;
360 else if (value_len
== 5 && strncasecmp( value
, "track", value_len
) == 0 )
361 line_type
= GPSPOINT_TYPE_TRACK
;
362 else if (value_len
== 10 && strncasecmp( value
, "trackpoint", value_len
) == 0 )
363 line_type
= GPSPOINT_TYPE_TRACKPOINT
;
364 else if (value_len
== 8 && strncasecmp( value
, "waypoint", value_len
) == 0 )
365 line_type
= GPSPOINT_TYPE_WAYPOINT
;
367 /* all others are ignored */
368 line_type
= GPSPOINT_TYPE_NONE
;
370 else if (key_len
== 4 && strncasecmp( key
, "name", key_len
) == 0 && value
!= NULL
)
372 if (line_name
== NULL
)
374 line_name
= g_strndup ( value
, value_len
);
377 else if (key_len
== 7 && strncasecmp( key
, "comment", key_len
) == 0 && value
!= NULL
)
379 if (line_comment
== NULL
)
380 line_comment
= deslashndup ( value
, value_len
);
382 else if (key_len
== 5 && strncasecmp( key
, "image", key_len
) == 0 && value
!= NULL
)
384 if (line_image
== NULL
)
385 line_image
= deslashndup ( value
, value_len
);
387 else if (key_len
== 8 && strncasecmp( key
, "latitude", key_len
) == 0 && value
!= NULL
)
389 line_latlon
.lat
= g_strtod(value
, NULL
);
391 else if (key_len
== 9 && strncasecmp( key
, "longitude", key_len
) == 0 && value
!= NULL
)
393 line_latlon
.lon
= g_strtod(value
, NULL
);
395 else if (key_len
== 8 && strncasecmp( key
, "altitude", key_len
) == 0 && value
!= NULL
)
397 line_altitude
= g_strtod(value
, NULL
);
399 else if (key_len
== 7 && strncasecmp( key
, "visible", key_len
) == 0 && value
[0] != 'y' && value
[0] != 'Y' && value
[0] != 't' && value
[0] != 'T')
401 line_visible
= FALSE
;
403 else if (key_len
== 6 && strncasecmp( key
, "symbol", key_len
) == 0 && value
!= NULL
)
405 line_symbol
= g_strndup ( value
, value_len
);
407 else if (key_len
== 8 && strncasecmp( key
, "unixtime", key_len
) == 0 && value
!= NULL
)
409 line_timestamp
= g_strtod(value
, NULL
);
410 if ( line_timestamp
!= 0x80000000 )
411 line_has_timestamp
= TRUE
;
413 else if (key_len
== 10 && strncasecmp( key
, "newsegment", key_len
) == 0 && value
!= NULL
)
415 line_newsegment
= TRUE
;
417 else if (key_len
== 8 && strncasecmp( key
, "extended", key_len
) == 0 && value
!= NULL
)
419 line_extended
= TRUE
;
421 else if (key_len
== 5 && strncasecmp( key
, "speed", key_len
) == 0 && value
!= NULL
)
423 line_speed
= g_strtod(value
, NULL
);
425 else if (key_len
== 6 && strncasecmp( key
, "course", key_len
) == 0 && value
!= NULL
)
427 line_course
= g_strtod(value
, NULL
);
429 else if (key_len
== 3 && strncasecmp( key
, "sat", key_len
) == 0 && value
!= NULL
)
431 line_sat
= atoi(value
);
433 else if (key_len
== 3 && strncasecmp( key
, "fix", key_len
) == 0 && value
!= NULL
)
435 line_fix
= atoi(value
);
439 static void a_gpspoint_write_waypoint ( const gchar
*name
, VikWaypoint
*wp
, FILE *f
)
441 static struct LatLon ll
;
442 gchar
*s_lat
, *s_lon
;
443 vik_coord_to_latlon ( &(wp
->coord
), &ll
);
444 s_lat
= a_coords_dtostr(ll
.lat
);
445 s_lon
= a_coords_dtostr(ll
.lon
);
446 fprintf ( f
, "type=\"waypoint\" latitude=\"%s\" longitude=\"%s\" name=\"%s\"", s_lat
, s_lon
, name
);
450 if ( wp
->altitude
!= VIK_DEFAULT_ALTITUDE
) {
451 gchar
*s_alt
= a_coords_dtostr(wp
->altitude
);
452 fprintf ( f
, " altitude=\"%s\"", s_alt
);
457 gchar
*tmp_comment
= slashdup(wp
->comment
);
458 fprintf ( f
, " comment=\"%s\"", tmp_comment
);
459 g_free ( tmp_comment
);
463 gchar
*tmp_image
= slashdup(wp
->image
);
464 fprintf ( f
, " image=\"%s\"", tmp_image
);
465 g_free ( tmp_image
);
469 fprintf ( f
, " symbol=\"%s\"", wp
->symbol
);
472 fprintf ( f
, " visible=\"n\"" );
476 static void a_gpspoint_write_trackpoint ( VikTrackpoint
*tp
, FILE *f
)
478 static struct LatLon ll
;
479 gchar
*s_lat
, *s_lon
;
480 vik_coord_to_latlon ( &(tp
->coord
), &ll
);
482 /* TODO: modify a_coords_dtostr() to accept (optional) buffer
483 * instead of doing malloc/free everytime */
484 s_lat
= a_coords_dtostr(ll
.lat
);
485 s_lon
= a_coords_dtostr(ll
.lon
);
486 fprintf ( f
, "type=\"trackpoint\" latitude=\"%s\" longitude=\"%s\"", s_lat
, s_lon
);
490 if ( tp
->altitude
!= VIK_DEFAULT_ALTITUDE
) {
491 gchar
*s_alt
= a_coords_dtostr(tp
->altitude
);
492 fprintf ( f
, " altitude=\"%s\"", s_alt
);
495 if ( tp
->has_timestamp
)
496 fprintf ( f
, " unixtime=\"%ld\"", tp
->timestamp
);
497 if ( tp
->newsegment
)
498 fprintf ( f
, " newsegment=\"yes\"" );
501 fprintf ( f
, " extended=\"yes\"" );
502 if (!isnan(tp
->speed
)) {
503 gchar
*s_speed
= a_coords_dtostr(tp
->speed
);
504 fprintf ( f
, " speed=\"%s\"", s_speed
);
507 if (!isnan(tp
->course
)) {
508 gchar
*s_course
= a_coords_dtostr(tp
->course
);
509 fprintf ( f
, " course=\"%s\"", s_course
);
513 fprintf ( f
, " sat=\"%d\"", tp
->nsats
);
514 if (tp
->fix_mode
> 0)
515 fprintf ( f
, " fix=\"%d\"", tp
->fix_mode
);
521 static void a_gpspoint_write_track ( const gchar
*name
, VikTrack
*t
, FILE *f
)
525 gchar
*tmp_comment
= slashdup(t
->comment
);
526 fprintf ( f
, "type=\"track\" name=\"%s\" comment=\"%s\"%s\n", name
, tmp_comment
, t
->visible
? "" : " visible=\"n\"" );
527 g_free ( tmp_comment
);
530 fprintf ( f
, "type=\"track\" name=\"%s\"%s\n", name
, t
->visible
? "" : " visible=\"n\"" );
531 g_list_foreach ( t
->trackpoints
, (GFunc
) a_gpspoint_write_trackpoint
, f
);
532 fprintf ( f
, "type=\"trackend\"\n" );
535 void a_gpspoint_write_file ( VikTrwLayer
*trw
, FILE *f
)
537 GHashTable
*tracks
= vik_trw_layer_get_tracks ( trw
);
538 GHashTable
*waypoints
= vik_trw_layer_get_waypoints ( trw
);
540 fprintf ( f
, "type=\"waypointlist\"\n" );
541 g_hash_table_foreach ( waypoints
, (GHFunc
) a_gpspoint_write_waypoint
, f
);
542 fprintf ( f
, "type=\"waypointlistend\"\n" );
543 g_hash_table_foreach ( tracks
, (GHFunc
) a_gpspoint_write_track
, f
);