#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#define __USE_XOPEN
#include <time.h>
#include <libxml/parser.h>
return;
if (MATCH(".buddy", utf8_string, &dive->buddy))
return;
-
+ if (MATCH(".rating", get_index, &dive->rating))
+ return;
if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cylinder_index].type.size))
return;
if (MATCH(".cylinder.workpressure", pressure, &dive->cylinder[cylinder_index].type.workingpressure))
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)
- 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);
- }
-}
-
static void dive_end(void)
{
if (!dive)
return;
- sanitize_cylinder_info(dive);
record_dive(dive);
dive = NULL;
cylinder_index = 0;
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)