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 /* Integer values are probably in feet */
227 depth->mm = 304.8 * val.i;
229 /* Float? Probably meters.. */
231 depth->mm = val.fp * 1000;
234 printf("Strange depth reading %s\n", buffer);
239 static void temperature(char *buffer, void *_temperature)
241 temperature_t *temperature = _temperature;
242 union int_or_float val;
244 switch (integer_or_float(buffer, &val)) {
245 /* C or F? Who knows? Let's default to Celsius */
250 /* Ignore zero. It means "none" */
255 temperature->mkelvin = (val.fp + 273.16) * 1000;
259 if (val.fp < 212.0) {
260 temperature->mkelvin = (val.fp + 459.67) * 5000/9;
263 /* Kelvin or already millikelvin */
266 temperature->mkelvin = val.fp;
269 printf("Strange temperature reading %s\n", buffer);
274 static void sampletime(char *buffer, void *_time)
278 duration_t *time = _time;
280 i = sscanf(buffer, "%d:%d", &min, &sec);
287 time->seconds = sec + min*60;
290 printf("Strange sample time reading %s\n", buffer);
295 static void duration(char *buffer, void *_time)
297 sampletime(buffer, _time);
300 static void ignore(char *buffer, void *_time)
304 /* We're in samples - try to convert the random xml value to something useful */
305 static void try_to_fill_sample(struct sample *sample, const char *name, char *buf)
307 const char *last = last_part(name);
309 if (match("pressure", last, pressure, buf, &sample->tankpressure))
311 if (match("cylpress", last, pressure, buf, &sample->tankpressure))
313 if (match("depth", last, depth, buf, &sample->depth))
315 if (match("temperature", last, temperature, buf, &sample->temperature))
317 if (match("sampletime", last, sampletime, buf, &sample->time))
319 if (match("time", last, sampletime, buf, &sample->time))
322 nonmatch("sample", name, last, buf);
325 /* We're in the top-level dive xml. Try to convert whatever value to a dive value */
326 static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
328 const char *last = last_part(name);
330 if (match("date", last, divedate, buf, &dive->when))
332 if (match("time", last, divetime, buf, &dive->when))
334 if (match("datetime", last, divedatetime, buf, &dive->when))
336 if (match("maxdepth", last, depth, buf, &dive->maxdepth))
338 if (match("meandepth", last, depth, buf, &dive->meandepth))
340 if (match("divetime", last, duration, buf, &dive->duration))
342 if (match("divetimesec", last, duration, buf, &dive->duration))
344 if (match("surfacetime", last, duration, buf, &dive->surfacetime))
346 if (match("airtemp", last, temperature, buf, &dive->airtemp))
348 if (match("watertemp", last, temperature, buf, &dive->watertemp))
350 if (match("cylinderstartpressure", last, pressure, buf, &dive->beginning_pressure))
352 if (match("cylinderendpressure", last, pressure, buf, &dive->end_pressure))
354 if (match("divenumber", last, ignore, buf, NULL))
356 if (match("diveseries", last, ignore, buf, NULL))
358 if (match("number", last, ignore, buf, NULL))
360 if (match("size", last, ignore, buf, NULL))
362 if (match("fingerprint", last, ignore, buf, NULL))
364 nonmatch("dive", name, last, buf);
367 static unsigned int dive_size(int samples)
369 return sizeof(struct dive) + samples*sizeof(struct sample);
373 * File boundaries are dive boundaries. But sometimes there are
374 * multiple dives per file, so there can be other events too that
375 * trigger a "new dive" marker and you may get some nesting due
376 * to that. Just ignore nesting levels.
378 static void dive_start(void)
386 size = dive_size(alloc_samples);
390 memset(dive, 0, size);
391 memset(&tm, 0, sizeof(tm));
394 static char *generate_name(struct dive *dive)
398 char buffer[256], *p;
400 tm = gmtime(&dive->when);
402 len = snprintf(buffer, sizeof(buffer),
406 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
407 tm->tm_hour, tm->tm_min, tm->tm_sec,
408 to_feet(dive->maxdepth), dive->duration.seconds / 60);
412 memcpy(p, buffer, len+1);
416 static void dive_end(void)
421 dive->name = generate_name(dive);
426 static void sample_start(void)
433 if (nr >= alloc_samples) {
436 alloc_samples = (alloc_samples * 3)/2 + 10;
437 size = dive_size(alloc_samples);
438 dive = realloc(dive, size);
442 sample = dive->sample + nr;
443 memset(sample, 0, sizeof(*sample));
446 static void sample_end(void)
454 static void entry(const char *name, int size, const char *raw)
456 char *buf = malloc(size+1);
460 memcpy(buf, raw, size);
463 try_to_fill_sample(sample, name, buf);
467 try_to_fill_dive(dive, name, buf);
472 static const char *nodename(xmlNode *node, char *buf, int len)
474 if (!node || !node->name)
482 const char *name = node->name;
483 int i = strlen(name);
485 unsigned char c = name[i];
491 if (!node || !node->name)
501 static void visit_one_node(xmlNode *node)
504 const unsigned char *content;
505 char buffer[MAXNAME];
508 content = node->content;
512 /* Trim whitespace at beginning */
513 while (isspace(*content))
516 /* Trim whitespace at end */
517 len = strlen(content);
518 while (len && isspace(content[len-1]))
524 /* Don't print out the node name if it is "text" */
525 if (!strcmp(node->name, "text"))
528 name = nodename(node, buffer, sizeof(buffer));
530 entry(name, len, content);
533 static void traverse(xmlNode *node)
537 for (n = node; n; n = n->next) {
538 /* XML from libdivecomputer: 'dive' per new dive */
539 if (!strcmp(n->name, "dive")) {
541 traverse(n->children);
547 * At least both libdivecomputer and Suunto
550 * Well - almost. Ignore case.
552 if (!strcasecmp(n->name, "sample")) {
554 traverse(n->children);
559 /* Anything else - just visit it and recurse */
561 traverse(n->children);
565 void parse_xml_file(const char *filename)
569 doc = xmlReadFile(filename, NULL, 0);
571 fprintf(stderr, "Failed to parse '%s'.\n", filename);
576 traverse(xmlDocGetRootElement(doc));
582 void parse_xml_init(void)