X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=parse-xml.c;h=cc2d0076d42f36491d6ce6809a12056a68067d8a;hb=788ebc0500b12fb502b82473c1459ccca06345a5;hp=b8f67932467308e7f1ce7df68e40a2d75299d3c9;hpb=e5471e3fe8c870bb564481783af95babe93494f8;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index b8f6793..cc2d007 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #define __USE_XOPEN #include #include @@ -96,16 +98,16 @@ const struct units IMPERIAL_units = { /* * Dive info as it is being built up.. */ -static struct dive *dive; -static struct sample *sample; +static struct dive *cur_dive; +static struct sample *cur_sample; static struct { int active; duration_t time; int type, flags, value; const char *name; -} event; -static struct tm tm; -static int cylinder_index; +} cur_event; +static struct tm cur_tm; +static int cur_cylinder_index; static enum import_source { UNKNOWN, @@ -151,22 +153,22 @@ static void divedate(char *buffer, void *_when) time_t *when = _when; int success = 0; - success = tm.tm_sec | tm.tm_min | tm.tm_hour; + success = cur_tm.tm_sec | cur_tm.tm_min | cur_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; + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; } else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) { - tm.tm_year = y; - tm.tm_mon = m-1; - tm.tm_mday = d; + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; } else { fprintf(stderr, "Unable to parse date '%s'\n", buffer); success = 0; } if (success) - *when = utc_mktime(&tm); + *when = utc_mktime(&cur_tm); free(buffer); } @@ -177,11 +179,11 @@ static void divetime(char *buffer, void *_when) time_t *when = _when; if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) { - tm.tm_hour = h; - tm.tm_min = m; - tm.tm_sec = s; - if (tm.tm_year) - *when = utc_mktime(&tm); + cur_tm.tm_hour = h; + cur_tm.tm_min = m; + cur_tm.tm_sec = s; + if (cur_tm.tm_year) + *when = utc_mktime(&cur_tm); } free(buffer); } @@ -195,13 +197,13 @@ static void divedatetime(char *buffer, void *_when) if (sscanf(buffer, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hr, &min, &sec) == 6) { - tm.tm_year = y; - tm.tm_mon = m-1; - tm.tm_mday = d; - tm.tm_hour = hr; - tm.tm_min = min; - tm.tm_sec = sec; - *when = utc_mktime(&tm); + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; + cur_tm.tm_hour = hr; + cur_tm.tm_min = min; + cur_tm.tm_sec = sec; + *when = utc_mktime(&cur_tm); } free(buffer); } @@ -376,7 +378,7 @@ static void gasmix(char *buffer, void *_fraction) /* libdivecomputer does negative percentages. */ if (*buffer == '-') return; - if (cylinder_index < MAX_CYLINDERS) + if (cur_cylinder_index < MAX_CYLINDERS) percent(buffer, _fraction); } @@ -573,8 +575,8 @@ static void eventtime(char *buffer, void *_duration) { duration_t *duration = _duration; sampletime(buffer, duration); - if (sample) - duration->seconds += sample->time.seconds; + if (cur_sample) + duration->seconds += cur_sample->time.seconds; } static void try_to_fill_event(const char *name, char *buf) @@ -582,17 +584,17 @@ 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)) + if (MATCH(".event", utf8_string, &cur_event.name)) return; - if (MATCH(".name", utf8_string, &event.name)) + if (MATCH(".name", utf8_string, &cur_event.name)) return; - if (MATCH(".time", eventtime, &event.time)) + if (MATCH(".time", eventtime, &cur_event.time)) return; - if (MATCH(".type", get_index, &event.type)) + if (MATCH(".type", get_index, &cur_event.type)) return; - if (MATCH(".flags", get_index, &event.flags)) + if (MATCH(".flags", get_index, &cur_event.flags)) return; - if (MATCH(".value", get_index, &event.value)) + if (MATCH(".value", get_index, &cur_event.value)) return; nonmatch("event", name, buf); } @@ -804,7 +806,7 @@ static int uemis_gas_template; static int uemis_cylinder_index(void *_cylinder) { cylinder_t *cylinder = _cylinder; - unsigned int index = cylinder - dive->cylinder; + unsigned int index = cylinder - cur_dive->cylinder; if (index > 6) { fprintf(stderr, "Uemis cylinder pointer calculations broken\n"); @@ -836,14 +838,14 @@ static void uemis_cylindersize(char *buffer, void *_cylinder) { int index = uemis_cylinder_index(_cylinder); if (index >= 0) - cylindersize(buffer, &dive->cylinder[index].type.size); + cylindersize(buffer, &cur_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); + percent(buffer, &cur_dive->cylinder[index].gasmix.o2); } static int uemis_dive_match(struct dive **divep, const char *name, int len, char *buf) @@ -1024,23 +1026,24 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) return; if (MATCH(".buddy", utf8_string, &dive->buddy)) return; - - if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cylinder_index].type.size)) + if (MATCH(".rating", get_index, &dive->rating)) + return; + if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cur_cylinder_index].type.size)) return; - if (MATCH(".cylinder.workpressure", pressure, &dive->cylinder[cylinder_index].type.workingpressure)) + if (MATCH(".cylinder.workpressure", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure)) return; - if (MATCH(".cylinder.description", utf8_string, &dive->cylinder[cylinder_index].type.description)) + if (MATCH(".cylinder.description", utf8_string, &dive->cylinder[cur_cylinder_index].type.description)) return; - if (MATCH(".cylinder.start", pressure, &dive->cylinder[cylinder_index].start)) + if (MATCH(".cylinder.start", pressure, &dive->cylinder[cur_cylinder_index].start)) return; - if (MATCH(".cylinder.end", pressure, &dive->cylinder[cylinder_index].end)) + if (MATCH(".cylinder.end", pressure, &dive->cylinder[cur_cylinder_index].end)) return; - if (MATCH(".o2", gasmix, &dive->cylinder[cylinder_index].gasmix.o2)) + if (MATCH(".o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) return; - if (MATCH(".n2", gasmix_nitrogen, &dive->cylinder[cylinder_index].gasmix)) + if (MATCH(".n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix)) return; - if (MATCH(".he", gasmix, &dive->cylinder[cylinder_index].gasmix.he)) + if (MATCH(".he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he)) return; nonmatch("dive", name, buf); @@ -1054,149 +1057,34 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) */ static void dive_start(void) { - if (dive) - return; - dive = alloc_dive(); - memset(&tm, 0, sizeof(tm)); -} - -static void sanitize_gasmix(struct gasmix *mix) -{ - unsigned int o2, he; - - o2 = mix->o2.permille; - he = mix->he.permille; - - /* Regular air: leave empty */ - if (!he) { - if (!o2) - return; - /* 20.9% or 21% O2 is just air */ - if (o2 >= 209 && o2 <= 210) { - mix->o2.permille = 0; - return; - } - } - - /* Sane mix? */ - if (o2 <= 1000 && he <= 1000 && o2+he <= 1000) - return; - fprintf(stderr, "Odd gasmix: %d O2 %d He\n", o2, he); - memset(mix, 0, sizeof(*mix)); -} - -/* - * See if the size/workingpressure looks like some standard cylinder - * size, eg "AL80". - */ -static void match_standard_cylinder(cylinder_type_t *type) -{ - double cuft; - int psi, len; - const char *fmt; - char buffer[20], *p; - - /* Do we already have a cylinder description? */ - if (type->description) + if (cur_dive) return; - - cuft = ml_to_cuft(type->size.mliter); - cuft *= to_ATM(type->workingpressure); - psi = to_PSI(type->workingpressure); - - switch (psi) { - case 2300 ... 2500: /* 2400 psi: LP tank */ - fmt = "LP%d"; - break; - case 2600 ... 2700: /* 2640 psi: LP+10% */ - fmt = "LP%d"; - break; - case 2900 ... 3100: /* 3000 psi: ALx tank */ - fmt = "AL%d"; - break; - case 3400 ... 3500: /* 3442 psi: HP tank */ - fmt = "HP%d"; - break; - case 3700 ... 3850: /* HP+10% */ - fmt = "HP%d+"; - break; - default: - return; - } - len = snprintf(buffer, sizeof(buffer), fmt, (int) (cuft+0.5)); - p = malloc(len+1); - if (!p) - return; - memcpy(p, buffer, len+1); - type->description = p; -} - - -/* - * There are two ways to give cylinder size information: - * - total amount of gas in cuft (depends on working pressure and physical size) - * - physical size - * - * where "physical size" is the one that actually matters and is sane. - * - * We internally use physical size only. But we save the workingpressure - * so that we can do the conversion if required. - */ -static void sanitize_cylinder_type(cylinder_type_t *type) -{ - double volume_of_air, atm, volume; - - /* If we have no working pressure, it had *better* be just a physical size! */ - if (!type->workingpressure.mbar) - return; - - /* No size either? Nothing to go on */ - if (!type->size.mliter) - return; - - if (input_units.volume == CUFT) { - /* confusing - we don't really start from ml but millicuft !*/ - volume_of_air = cuft_to_l(type->size.mliter); - 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); -} - -static void sanitize_cylinder_info(struct dive *dive) -{ - int i; - - for (i = 0; i < MAX_CYLINDERS; i++) { - sanitize_gasmix(&dive->cylinder[i].gasmix); - sanitize_cylinder_type(&dive->cylinder[i].type); - } + cur_dive = alloc_dive(); + memset(&cur_tm, 0, sizeof(cur_tm)); } static void dive_end(void) { - if (!dive) + if (!cur_dive) return; - sanitize_cylinder_info(dive); - record_dive(dive); - dive = NULL; - cylinder_index = 0; + record_dive(cur_dive); + cur_dive = NULL; + cur_cylinder_index = 0; } static void event_start(void) { - memset(&event, 0, sizeof(event)); - event.active = 1; + memset(&cur_event, 0, sizeof(cur_event)); + cur_event.active = 1; } static void event_end(void) { - 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; + if (cur_event.name && strcmp(cur_event.name, "surface") != 0) + add_event(cur_dive, cur_event.time.seconds, + cur_event.type, cur_event.flags, + cur_event.value, cur_event.name); + cur_event.active = 0; } static void cylinder_start(void) @@ -1205,21 +1093,21 @@ static void cylinder_start(void) static void cylinder_end(void) { - cylinder_index++; + cur_cylinder_index++; } static void sample_start(void) { - sample = prepare_sample(&dive); + cur_sample = prepare_sample(&cur_dive); } static void sample_end(void) { - if (!dive) + if (!cur_dive) return; - finish_sample(dive, sample); - sample = NULL; + finish_sample(cur_dive); + cur_sample = NULL; } static void entry(const char *name, int size, const char *raw) @@ -1230,16 +1118,16 @@ static void entry(const char *name, int size, const char *raw) return; memcpy(buf, raw, size); buf[size] = 0; - if (event.active) { + if (cur_event.active) { try_to_fill_event(name, buf); return; } - if (sample) { - try_to_fill_sample(sample, name, buf); + if (cur_sample) { + try_to_fill_sample(cur_sample, name, buf); return; } - if (dive) { - try_to_fill_dive(&dive, name, buf); + if (cur_dive) { + try_to_fill_dive(&cur_dive, name, buf); return; } } @@ -1416,11 +1304,70 @@ static void reset_all(void) import_source = UNKNOWN; } +struct memblock { + void *buffer; + size_t size; +}; + +static int readfile(const char *filename, struct memblock *mem) +{ + int ret, fd = open(filename, O_RDONLY); + struct stat st; + + mem->buffer = NULL; + mem->size = 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return fd; + ret = fstat(fd, &st); + if (ret < 0) + goto out; + ret = -EINVAL; + if (!S_ISREG(st.st_mode)) + goto out; + ret = 0; + if (!st.st_size) + goto out; + mem->buffer = malloc(st.st_size); + ret = -1; + errno = ENOMEM; + if (!mem->buffer) + goto out; + mem->size = st.st_size; + ret = read(fd, mem->buffer, mem->size); + if (ret < 0) + goto free; + if (ret == mem->size) + goto out; + errno = EIO; + ret = -1; +free: + free(mem->buffer); + mem->buffer = NULL; + mem->size = 0; +out: + close(fd); + return ret; +} + void parse_xml_file(const char *filename, GError **error) { xmlDoc *doc; + struct memblock mem; + + if (readfile(filename, &mem) < 0) { + fprintf(stderr, "Failed to read '%s'.\n", filename); + if (error) { + *error = g_error_new(g_quark_from_string("subsurface"), + DIVE_ERROR_PARSE, + "Failed to read '%s'", + filename); + } + return; + } - doc = xmlReadFile(filename, NULL, 0); + doc = xmlReadMemory(mem.buffer, mem.size, filename, NULL, 0); if (!doc) { fprintf(stderr, "Failed to parse '%s'.\n", filename); if (error != NULL)