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