X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=parse-xml.c;h=9b0797ea03f3f0dffa995e45967ed7c8f844d093;hb=d5e42d485e6c4a62b78281aac900bb447d811ab1;hp=5ac36a1521b5b54179308de230b23e5f5a7956a0;hpb=da4edbcce81a9a90e414bc6281183df154019b0c;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index 5ac36a1..9b0797e 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) { @@ -300,8 +302,40 @@ static void duration(char *buffer, void *_time) sampletime(buffer, _time); } -static void ignore(char *buffer, void *_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) \ @@ -329,6 +363,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) { @@ -359,16 +408,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(".divenumber", ignore, NULL)) - return; - if (MATCH(".diveseries", ignore, NULL)) + + if (MATCH(".o2", gasmix, &dive->gasmix[gasmix_index].o2)) return; - if (MATCH(".number", ignore, NULL)) + if (MATCH(".n2", gasmix_nitrogen, &dive->gasmix[gasmix_index])) return; - if (MATCH(".size", ignore, NULL)) + if (MATCH(".he", gasmix, &dive->gasmix[gasmix_index].he)) return; - if (MATCH(".fingerprint", ignore, NULL)) + + /* Suunto XML files are some crazy sh*t. */ + if (suunto && suunto_dive_match(dive, name, len, buf)) return; + nonmatch("dive", name, buf); } @@ -421,14 +472,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) @@ -449,6 +560,7 @@ static void sample_start(void) } sample = dive->sample + nr; memset(sample, 0, sizeof(*sample)); + event_index = 0; } static void sample_end(void) @@ -564,34 +676,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(); } }