1 /*
2     Parse 'GarminDevice.xml' on a Garmin mass storage device (e.g. Zumo,
3       Nuvi, Colorado, etc. and return key device info.
4 
5     Copyright (C) 2008 Robert Lipe, robertlipe@gpsbabel.org
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
20 
21  */
22 
23 // References:
24 // http://developer.garmin.com/web-device/garmin-mass-storage-mode-devices/
25 // http://developer.garmin.com/schemas/device/v2/
26 
27 #include "defs.h"
28 #include "xmlgeneric.h"
29 #include "garmin_device_xml.h"
30 
31 #define MYNAME "whatever"
32 
33 static gdx_info* my_gdx_info;
34 static int type;
35 static char* mountpoint, *base, *path, *ext;
36 static xg_callback device_s, id_s, path_s, ext_s, base_s, dir_s;
37 jmp_buf gdx_jmp_buf;
38 
type_s(const char * args,const char ** unused)39 void type_s(const char* args, const char** unused)
40 {
41   type = strcmp(args, "GPSData");
42 }
43 
device_s(const char * args,const char ** unused)44 void device_s(const char* args, const char** unused)
45 {
46   if (my_gdx_info) {
47     fatal(MYNAME ": More than one device type found in file.\n");
48   }
49   my_gdx_info = (gdx_info*) xcalloc(sizeof *my_gdx_info, 1);
50   my_gdx_info->device_desc = xstrdup(args);
51 }
52 
id_s(const char * args,const char ** unused)53 void id_s(const char* args, const char** unused)
54 {
55   my_gdx_info->device_id = xstrdup(args);
56 }
57 
path_s(const char * args,const char ** unused)58 void path_s(const char* args, const char** unused)
59 {
60   path = xstrdup(args);
61 }
62 
ext_s(const char * args,const char ** unused)63 void ext_s(const char* args, const char** unused)
64 {
65   ext = xstrdup(args);
66 }
67 
base_s(const char * args,const char ** unused)68 void base_s(const char* args, const char** unused)
69 {
70   base = xstrdup(args);
71 }
72 
dir_s(const char * args,const char ** unused)73 void dir_s(const char* args, const char** unused)
74 {
75   if (type) {
76     return;
77   }
78   if (0 == strcmp(args, "OutputFromUnit")) {
79     xasprintf(&my_gdx_info->from_device.path,  "%s%c%s",
80               mountpoint, GB_PATHSEP, path);
81     my_gdx_info->from_device.basename = xstrdup(base);
82     my_gdx_info->from_device.extension = xstrdup(ext);
83     xasprintf(&my_gdx_info->from_device.canon, "%s/%s.%s",
84               my_gdx_info->from_device.path,
85               my_gdx_info->from_device.basename,
86               my_gdx_info->from_device.extension);
87   } else if (0 == strcmp(args, "InputToUnit")) {
88     xasprintf(&my_gdx_info->to_device.path,  "%s%c%s",
89               mountpoint, GB_PATHSEP, path);
90     my_gdx_info->to_device.basename = xstrdup(base);
91     my_gdx_info->to_device.extension = xstrdup(ext);
92   } else {
93     fatal(MYNAME ":Unknown direction '%s'\n", args);
94   }
95 
96   if (base) {
97     xfree(base) ;
98   }
99   base = NULL;
100 
101   if (ext) {
102     xfree(ext) ;
103   }
104   ext = NULL;
105 
106   if (path) {
107     xfree(path) ;
108   }
109   path = NULL;
110 }
111 
112 static xg_tag_mapping gdx_map[] = {
113   { device_s, cb_cdata, "/Device/Model/Description" },
114   { id_s, cb_cdata, "/Device/Id" },
115   { path_s, cb_cdata, "/Device/MassStorageMode/DataType/File/Location/Path" },
116   { type_s, cb_cdata, "/Device/MassStorageMode/DataType/Name" },
117   { ext_s, cb_cdata, "/Device/MassStorageMode/DataType/File/Location/FileExtension" },
118   { base_s, cb_cdata, "/Device/MassStorageMode/DataType/File/Location/BaseName" },
119   { dir_s, cb_cdata, "/Device/MassStorageMode/DataType/File/TransferDirection" },
120   { 0, (xg_cb_type) 0, NULL }
121 };
122 
123 const gdx_info*
gdx_read(const char * fname)124 gdx_read(const char* fname)
125 {
126   // Test file open-able before gb_open gets a chance to fatal().
127   FILE* fin = fopen(fname, "r");
128 
129   if (fin) {
130     fclose(fin);
131     xml_init(fname, gdx_map, NULL);
132     xml_read();
133     xml_deinit();
134   }
135 
136   return my_gdx_info;
137 }
138 
139 
140 // Look for the Device in the incoming NULL-terminated list of directories
141 const gdx_info*
gdx_find_file(char ** dirlist)142 gdx_find_file(char** dirlist)
143 {
144   const gdx_info* gdx;
145   while (dirlist && *dirlist) {
146     char* tbuf;
147     xasprintf(&tbuf, "%s/%s", *dirlist, "/Garmin/GarminDevice.xml");
148     mountpoint = *dirlist;
149     gdx = gdx_read(tbuf);
150     xfree(tbuf);
151     if (gdx) {
152       longjmp(gdx_jmp_buf, 1);
153     }
154     dirlist++;
155   }
156   return NULL;
157 }
158 
159 const gdx_info*
gdx_get_info()160 gdx_get_info()
161 {
162   return my_gdx_info;
163 }
164