X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=parse-xml.c;h=6eafb0d3aaf993bf8efc78b5d6916387ac0f3c0a;hb=2a8f7ab78f8d00b699b683b122ad2cf0ddc094b6;hp=f68aae67e32f4f5417c1d27a8414b66bb610a5f8;hpb=5f79a804b925a8ffbcf933bb6fae4f764b518c8e;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index f68aae6..6eafb0d 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -16,7 +16,7 @@ struct dive_table dive_table; /* * Add a dive into the dive_table array */ -static void record_dive(struct dive *dive) +void record_dive(struct dive *dive) { int nr = dive_table.nr, allocated = dive_table.allocated; struct dive **dives = dive_table.dives; @@ -62,21 +62,16 @@ static int match(const char *pattern, int plen, return 1; } + +struct units input_units; + /* - * We keep our internal data in well-specified units, but - * the input may come in some random format. This keeps track - * of the incoming units. + * We're going to default to SI units for input. Yes, + * technically the SI unit for pressure is Pascal, but + * we default to bar (10^5 pascal), which people + * actually use. Similarly, C instead of Kelvin. */ -static struct units { - enum { METERS, FEET } length; - enum { LITER, CUFT } volume; - enum { BAR, PSI } pressure; - enum { CELSIUS, FAHRENHEIT } temperature; - enum { KG, LBS } weight; -} units; - -/* We're going to default to SI units for input */ -static const struct units SI_units = { +const struct units SI_units = { .length = METERS, .volume = LITER, .pressure = BAR, @@ -84,17 +79,38 @@ static const struct units SI_units = { .weight = KG }; +const struct units IMPERIAL_units = { + .length = FEET, + .volume = CUFT, + .pressure = PSI, + .temperature = FAHRENHEIT, + .weight = LBS +}; + /* * Dive info as it is being built up.. */ -static int alloc_samples; static struct dive *dive; static struct sample *sample; +static struct { + int active; + duration_t time; + int type, flags, value; + const char *name; +} event; static struct tm tm; -static int suunto, uemis; -static int event_index, cylinder_index; - -static time_t utc_mktime(struct tm *tm) +static int cylinder_index; + +static enum import_source { + UNKNOWN, + LIBDIVECOMPUTER, + SUUNTO, + UEMIS, + DIVINGLOG, + UDDF, +} import_source; + +time_t utc_mktime(struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 @@ -230,7 +246,10 @@ static void pressure(char *buffer, void *_press) /* Just ignore zero values */ if (!val.fp) break; - switch (units.pressure) { + switch (input_units.pressure) { + case PASCAL: + mbar = val.fp / 100; + break; case BAR: /* Assume mbar, but if it's really small, it's bar */ mbar = val.fp; @@ -259,7 +278,7 @@ static void depth(char *buffer, void *_depth) switch (integer_or_float(buffer, &val)) { case FLOAT: - switch (units.length) { + switch (input_units.length) { case METERS: depth->mm = val.fp * 1000 + 0.5; break; @@ -285,7 +304,10 @@ static void temperature(char *buffer, void *_temperature) if (!val.fp) break; /* Celsius */ - switch (units.temperature) { + switch (input_units.temperature) { + case KELVIN: + temperature->mkelvin = val.fp * 1000; + break; case CELSIUS: temperature->mkelvin = (val.fp + 273.15) * 1000 + 0.5; break; @@ -393,11 +415,11 @@ static void utf8_string(char *buffer, void *_res) static void water_pressure(char *buffer, void *_depth) { depth_t *depth = _depth; - union int_or_float val; + union int_or_float val; double atm, cm; - switch (integer_or_float(buffer, &val)) { - case FLOAT: + switch (integer_or_float(buffer, &val)) { + case FLOAT: if (!val.fp) break; /* cbar to atm */ @@ -406,7 +428,7 @@ static void water_pressure(char *buffer, void *_depth) * atm to cm. Why not mm? The precision just isn't * there. */ - cm = 100 * (atm - 1) + 0.5; + cm = 100 * atm + 0.5; if (cm > 0) { depth->mm = 10 * (long)cm; break; @@ -445,10 +467,10 @@ static void centibar(char *buffer, void *_pressure) static void decicelsius(char *buffer, void *_temp) { temperature_t *temp = _temp; - union int_or_float val; + union int_or_float val; - switch (integer_or_float(buffer, &val)) { - case FLOAT: + switch (integer_or_float(buffer, &val)) { + case FLOAT: temp->mkelvin = (val.fp/10 + 273.15) * 1000 + 0.5; break; default: @@ -467,6 +489,107 @@ static int uemis_fill_sample(struct sample *sample, const char *name, int len, c 0; } +/* + * Divinglog is crazy. The temperatures are in celsius. EXCEPT + * for the sample temperatures, that are in Fahrenheit. + * WTF? + * + * Oh, and I think Diving Log *internally* probably kept them + * in celsius, because I'm seeing entries like + * + * 32.0 + * + * in there. Which is freezing, aka 0 degC. I bet the "0" is + * what Diving Log uses for "no temperature". + * + * So throw away crap like that. + */ +static void fahrenheit(char *buffer, void *_temperature) +{ + temperature_t *temperature = _temperature; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + case FLOAT: + /* Floating point equality is evil, but works for small integers */ + if (val.fp == 32.0) + break; + temperature->mkelvin = (val.fp + 459.67) * 5000/9; + break; + default: + fprintf(stderr, "Crazy Diving Log temperature reading %s\n", buffer); + } + free(buffer); +} + +/* + * Did I mention how bat-shit crazy divinglog is? The sample + * pressures are in PSI. But the tank working pressure is in + * bar. WTF^2? + * + * Crazy stuff like this is why subsurface has everything in + * these inconvenient typed structures, and you have to say + * "pressure->mbar" to get the actual value. Exactly so that + * you can never have unit confusion. + */ +static void psi(char *buffer, void *_pressure) +{ + pressure_t *pressure = _pressure; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + case FLOAT: + pressure->mbar = val.fp * 68.95 + 0.5; + break; + default: + fprintf(stderr, "Crazy Diving Log PSI reading %s\n", buffer); + } + free(buffer); +} + +static int divinglog_fill_sample(struct sample *sample, const char *name, int len, char *buf) +{ + return MATCH(".p.time", sampletime, &sample->time) || + MATCH(".p.depth", depth, &sample->depth) || + MATCH(".p.temp", fahrenheit, &sample->temperature) || + MATCH(".p.press1", psi, &sample->cylinderpressure) || + 0; +} + +static int uddf_fill_sample(struct sample *sample, const char *name, int len, char *buf) +{ + return MATCH(".divetime", sampletime, &sample->time) || + MATCH(".depth", depth, &sample->depth) || + MATCH(".temperature", temperature, &sample->temperature) || + 0; +} + +static void eventtime(char *buffer, void *_duration) +{ + duration_t *duration = _duration; + sampletime(buffer, duration); + if (sample) + duration->seconds += sample->time.seconds; +} + +static void try_to_fill_event(const char *name, char *buf) +{ + int len = strlen(name); + + start_match("event", name, buf); + if (MATCH(".event", utf8_string, &event.name)) + return; + if (MATCH(".name", utf8_string, &event.name)) + return; + if (MATCH(".time", eventtime, &event.time)) + return; + if (MATCH(".type", get_index, &event.type)) + return; + if (MATCH(".flags", get_index, &event.flags)) + return; + nonmatch("event", name, buf); +} + /* We're in samples - try to convert the random xml value to something useful */ static void try_to_fill_sample(struct sample *sample, const char *name, char *buf) { @@ -488,9 +611,24 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu if (MATCH(".sample.time", sampletime, &sample->time)) return; - if (uemis) { + switch (import_source) { + case UEMIS: if (uemis_fill_sample(sample, name, len, buf)) return; + break; + + case DIVINGLOG: + if (divinglog_fill_sample(sample, name, len, buf)) + return; + break; + + case UDDF: + if (uddf_fill_sample(sample, name, len, buf)) + return; + break; + + default: + break; } nonmatch("sample", name, buf); @@ -514,6 +652,45 @@ static int suunto_dive_match(struct dive *dive, const char *name, int len, char 0; } +static const char *country, *city; + +static void divinglog_place(char *place, void *_location) +{ + char **location = _location; + char buffer[256], *p; + int len; + + len = snprintf(buffer, sizeof(buffer), + "%s%s%s%s%s", + place, + city ? ", " : "", + city ? city : "", + country ? ", " : "", + country ? country : ""); + + p = malloc(len+1); + memcpy(p, buffer, len+1); + *location = p; + + city = NULL; + country = NULL; +} + +static int divinglog_dive_match(struct dive *dive, const char *name, int len, char *buf) +{ + return MATCH(".divedate", divedate, &dive->when) || + MATCH(".entrytime", divetime, &dive->when) || + MATCH(".depth", depth, &dive->maxdepth) || + MATCH(".tanksize", cylindersize, &dive->cylinder[0].type.size) || + MATCH(".presw", pressure, &dive->cylinder[0].type.workingpressure) || + MATCH(".comments", utf8_string, &dive->notes) || + MATCH(".buddy.names", utf8_string, &dive->buddy) || + MATCH(".country.name", utf8_string, &country) || + MATCH(".city.name", utf8_string, &city) || + MATCH(".place.name", divinglog_place, &dive->location) || + 0; +} + static int buffer_value(char *buffer) { int val = atoi(buffer); @@ -523,29 +700,29 @@ static int buffer_value(char *buffer) static void uemis_length_unit(char *buffer, void *_unused) { - units.length = buffer_value(buffer) ? FEET : METERS; + input_units.length = buffer_value(buffer) ? FEET : METERS; } static void uemis_volume_unit(char *buffer, void *_unused) { - units.volume = buffer_value(buffer) ? CUFT : LITER; + input_units.volume = buffer_value(buffer) ? CUFT : LITER; } static void uemis_pressure_unit(char *buffer, void *_unused) { #if 0 - units.pressure = buffer_value(buffer) ? PSI : BAR; + input_units.pressure = buffer_value(buffer) ? PSI : BAR; #endif } static void uemis_temperature_unit(char *buffer, void *_unused) { - units.temperature = buffer_value(buffer) ? FAHRENHEIT : CELSIUS; + input_units.temperature = buffer_value(buffer) ? FAHRENHEIT : CELSIUS; } static void uemis_weight_unit(char *buffer, void *_unused) { - units.weight = buffer_value(buffer) ? LBS : KG; + input_units.weight = buffer_value(buffer) ? LBS : KG; } static void uemis_time_unit(char *buffer, void *_unused) @@ -560,11 +737,11 @@ static void uemis_date_unit(char *buffer, void *_unused) static void uemis_date_time(char *buffer, void *_when) { time_t *when = _when; - union int_or_float val; + union int_or_float val; - switch (integer_or_float(buffer, &val)) { - case FLOAT: - *when = (val.fp - 40587.5) * 86400; + switch (integer_or_float(buffer, &val)) { + case FLOAT: + *when = (val.fp - 40587) * 86400; break; default: fprintf(stderr, "Strange julian date: %s", buffer); @@ -581,48 +758,210 @@ static void uemis_date_time(char *buffer, void *_when) */ static void uemis_time_zone(char *buffer, void *_when) { +#if 0 /* seems like this is only used to display it correctly + * the stored time appears to be UTC */ + time_t *when = _when; signed char tz = atoi(buffer); *when += tz * 3600; +#endif +} + +/* 0 - air ; 1 - nitrox1 ; 2 - nitrox2 ; 3 = nitrox3 */ +static int uemis_gas_template; + +/* + * Christ. Uemis tank data is a total mess. + * + * We're passed a "virtual cylinder" (0 - 6) for the different + * Uemis tank cases ("air", "nitrox_1", "nitrox_2.{bottom,deco}" + * and "nitrox_3.{bottom,deco,travel}". We need to turn that + * into the actual cylinder data depending on the gas template, + * and ignore the ones that are irrelevant for that template. + * + * So for "template 2" (nitrox_2), we ignore virtual tanks 0-1 + * (which are "air" and "nitrox_1" respectively), and tanks 4-6 + * (which are the three "nitrox_3" tanks), and we turn virtual + * tanks 2/3 into actual tanks 0/1. + * + * Confused yet? + */ +static int uemis_cylinder_index(void *_cylinder) +{ + cylinder_t *cylinder = _cylinder; + unsigned int index = cylinder - dive->cylinder; + + if (index > 6) { + fprintf(stderr, "Uemis cylinder pointer calculations broken\n"); + return -1; + } + switch(uemis_gas_template) { + case 1: /* Dive uses tank 1 */ + index -= 1; + /* Fallthrough */ + case 0: /* Dive uses tank 0 */ + if (index) + index = -1; + break; + case 2: /* Dive uses tanks 2-3 */ + index -= 2; + if (index > 1) + index = -1; + break; + case 3: /* Dive uses tanks 4-6 */ + index -= 4; + if (index > 2) + index = -1; + break; + } + return index; +} + +static void uemis_cylindersize(char *buffer, void *_cylinder) +{ + int index = uemis_cylinder_index(_cylinder); + if (index >= 0) + cylindersize(buffer, &dive->cylinder[index].type.size); +} + +static void uemis_percent(char *buffer, void *_cylinder) +{ + int index = uemis_cylinder_index(_cylinder); + if (index >= 0) + percent(buffer, &dive->cylinder[index].gasmix.o2); } -/* Christ. Uemis tank data is a total mess. */ static int uemis_dive_match(struct dive *dive, const char *name, int len, char *buf) { - return MATCH(".units.length", uemis_length_unit, &units) || - MATCH(".units.volume", uemis_volume_unit, &units) || - MATCH(".units.pressure", uemis_pressure_unit, &units) || - MATCH(".units.temperature", uemis_temperature_unit, &units) || - MATCH(".units.weight", uemis_weight_unit, &units) || - MATCH(".units.time", uemis_time_unit, &units) || - MATCH(".units.date", uemis_date_unit, &units) || + return MATCH(".units.length", uemis_length_unit, &input_units) || + MATCH(".units.volume", uemis_volume_unit, &input_units) || + MATCH(".units.pressure", uemis_pressure_unit, &input_units) || + MATCH(".units.temperature", uemis_temperature_unit, &input_units) || + MATCH(".units.weight", uemis_weight_unit, &input_units) || + MATCH(".units.time", uemis_time_unit, &input_units) || + MATCH(".units.date", uemis_date_unit, &input_units) || MATCH(".date_time", uemis_date_time, &dive->when) || MATCH(".time_zone", uemis_time_zone, &dive->when) || MATCH(".ambient.temperature", decicelsius, &dive->airtemp) || - MATCH(".air.bottom_tank.size", cylindersize, &dive->cylinder[0].type.size) || - MATCH(".air.bottom_tank.oxygen", percent, &dive->cylinder[0].gasmix.o2) || - MATCH(".nitrox_1.bottom_tank.size", cylindersize, &dive->cylinder[1].type.size) || - MATCH(".nitrox_1.bottom_tank.oxygen", percent, &dive->cylinder[1].gasmix.o2) || - MATCH(".nitrox_2.bottom_tank.size", cylindersize, &dive->cylinder[2].type.size) || - MATCH(".nitrox_2.bottom_tank.oxygen", percent, &dive->cylinder[2].gasmix.o2) || - MATCH(".nitrox_2.deco_tank.size", cylindersize, &dive->cylinder[3].type.size) || - MATCH(".nitrox_2.deco_tank.oxygen", percent, &dive->cylinder[3].gasmix.o2) || - MATCH(".nitrox_3.bottom_tank.size", cylindersize, &dive->cylinder[4].type.size) || - MATCH(".nitrox_3.bottom_tank.oxygen", percent, &dive->cylinder[4].gasmix.o2) || - MATCH(".nitrox_3.deco_tank.size", cylindersize, &dive->cylinder[5].type.size) || - MATCH(".nitrox_3.deco_tank.oxygen", percent, &dive->cylinder[5].gasmix.o2) || - MATCH(".nitrox_3.travel_tank.size", cylindersize, &dive->cylinder[6].type.size) || - MATCH(".nitrox_3.travel_tank.oxygen", percent, &dive->cylinder[6].gasmix.o2) || + MATCH(".gas.template", get_index, &uemis_gas_template) || + MATCH(".air.bottom_tank.size", uemis_cylindersize, dive->cylinder + 0) || + MATCH(".air.bottom_tank.oxygen", uemis_percent, dive->cylinder + 0) || + MATCH(".nitrox_1.bottom_tank.size", uemis_cylindersize, dive->cylinder + 1) || + MATCH(".nitrox_1.bottom_tank.oxygen", uemis_percent, dive->cylinder + 1) || + MATCH(".nitrox_2.bottom_tank.size", uemis_cylindersize, dive->cylinder + 2) || + MATCH(".nitrox_2.bottom_tank.oxygen", uemis_percent, dive->cylinder + 2) || + MATCH(".nitrox_2.deco_tank.size", uemis_cylindersize, dive->cylinder + 3) || + MATCH(".nitrox_2.deco_tank.oxygen", uemis_percent, dive->cylinder + 3) || + MATCH(".nitrox_3.bottom_tank.size", uemis_cylindersize, dive->cylinder + 4) || + MATCH(".nitrox_3.bottom_tank.oxygen", uemis_percent, dive->cylinder + 4) || + MATCH(".nitrox_3.deco_tank.size", uemis_cylindersize, dive->cylinder + 5) || + MATCH(".nitrox_3.deco_tank.oxygen", uemis_percent, dive->cylinder + 5) || + MATCH(".nitrox_3.travel_tank.size", uemis_cylindersize, dive->cylinder + 6) || + MATCH(".nitrox_3.travel_tank.oxygen", uemis_percent, dive->cylinder + 6) || + 0; +} + +/* + * Uddf specifies ISO 8601 time format. + * + * There are many variations on that. This handles the useful cases. + */ +static void uddf_datetime(char *buffer, void *_when) +{ + char c; + int y,m,d,hh,mm,ss; + time_t *when = _when; + struct tm tm = { 0 }; + int i; + + i = sscanf(buffer, "%d-%d-%d%c%d:%d:%d", &y, &m, &d, &c, &hh, &mm, &ss); + if (i == 7) + goto success; + ss = 0; + if (i == 6) + goto success; + + i = sscanf(buffer, "%04d%02d%02d%c%02d%02d%02d", &y, &m, &d, &c, &hh, &mm, &ss); + if (i == 7) + goto success; + ss = 0; + if (i == 6) + goto success; +bad_date: + printf("Bad date time %s\n", buffer); + free(buffer); + return; + +success: + if (c != 'T' && c != ' ') + goto bad_date; + tm.tm_year = y; + tm.tm_mon = m - 1; + tm.tm_mday = d; + tm.tm_hour = hh; + tm.tm_min = mm; + tm.tm_sec = ss; + *when = utc_mktime(&tm); + free(buffer); +} + +static int uddf_dive_match(struct dive *dive, const char *name, int len, char *buf) +{ + return MATCH(".datetime", uddf_datetime, &dive->when) || + MATCH(".diveduration", duration, &dive->duration) || + MATCH(".greatestdepth", depth, &dive->maxdepth) || 0; } +static void gps_location(char *buffer, void *_dive) +{ + int i; + struct dive *dive = _dive; + double latitude, longitude; + + i = sscanf(buffer, "%lf %lf", &latitude, &longitude); + if (i == 2) { + dive->latitude = latitude; + dive->longitude = longitude; + } + free(buffer); +} + /* 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) { int len = strlen(name); start_match("dive", name, buf); + + switch (import_source) { + case SUUNTO: + if (suunto_dive_match(dive, name, len, buf)) + return; + break; + + case UEMIS: + if (uemis_dive_match(dive, name, len, buf)) + return; + break; + + case DIVINGLOG: + if (divinglog_dive_match(dive, name, len, buf)) + return; + break; + + case UDDF: + if (uddf_dive_match(dive, name, len, buf)) + return; + break; + + default: + break; + } + + if (MATCH(".number", get_index, &dive->number)) + return; if (MATCH(".date", divedate, &dive->when)) return; if (MATCH(".time", divetime, &dive->when)) @@ -633,6 +972,10 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH(".meandepth", depth, &dive->meandepth)) return; + if (MATCH(".depth.max", depth, &dive->maxdepth)) + return; + if (MATCH(".depth.mean", depth, &dive->meandepth)) + return; if (MATCH(".duration", duration, &dive->duration)) return; if (MATCH(".divetime", duration, &dive->duration)) @@ -645,14 +988,24 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH(".watertemp", temperature, &dive->watertemp)) return; + if (MATCH(".temperature.air", temperature, &dive->airtemp)) + return; + if (MATCH(".temperature.water", temperature, &dive->watertemp)) + return; if (MATCH(".cylinderstartpressure", pressure, &dive->cylinder[0].start)) return; if (MATCH(".cylinderendpressure", pressure, &dive->cylinder[0].end)) return; + if (MATCH(".gps", gps_location, dive)) + return; if (MATCH(".location", utf8_string, &dive->location)) return; if (MATCH(".notes", utf8_string, &dive->notes)) return; + if (MATCH(".divemaster", utf8_string, &dive->divemaster)) + return; + if (MATCH(".buddy", utf8_string, &dive->buddy)) + return; if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cylinder_index].type.size)) return; @@ -672,13 +1025,6 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) if (MATCH(".he", gasmix, &dive->cylinder[cylinder_index].gasmix.he)) return; - /* Suunto XML files are some crazy sh*t. */ - if (suunto && suunto_dive_match(dive, name, len, buf)) - return; - - if (uemis && uemis_dive_match(dive, name, len, buf)) - return; - nonmatch("dive", name, buf); } @@ -690,21 +1036,13 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) */ static void dive_start(void) { - unsigned int size; - if (dive) return; - - alloc_samples = 5; - size = dive_size(alloc_samples); - dive = malloc(size); - if (!dive) - exit(1); - memset(dive, 0, size); + dive = alloc_dive(); memset(&tm, 0, sizeof(tm)); } -static void sanitize_gasmix(gasmix_t *mix) +static void sanitize_gasmix(struct gasmix *mix) { unsigned int o2, he; @@ -735,7 +1073,8 @@ static void sanitize_gasmix(gasmix_t *mix) */ static void match_standard_cylinder(cylinder_type_t *type) { - int psi, cuft, len; + double cuft; + int psi, len; const char *fmt; char buffer[20], *p; @@ -743,7 +1082,8 @@ static void match_standard_cylinder(cylinder_type_t *type) if (type->description) return; - cuft = type->size.mliter / 1000; + cuft = type->size.mliter / 28317.0; + cuft *= to_ATM(type->workingpressure); psi = type->workingpressure.mbar / 68.95; switch (psi) { @@ -751,7 +1091,7 @@ static void match_standard_cylinder(cylinder_type_t *type) fmt = "LP%d"; break; case 2600 ... 2700: /* 2640 psi: LP+10% */ - fmt = "LP%d+"; + fmt = "LP%d"; break; case 2900 ... 3100: /* 3000 psi: ALx tank */ fmt = "AL%d"; @@ -765,7 +1105,7 @@ static void match_standard_cylinder(cylinder_type_t *type) default: return; } - len = snprintf(buffer, sizeof(buffer), fmt, cuft); + len = snprintf(buffer, sizeof(buffer), fmt, (int) (cuft+0.5)); p = malloc(len+1); if (!p) return; @@ -796,14 +1136,15 @@ static void sanitize_cylinder_type(cylinder_type_t *type) if (!type->size.mliter) return; + if (input_units.volume == CUFT || import_source == SUUNTO) { + volume_of_air = type->size.mliter * 28.317; /* milli-cu ft to milliliter */ + atm = to_ATM(type->workingpressure); /* working pressure in atm */ + volume = volume_of_air / atm; /* milliliters at 1 atm: "true size" */ + type->size.mliter = volume + 0.5; + } + /* Ok, we have both size and pressure: try to match a description */ match_standard_cylinder(type); - - /* .. and let's assume that the 'size' was cu ft of air */ - volume_of_air = type->size.mliter * 28.317; /* milli-cu ft to milliliter */ - atm = type->workingpressure.mbar / 1013.25; /* working pressure in atm */ - volume = volume_of_air / atm; /* milliliters at 1 atm: "true size" */ - type->size.mliter = volume + 0.5; } static void sanitize_cylinder_info(struct dive *dive) @@ -826,34 +1167,17 @@ static void dive_end(void) cylinder_index = 0; } -static void suunto_start(void) -{ - suunto++; - units = SI_units; -} - -static void suunto_end(void) -{ - suunto--; -} - -static void uemis_start(void) -{ - uemis++; - units = SI_units; -} - -static void uemis_end(void) -{ -} - static void event_start(void) { + memset(&event, 0, sizeof(event)); + event.active = 1; } static void event_end(void) { - event_index++; + if (event.name && strcmp(event.name, "surface") != 0) + add_event(dive, event.time.seconds, event.type, event.flags, event.value, event.name); + event.active = 0; } static void cylinder_start(void) @@ -867,23 +1191,7 @@ static void cylinder_end(void) static void sample_start(void) { - int nr; - - if (!dive) - return; - nr = dive->samples; - if (nr >= alloc_samples) { - unsigned int size; - - alloc_samples = (alloc_samples * 3)/2 + 10; - size = dive_size(alloc_samples); - dive = realloc(dive, size); - if (!dive) - return; - } - sample = dive->sample + nr; - memset(sample, 0, sizeof(*sample)); - event_index = 0; + sample = prepare_sample(&dive); } static void sample_end(void) @@ -891,8 +1199,8 @@ static void sample_end(void) if (!dive) return; + finish_sample(dive, sample); sample = NULL; - dive->samples++; } static void entry(const char *name, int size, const char *raw) @@ -903,6 +1211,10 @@ static void entry(const char *name, int size, const char *raw) return; memcpy(buf, raw, size); buf[size] = 0; + if (event.active) { + try_to_fill_event(name, buf); + return; + } if (sample) { try_to_fill_sample(sample, name, buf); return; @@ -991,6 +1303,43 @@ static void visit(xmlNode *n) traverse(n->children); } +static void suunto_importer(void) +{ + import_source = SUUNTO; + input_units = SI_units; +} + +static void uemis_importer(void) +{ + import_source = UEMIS; + input_units = SI_units; +} + +static void DivingLog_importer(void) +{ + import_source = DIVINGLOG; + + /* + * Diving Log units are really strange. + * + * Temperatures are in C, except in samples, + * when they are in Fahrenheit. Depths are in + * meters, an dpressure is in PSI in the samples, + * but in bar when it comes to working pressure. + * + * Crazy f*%^ morons. + */ + input_units = SI_units; +} + +static void uddf_importer(void) +{ + import_source = UDDF; + input_units = SI_units; + input_units.pressure = PASCAL; + input_units.temperature = KELVIN; +} + /* * I'm sure this could be done as some fancy DTD rules. * It's just not worth the headache. @@ -1000,14 +1349,22 @@ static struct nesting { void (*start)(void), (*end)(void); } nesting[] = { { "dive", dive_start, dive_end }, - { "SUUNTO", suunto_start, suunto_end }, + { "Dive", dive_start, dive_end }, { "sample", sample_start, sample_end }, + { "waypoint", sample_start, sample_end }, { "SAMPLE", sample_start, sample_end }, { "reading", sample_start, sample_end }, { "event", event_start, event_end }, { "gasmix", cylinder_start, cylinder_end }, { "cylinder", cylinder_start, cylinder_end }, - { "pre_dive", uemis_start, uemis_end }, + { "P", sample_start, sample_end }, + + /* Import type recognition */ + { "SUUNTO", suunto_importer }, + { "Divinglog", DivingLog_importer }, + { "pre_dive", uemis_importer }, + { "uddf", uddf_importer }, + { NULL, } }; @@ -1042,21 +1399,29 @@ static void reset_all(void) * data within one file, we might have to reset it per * dive for that format. */ - units = SI_units; - suunto = 0; - uemis = 0; + input_units = SI_units; + import_source = UNKNOWN; } -void parse_xml_file(const char *filename) +void parse_xml_file(const char *filename, GError **error) { xmlDoc *doc; doc = xmlReadFile(filename, NULL, 0); if (!doc) { fprintf(stderr, "Failed to parse '%s'.\n", filename); + if (error != NULL) + { + *error = g_error_new(g_quark_from_string("subsurface"), + DIVE_ERROR_PARSE, + "Failed to parse '%s'", + filename); + } return; } - + /* we assume that the last (or only) filename passed as argument is a + * great filename to use as default when saving the dives */ + set_filename(filename); reset_all(); dive_start(); traverse(xmlDocGetRootElement(doc));