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
31 static void a_gpspoint_write_track ( const gchar
*name
, VikTrack
*t
, FILE *f
);
32 static void a_gpspoint_write_trackpoint ( VikTrackpoint
*tp
, FILE *f
);
33 static void a_gpspoint_write_waypoint ( const gchar
*name
, VikWaypoint
*wp
, FILE *f
);
36 /* outline for file gpspoint.c
41 get first tag, if not type, skip it.
42 if type, record type. if waypoint list, etc move on. if track, make a new track, make it current track, add it, etc.
43 if waypoint, read on and store to the waypoint.
44 if trackpoint, make trackpoint, store to current track (error / skip if none)
48 /* Thanks to etrex-cache's gpsbabel's gpspoint.c for starting me off! */
50 static char line_buffer
[2048];
52 #define GPSPOINT_TYPE_NONE 0
53 #define GPSPOINT_TYPE_WAYPOINT 1
54 #define GPSPOINT_TYPE_TRACKPOINT 2
55 /* #define GPSPOINT_TYPE_ROUTEPOINT 3 */
56 #define GPSPOINT_TYPE_TRACK 4
58 /* #define GPSPOINT_TYPE_ROUTE 5 */
60 static VikTrack
*current_track
; /* pointer to pointer to first GList */
62 static gint line_type
= GPSPOINT_TYPE_NONE
;
63 static struct LatLon line_latlon
;
64 static gchar
*line_name
;
65 static gchar
*line_comment
;
66 static gchar
*line_image
;
67 static gboolean line_newsegment
= FALSE
;
68 static gboolean line_has_timestamp
= FALSE
;
69 static time_t line_timestamp
= 0;
70 static gdouble line_altitude
= VIK_DEFAULT_ALTITUDE
;
71 static gboolean line_visible
= TRUE
;
72 /* other possible properties go here */
75 static void gpspoint_process_tag ( const gchar
*tag
, gint len
);
76 static void gpspoint_process_key_and_value ( const gchar
*key
, gint key_len
, const gchar
*value
, gint value_len
);
78 static gchar
*slashdup(const gchar
*str
)
80 guint16 len
= strlen(str
);
81 guint16 need_bs_count
, i
, j
;
83 for ( i
= 0, need_bs_count
= 0; i
< len
; i
++ )
84 if ( str
[i
] == '\\' || str
[i
] == '"' )
86 rv
= g_malloc ( (len
+need_bs_count
+1) * sizeof(gchar
) );
87 for ( i
= 0, j
= 0; i
< len
; i
++, j
++ )
89 if ( str
[i
] == '\\' || str
[i
] == '"' )
97 static gchar
*deslashndup ( const gchar
*str
, guint16 len
)
99 guint16 i
,j
, bs_count
, new_len
;
100 gboolean backslash
= FALSE
;
106 for ( i
= 0, bs_count
= 0; i
< len
; i
++ )
107 if ( str
[i
] == '\\' )
113 if ( str
[i
-1] == '\\' && (len
== 1 || str
[i
-2] != '\\') )
116 new_len
= len
- bs_count
;
117 rv
= g_malloc ( (new_len
+1) * sizeof(gchar
) );
118 for ( i
= 0, j
= 0; i
< len
&& j
< new_len
; i
++ )
119 if ( str
[i
] == '\\' && !backslash
)
131 void a_gpspoint_read_file(VikTrwLayer
*trw
, FILE *f
) {
132 VikCoordMode coord_mode
= vik_trw_layer_get_coord_mode ( trw
);
133 gchar
*tag_start
, *tag_end
;
134 GHashTable
*tracks
= vik_trw_layer_get_tracks ( trw
);
135 GHashTable
*waypoints
= vik_trw_layer_get_waypoints ( trw
);
136 g_assert ( f
!= NULL
&& trw
!= NULL
);
139 line_newsegment
= FALSE
;
140 current_track
= NULL
;
141 while (fgets(line_buffer
, 2048, f
))
143 gboolean inside_quote
= 0;
144 gboolean backslash
= 0;
146 line_buffer
[strlen(line_buffer
)-1] = '\0'; /* chop off newline */
148 /* for gpspoint files wrapped inside */
149 if ( strlen(line_buffer
) >= 13 && strncmp ( line_buffer
, "~EndLayerData", 13 ) == 0 )
152 /* each line: nullify stuff, make thing if nes, free name if ness */
153 tag_start
= line_buffer
;
156 /* my addition: find first non-whitespace character. if the null, skip line. */
157 while (*tag_start
!= '\0' && isspace(*tag_start
))
159 if (tag_start
== '\0')
162 if (*tag_start
== '#')
167 inside_quote
= !inside_quote
;
168 while (*tag_end
!= '\0' && (!isspace(*tag_end
) || inside_quote
)) {
170 if (*tag_end
== '\\' && !backslash
)
174 else if (*tag_end
== '"')
175 inside_quote
= !inside_quote
;
178 gpspoint_process_tag ( tag_start
, tag_end
- tag_start
);
180 if (*tag_end
== '\0' )
183 tag_start
= tag_end
+1;
185 if (line_type
== GPSPOINT_TYPE_WAYPOINT
&& line_name
)
187 VikWaypoint
*wp
= vik_waypoint_new();
188 gint i
= strlen(line_name
);
189 wp
->visible
= line_visible
;
190 wp
->altitude
= line_altitude
;
192 line_name
[i
] = toupper(line_name
[i
]); /* TODO: check for acceptable chars */
194 vik_coord_load_from_latlon ( &(wp
->coord
), coord_mode
, &line_latlon
);
196 g_hash_table_insert ( waypoints
, line_name
, wp
);
200 vik_waypoint_set_comment ( wp
, line_comment
);
206 vik_waypoint_set_image ( wp
, line_image
);
210 line_name
= NULL
; /* will be freed automatically */
212 else if (line_type
== GPSPOINT_TYPE_TRACK
&& line_name
)
214 VikTrack
*pl
= vik_track_new();
215 gint i
= strlen(line_name
);
217 /* Thanks to Peter Jones for this Fix */
218 if (!line_name
) line_name
= g_strdup("UNK");
220 pl
->visible
= line_visible
;
223 line_name
[i
] = toupper(line_name
[i
]);
227 vik_track_set_comment ( pl
, line_comment
);
231 pl
->trackpoints
= NULL
;
232 g_hash_table_insert ( tracks
, line_name
, pl
);
233 line_name
= NULL
; /* will be freed automatically */
237 else if (line_type
== GPSPOINT_TYPE_TRACKPOINT
&& current_track
)
239 VikTrackpoint
*tp
= g_malloc ( sizeof ( VikTrackpoint
) );
240 vik_coord_load_from_latlon ( &(tp
->coord
), coord_mode
, &line_latlon
);
241 tp
->newsegment
= line_newsegment
;
242 tp
->has_timestamp
= line_has_timestamp
;
243 tp
->timestamp
= line_timestamp
;
244 tp
->altitude
= line_altitude
;
245 current_track
->trackpoints
= g_list_append ( current_track
->trackpoints
, tp
);
249 g_free ( line_name
);
252 g_free ( line_comment
);
254 g_free ( line_image
);
257 line_type
= GPSPOINT_TYPE_NONE
;
258 line_newsegment
= FALSE
;
259 line_has_timestamp
= FALSE
;
261 line_altitude
= VIK_DEFAULT_ALTITUDE
;
266 /* Tag will be of a few defined forms:
272 So we must determine end of tag name, start of value, end of value.
274 static void gpspoint_process_tag ( const gchar
*tag
, gint len
)
276 const gchar
*key_end
, *value_start
, *value_end
;
278 /* Searching for key end */
281 while (++key_end
- tag
< len
)
285 if (key_end
- tag
== len
)
286 return; /* no good */
288 if (key_end
- tag
== len
+ 1)
289 value_start
= value_end
= 0; /* size = 0 */
292 value_start
= key_end
+ 1; /* equal_sign plus one */
294 if (*value_start
== '"')
297 if (*value_start
== '"')
298 value_start
= value_end
= 0; /* size = 0 */
301 if (*(tag
+len
-1) == '"')
302 value_end
= tag
+ len
- 1;
308 value_end
= tag
+ len
; /* value start really IS value start. */
310 gpspoint_process_key_and_value(tag
, key_end
- tag
, value_start
, value_end
- value_start
);
315 value = NULL for none
317 static void gpspoint_process_key_and_value ( const gchar
*key
, gint key_len
, const gchar
*value
, gint value_len
)
319 if (key_len
== 4 && strncasecmp( key
, "type", key_len
) == 0 )
322 line_type
= GPSPOINT_TYPE_NONE
;
323 else if (value_len
== 5 && strncasecmp( value
, "track", value_len
) == 0 )
324 line_type
= GPSPOINT_TYPE_TRACK
;
325 else if (value_len
== 10 && strncasecmp( value
, "trackpoint", value_len
) == 0 )
326 line_type
= GPSPOINT_TYPE_TRACKPOINT
;
327 else if (value_len
== 8 && strncasecmp( value
, "waypoint", value_len
) == 0 )
328 line_type
= GPSPOINT_TYPE_WAYPOINT
;
330 /* all others are ignored */
331 line_type
= GPSPOINT_TYPE_NONE
;
333 else if (key_len
== 4 && strncasecmp( key
, "name", key_len
) == 0 && value
!= NULL
)
335 if (line_name
== NULL
)
337 line_name
= g_strndup ( value
, value_len
);
340 else if (key_len
== 7 && strncasecmp( key
, "comment", key_len
) == 0 && value
!= NULL
)
342 if (line_comment
== NULL
)
343 line_comment
= deslashndup ( value
, value_len
);
345 else if (key_len
== 5 && strncasecmp( key
, "image", key_len
) == 0 && value
!= NULL
)
347 if (line_image
== NULL
)
348 line_image
= deslashndup ( value
, value_len
);
350 else if (key_len
== 8 && strncasecmp( key
, "latitude", key_len
) == 0 && value
!= NULL
)
352 line_latlon
.lat
= strtod(value
, NULL
);
354 else if (key_len
== 9 && strncasecmp( key
, "longitude", key_len
) == 0 && value
!= NULL
)
356 line_latlon
.lon
= strtod(value
, NULL
);
358 else if (key_len
== 8 && strncasecmp( key
, "altitude", key_len
) == 0 && value
!= NULL
)
360 line_altitude
= strtod(value
, NULL
);
362 else if (key_len
== 7 && strncasecmp( key
, "visible", key_len
) == 0 && value
[0] != 'y' && value
[0] != 'Y' && value
[0] != 't' && value
[0] != 'T')
364 line_visible
= FALSE
;
366 else if (key_len
== 8 && strncasecmp( key
, "unixtime", key_len
) == 0 && value
!= NULL
)
368 line_timestamp
= strtod(value
, NULL
);
369 if ( line_timestamp
!= 0x80000000 )
370 line_has_timestamp
= TRUE
;
372 else if (key_len
== 10 && strncasecmp( key
, "newsegment", key_len
) == 0 && value
!= NULL
)
374 line_newsegment
= TRUE
;
378 static void a_gpspoint_write_waypoint ( const gchar
*name
, VikWaypoint
*wp
, FILE *f
)
380 static struct LatLon ll
;
381 vik_coord_to_latlon ( &(wp
->coord
), &ll
);
382 fprintf ( f
, "type=\"waypoint\" latitude=\"%f\" longitude=\"%f\" name=\"%s\"", ll
.lat
, ll
.lon
, name
);
383 if ( wp
->altitude
!= VIK_DEFAULT_ALTITUDE
)
384 fprintf ( f
, " altitude=\"%f\"", wp
->altitude
);
387 gchar
*tmp_comment
= slashdup(wp
->comment
);
388 fprintf ( f
, " comment=\"%s\"", tmp_comment
);
389 g_free ( tmp_comment
);
393 gchar
*tmp_image
= slashdup(wp
->image
);
394 fprintf ( f
, " image=\"%s\"", tmp_image
);
395 g_free ( tmp_image
);
398 fprintf ( f
, " visible=\"n\"" );
402 static void a_gpspoint_write_trackpoint ( VikTrackpoint
*tp
, FILE *f
)
404 static struct LatLon ll
;
405 vik_coord_to_latlon ( &(tp
->coord
), &ll
);
407 fprintf ( f
, "type=\"trackpoint\" latitude=\"%f\" longitude=\"%f\"", ll
.lat
, ll
.lon
);
409 if ( tp
->altitude
!= VIK_DEFAULT_ALTITUDE
)
410 fprintf ( f
, " altitude=\"%f\"", tp
->altitude
);
411 if ( tp
->has_timestamp
)
412 fprintf ( f
, " unixtime=\"%ld\"", tp
->timestamp
);
413 if ( tp
->newsegment
)
414 fprintf ( f
, " newsegment=\"yes\"" );
419 static void a_gpspoint_write_track ( const gchar
*name
, VikTrack
*t
, FILE *f
)
423 gchar
*tmp_comment
= slashdup(t
->comment
);
424 fprintf ( f
, "type=\"track\" name=\"%s\" comment=\"%s\"%s\n", name
, tmp_comment
, t
->visible
? "" : " visible=\"n\"" );
425 g_free ( tmp_comment
);
428 fprintf ( f
, "type=\"track\" name=\"%s\"%s\n", name
, t
->visible
? "" : " visible=\"n\"" );
429 g_list_foreach ( t
->trackpoints
, (GFunc
) a_gpspoint_write_trackpoint
, f
);
430 fprintf ( f
, "type=\"trackend\"\n" );
433 void a_gpspoint_write_file ( VikTrwLayer
*trw
, FILE *f
)
435 GHashTable
*tracks
= vik_trw_layer_get_tracks ( trw
);
436 GHashTable
*waypoints
= vik_trw_layer_get_waypoints ( trw
);
438 fprintf ( f
, "type=\"waypointlist\"\n" );
439 g_hash_table_foreach ( waypoints
, (GHFunc
) a_gpspoint_write_waypoint
, f
);
440 fprintf ( f
, "type=\"waypointlistend\"\n" );
441 g_hash_table_foreach ( tracks
, (GHFunc
) a_gpspoint_write_track
, f
);