X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;ds=sidebyside;f=parse-xml.c;h=6c93ad1a534e1f6fc7e5bf4dae944eeb7032fd75;hb=5001ab66cba885411e9ee4e8c701688b4928ab1d;hp=95625d12f550cf34854c9949ca2496af08b39ea9;hpb=14d7601cdf8b5ba05c7889f6272fdad3fee03c80;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index 95625d1..6c93ad1 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -69,6 +69,8 @@ static int alloc_samples; static struct dive *dive; static struct sample *sample; static struct tm tm; +static int suunto; +static int event_index, gasmix_index; static time_t utc_mktime(struct tm *tm) { @@ -104,14 +106,25 @@ static void divedate(char *buffer, void *_when) { int d,m,y; time_t *when = _when; + int success = 0; + success = tm.tm_sec | tm.tm_min | tm.tm_hour; if (sscanf(buffer, "%d.%d.%d", &d, &m, &y) == 3) { tm.tm_year = y; tm.tm_mon = m-1; tm.tm_mday = d; - if (tm.tm_sec | tm.tm_min | tm.tm_hour) - *when = utc_mktime(&tm); + } else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) { + tm.tm_year = y; + tm.tm_mon = m-1; + tm.tm_mday = d; + } else { + fprintf(stderr, "Unable to parse date '%s'\n", buffer); + success = 0; } + + if (success) + *when = utc_mktime(&tm); + free(buffer); } @@ -195,7 +208,7 @@ static void pressure(char *buffer, void *_press) case FLOAT: /* Maybe it's in Bar? */ if (val.fp < 500.0) { - pressure->mbar = val.fp * 1000; + pressure->mbar = val.fp * 1000 + 0.5; break; } printf("Unknown fractional pressure reading %s\n", buffer); @@ -231,7 +244,7 @@ static void depth(char *buffer, void *_depth) val.fp = val.i; /* fallthrough */ case FLOAT: - depth->mm = val.fp * 1000; + depth->mm = val.fp * 1000 + 0.5; break; default: printf("Strange depth reading %s\n", buffer); @@ -255,7 +268,7 @@ static void temperature(char *buffer, void *_temperature) break; /* Celsius */ if (val.fp < 50.0) { - temperature->mkelvin = (val.fp + 273.16) * 1000; + temperature->mkelvin = (val.fp + 273.15) * 1000 + 0.5; break; } /* Fahrenheit */ @@ -300,6 +313,42 @@ static void duration(char *buffer, void *_time) sampletime(buffer, _time); } +static void percent(char *buffer, void *_fraction) +{ + fraction_t *fraction = _fraction; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + /* C or F? Who knows? Let's default to Celsius */ + case INTEGER: + val.fp = val.i; + /* Fallthrough */ + case FLOAT: + if (val.fp <= 100.0) + fraction->permille = val.fp * 10 + 0.5; + break; + + default: + printf("Strange percentage reading %s\n", buffer); + break; + } + free(buffer); +} + +static void gasmix(char *buffer, void *_fraction) +{ + /* libdivecomputer does negative percentages. */ + if (*buffer == '-') + return; + if (gasmix_index < MAX_MIXES) + percent(buffer, _fraction); +} + +static void gasmix_nitrogen(char *buffer, void *_gasmix) +{ + /* Ignore n2 percentages. There's no value in them. */ +} + #define MATCH(pattern, fn, dest) \ match(pattern, strlen(pattern), name, len, fn, buf, dest) @@ -315,6 +364,8 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu return; if (MATCH(".sample.depth", depth, &sample->depth)) return; + if (MATCH(".sample.temp", temperature, &sample->temperature)) + return; if (MATCH(".sample.temperature", temperature, &sample->temperature)) return; if (MATCH(".sample.sampletime", sampletime, &sample->time)) @@ -325,6 +376,21 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu nonmatch("sample", name, buf); } +/* + * Crazy suunto xml. Look at how those o2/he things match up. + */ +static int suunto_dive_match(struct dive *dive, const char *name, int len, char *buf) +{ + return MATCH(".o2pct", percent, &dive->gasmix[0].o2) || + MATCH(".hepct_0", percent, &dive->gasmix[0].he) || + MATCH(".o2pct_2", percent, &dive->gasmix[1].o2) || + MATCH(".hepct_1", percent, &dive->gasmix[1].he) || + MATCH(".o2pct_3", percent, &dive->gasmix[2].o2) || + MATCH(".hepct_2", percent, &dive->gasmix[2].he) || + MATCH(".o2pct_4", percent, &dive->gasmix[3].o2) || + MATCH(".hepct_3", percent, &dive->gasmix[3].he); +} + /* We're in the top-level dive xml. Try to convert whatever value to a dive value */ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) { @@ -341,6 +407,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH(".meandepth", depth, &dive->meandepth)) return; + if (MATCH(".duration", duration, &dive->duration)) + return; if (MATCH(".divetime", duration, &dive->duration)) return; if (MATCH(".divetimesec", duration, &dive->duration)) @@ -355,6 +423,18 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH(".cylinderendpressure", pressure, &dive->end_pressure)) return; + + if (MATCH(".o2", gasmix, &dive->gasmix[gasmix_index].o2)) + return; + if (MATCH(".n2", gasmix_nitrogen, &dive->gasmix[gasmix_index])) + return; + if (MATCH(".he", gasmix, &dive->gasmix[gasmix_index].he)) + return; + + /* Suunto XML files are some crazy sh*t. */ + if (suunto && suunto_dive_match(dive, name, len, buf)) + return; + nonmatch("dive", name, buf); } @@ -407,14 +487,74 @@ static char *generate_name(struct dive *dive) return p; } +static void sanitize_gasmix(struct dive *dive) +{ + int i; + + for (i = 0; i < MAX_MIXES; i++) { + gasmix_t *mix = dive->gasmix+i; + unsigned int o2, he; + + o2 = mix->o2.permille; + he = mix->he.permille; + + /* Regular air: leave empty */ + if (!he) { + if (!o2) + continue; + /* 20.9% or 21% O2 is just air */ + if (o2 >= 209 && o2 <= 210) { + mix->o2.permille = 0; + continue; + } + } + + /* Sane mix? */ + if (o2 <= 1000 && he <= 1000 && o2+he <= 1000) + continue; + fprintf(stderr, "Odd gasmix: %d O2 %d He\n", o2, he); + memset(mix, 0, sizeof(*mix)); + } +} + static void dive_end(void) { if (!dive) return; if (!dive->name) dive->name = generate_name(dive); + sanitize_gasmix(dive); record_dive(dive); dive = NULL; + gasmix_index = 0; +} + +static void suunto_start(void) +{ + suunto++; +} + +static void suunto_end(void) +{ + suunto--; +} + +static void event_start(void) +{ +} + +static void event_end(void) +{ + event_index++; +} + +static void gasmix_start(void) +{ +} + +static void gasmix_end(void) +{ + gasmix_index++; } static void sample_start(void) @@ -435,6 +575,7 @@ static void sample_start(void) } sample = dive->sample + nr; memset(sample, 0, sizeof(*sample)); + event_index = 0; } static void sample_end(void) @@ -550,34 +691,41 @@ static void visit(xmlNode *n) traverse(n->children); } +/* + * I'm sure this could be done as some fancy DTD rules. + * It's just not worth the headache. + */ +static struct nesting { + const char *name; + void (*start)(void), (*end)(void); +} nesting[] = { + { "dive", dive_start, dive_end }, + { "SUUNTO", suunto_start, suunto_end }, + { "sample", sample_start, sample_end }, + { "SAMPLE", sample_start, sample_end }, + { "event", event_start, event_end }, + { "gasmix", gasmix_start, gasmix_end }, + { NULL, } +}; + static void traverse(xmlNode *root) { xmlNode *n; for (n = root; n; n = n->next) { - /* XML from libdivecomputer: 'dive' per new dive */ - if (!strcmp(n->name, "dive")) { - dive_start(); - visit(n); - dive_end(); - continue; - } + struct nesting *rule = nesting; - /* - * At least both libdivecomputer and Suunto - * agree on "sample". - * - * Well - almost. Ignore case. - */ - if (!strcasecmp(n->name, "sample")) { - sample_start(); - visit(n); - sample_end(); - continue; - } + do { + if (!strcmp(rule->name, n->name)) + break; + rule++; + } while (rule->name); - /* Anything else - just visit it and recurse */ + if (rule->start) + rule->start(); visit(n); + if (rule->end) + rule->end(); } }