7 #include <libxml/parser.h>
8 #include <libxml/tree.h>
14 struct dive_table dive_table;
17 * Add a dive into the dive_table array
19 static void record_dive(struct dive *dive)
21 int nr = dive_table.nr, allocated = dive_table.allocated;
22 struct dive **dives = dive_table.dives;
24 if (nr >= allocated) {
25 allocated = (nr + 32) * 3 / 2;
26 dives = realloc(dives, allocated * sizeof(struct dive *));
29 dive_table.dives = dives;
30 dive_table.allocated = allocated;
36 static void nonmatch(const char *type, const char *fullname, const char *name, char *buffer)
39 printf("Unable to match %s '(%.*s)%s' (%s)\n", type,
40 (int) (name - fullname), fullname, name,
45 static const char *last_part(const char *name)
47 const char *p = strrchr(name, '.');
48 return p ? p+1 : name;
51 typedef void (*matchfn_t)(char *buffer, void *);
53 static int match(const char *pattern, const char *name, matchfn_t fn, char *buf, void *data)
55 if (strcasecmp(pattern, name))
62 * Dive info as it is being built up..
64 static int alloc_samples;
65 static struct dive *dive;
66 static struct sample *sample;
69 static time_t utc_mktime(struct tm *tm)
71 static const int mdays[] = {
72 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
74 int year = tm->tm_year;
75 int month = tm->tm_mon;
76 int day = tm->tm_mday;
78 /* First normalize relative to 1900 */
84 /* Normalized to Jan 1, 1970: unix time */
87 if (year < 0 || year > 129) /* algo only works for 1970-2099 */
89 if (month < 0 || month > 11) /* array bounds */
91 if (month < 2 || (year + 2) % 4)
93 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_sec < 0)
95 return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
96 tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
99 static void divedate(char *buffer, void *_when)
102 time_t *when = _when;
104 if (sscanf(buffer, "%d.%d.%d", &d, &m, &y) == 3) {
108 if (tm.tm_sec | tm.tm_min | tm.tm_hour)
109 *when = utc_mktime(&tm);
114 static void divetime(char *buffer, void *_when)
117 time_t *when = _when;
119 if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) {
124 *when = utc_mktime(&tm);
129 /* Libdivecomputer: "2011-03-20 10:22:38" */
130 static void divedatetime(char *buffer, void *_when)
134 time_t *when = _when;
136 if (sscanf(buffer, "%d-%d-%d %d:%d:%d",
137 &y, &m, &d, &hr, &min, &sec) == 6) {
144 *when = utc_mktime(&tm);
160 static enum number_type integer_or_float(char *buffer, union int_or_float *res)
166 /* Integer or floating point? */
167 val = strtol(buffer, &end, 10);
168 if (val < 0 || end == buffer)
171 /* Looks like it might be floating point? */
174 fp = strtod(buffer, &end);
185 static void pressure(char *buffer, void *_press)
187 pressure_t *pressure = _press;
188 union int_or_float val;
190 switch (integer_or_float(buffer, &val)) {
192 /* Maybe it's in Bar? */
193 if (val.fp < 500.0) {
194 pressure->mbar = val.fp * 1000;
197 printf("Unknown fractional pressure reading %s\n", buffer);
202 * Random integer? Maybe in PSI? Or millibar already?
204 * We assume that 5 bar is a ridiculous tank pressure,
205 * so if it's smaller than 5000, it's in PSI..
208 pressure->mbar = val.i * 68.95;
211 pressure->mbar = val.i;
214 printf("Strange pressure reading %s\n", buffer);
219 static void depth(char *buffer, void *_depth)
221 depth_t *depth = _depth;
222 union int_or_float val;
224 switch (integer_or_float(buffer, &val)) {
225 /* All values are probably in meters */
230 depth->mm = val.fp * 1000;
233 printf("Strange depth reading %s\n", buffer);
238 static void temperature(char *buffer, void *_temperature)
240 temperature_t *temperature = _temperature;
241 union int_or_float val;
243 switch (integer_or_float(buffer, &val)) {
244 /* C or F? Who knows? Let's default to Celsius */
249 /* Ignore zero. It means "none" */
254 temperature->mkelvin = (val.fp + 273.16) * 1000;
258 if (val.fp < 212.0) {
259 temperature->mkelvin = (val.fp + 459.67) * 5000/9;
262 /* Kelvin or already millikelvin */
265 temperature->mkelvin = val.fp;
268 printf("Strange temperature reading %s\n", buffer);
273 static void sampletime(char *buffer, void *_time)
277 duration_t *time = _time;
279 i = sscanf(buffer, "%d:%d", &min, &sec);
286 time->seconds = sec + min*60;
289 printf("Strange sample time reading %s\n", buffer);
294 static void duration(char *buffer, void *_time)
296 sampletime(buffer, _time);
299 static void ignore(char *buffer, void *_time)
303 /* We're in samples - try to convert the random xml value to something useful */
304 static void try_to_fill_sample(struct sample *sample, const char *name, char *buf)
306 const char *last = last_part(name);
308 if (match("pressure", last, pressure, buf, &sample->tankpressure))
310 if (match("cylpress", last, pressure, buf, &sample->tankpressure))
312 if (match("depth", last, depth, buf, &sample->depth))
314 if (match("temperature", last, temperature, buf, &sample->temperature))
316 if (match("sampletime", last, sampletime, buf, &sample->time))
318 if (match("time", last, sampletime, buf, &sample->time))
321 nonmatch("sample", name, last, buf);
324 /* We're in the top-level dive xml. Try to convert whatever value to a dive value */
325 static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
327 const char *last = last_part(name);
329 if (match("date", last, divedate, buf, &dive->when))
331 if (match("time", last, divetime, buf, &dive->when))
333 if (match("datetime", last, divedatetime, buf, &dive->when))
335 if (match("maxdepth", last, depth, buf, &dive->maxdepth))
337 if (match("meandepth", last, depth, buf, &dive->meandepth))
339 if (match("divetime", last, duration, buf, &dive->duration))
341 if (match("divetimesec", last, duration, buf, &dive->duration))
343 if (match("surfacetime", last, duration, buf, &dive->surfacetime))
345 if (match("airtemp", last, temperature, buf, &dive->airtemp))
347 if (match("watertemp", last, temperature, buf, &dive->watertemp))
349 if (match("cylinderstartpressure", last, pressure, buf, &dive->beginning_pressure))
351 if (match("cylinderendpressure", last, pressure, buf, &dive->end_pressure))
353 if (match("divenumber", last, ignore, buf, NULL))
355 if (match("diveseries", last, ignore, buf, NULL))
357 if (match("number", last, ignore, buf, NULL))
359 if (match("size", last, ignore, buf, NULL))
361 if (match("fingerprint", last, ignore, buf, NULL))
363 nonmatch("dive", name, last, buf);
366 static unsigned int dive_size(int samples)
368 return sizeof(struct dive) + samples*sizeof(struct sample);
372 * File boundaries are dive boundaries. But sometimes there are
373 * multiple dives per file, so there can be other events too that
374 * trigger a "new dive" marker and you may get some nesting due
375 * to that. Just ignore nesting levels.
377 static void dive_start(void)
385 size = dive_size(alloc_samples);
389 memset(dive, 0, size);
390 memset(&tm, 0, sizeof(tm));
393 static char *generate_name(struct dive *dive)
397 char buffer[256], *p;
399 tm = gmtime(&dive->when);
401 len = snprintf(buffer, sizeof(buffer),
405 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
406 tm->tm_hour, tm->tm_min, tm->tm_sec,
407 to_feet(dive->maxdepth), dive->duration.seconds / 60);
411 memcpy(p, buffer, len+1);
415 static void dive_end(void)
420 dive->name = generate_name(dive);
425 static void sample_start(void)
432 if (nr >= alloc_samples) {
435 alloc_samples = (alloc_samples * 3)/2 + 10;
436 size = dive_size(alloc_samples);
437 dive = realloc(dive, size);
441 sample = dive->sample + nr;
442 memset(sample, 0, sizeof(*sample));
445 static void sample_end(void)
453 static void entry(const char *name, int size, const char *raw)
455 char *buf = malloc(size+1);
459 memcpy(buf, raw, size);
462 try_to_fill_sample(sample, name, buf);
466 try_to_fill_dive(dive, name, buf);
471 static const char *nodename(xmlNode *node, char *buf, int len)
473 if (!node || !node->name)
481 const char *name = node->name;
482 int i = strlen(name);
484 unsigned char c = name[i];
490 if (!node || !node->name)
500 static void visit_one_node(xmlNode *node)
503 const unsigned char *content;
504 char buffer[MAXNAME];
507 content = node->content;
511 /* Trim whitespace at beginning */
512 while (isspace(*content))
515 /* Trim whitespace at end */
516 len = strlen(content);
517 while (len && isspace(content[len-1]))
523 /* Don't print out the node name if it is "text" */
524 if (!strcmp(node->name, "text"))
527 name = nodename(node, buffer, sizeof(buffer));
529 entry(name, len, content);
532 static void traverse(xmlNode *node)
536 for (n = node; n; n = n->next) {
537 /* XML from libdivecomputer: 'dive' per new dive */
538 if (!strcmp(n->name, "dive")) {
540 traverse(n->children);
546 * At least both libdivecomputer and Suunto
549 * Well - almost. Ignore case.
551 if (!strcasecmp(n->name, "sample")) {
553 traverse(n->children);
558 /* Anything else - just visit it and recurse */
560 traverse(n->children);
564 void parse_xml_file(const char *filename)
568 doc = xmlReadFile(filename, NULL, 0);
570 fprintf(stderr, "Failed to parse '%s'.\n", filename);
575 traverse(xmlDocGetRootElement(doc));
581 void parse_xml_init(void)