#include <string.h>
#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>
#include <libxml/tree.h>
+#ifdef XSLT
+#include <libxslt/transform.h>
+#endif
#include "dive.h"
+#include "uemis.h"
int verbose;
static enum import_source {
UNKNOWN,
LIBDIVECOMPUTER,
- SUUNTO,
UEMIS,
DIVINGLOG,
UDDF,
if (!val.fp)
break;
/* cbar to atm */
- atm = (val.fp / 100) / 1.01325;
+ atm = bar_to_atm(val.fp * 10);
/*
* atm to cm. Why not mm? The precision just isn't
* there.
return;
if (MATCH(".sample.cylpress", pressure, &sample->cylinderpressure))
return;
+ if (MATCH(".sample.cylinderindex", get_index, &sample->cylinderindex))
+ return;
if (MATCH(".sample.depth", depth, &sample->depth))
return;
if (MATCH(".sample.temp", temperature, &sample->temperature))
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->cylinder[0].gasmix.o2) ||
- MATCH(".hepct_0", percent, &dive->cylinder[0].gasmix.he) ||
- MATCH(".o2pct_2", percent, &dive->cylinder[1].gasmix.o2) ||
- MATCH(".hepct_1", percent, &dive->cylinder[1].gasmix.he) ||
- MATCH(".o2pct_3", percent, &dive->cylinder[2].gasmix.o2) ||
- MATCH(".hepct_2", percent, &dive->cylinder[2].gasmix.he) ||
- MATCH(".o2pct_4", percent, &dive->cylinder[3].gasmix.o2) ||
- MATCH(".hepct_3", percent, &dive->cylinder[3].gasmix.he) ||
- MATCH(".cylindersize", cylindersize, &dive->cylinder[0].type.size) ||
- MATCH(".cylinderworkpressure", pressure, &dive->cylinder[0].type.workingpressure) ||
- 0;
-}
-
static const char *country, *city;
static void divinglog_place(char *place, void *_location)
country = NULL;
}
-static int divinglog_dive_match(struct dive *dive, const char *name, int len, char *buf)
+static int divinglog_dive_match(struct dive **divep, const char *name, int len, char *buf)
{
+ struct dive *dive = *divep;
+
return MATCH(".divedate", divedate, &dive->when) ||
MATCH(".entrytime", divetime, &dive->when) ||
MATCH(".depth", depth, &dive->maxdepth) ||
#endif
}
+static void uemis_ts(char *buffer, void *_when)
+{
+ struct tm tm;
+ time_t *when = _when;
+
+ memset(&tm, 0, sizeof(tm));
+ sscanf(buffer,"%d-%d-%dT%d:%d:%d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ tm.tm_mon -= 1;
+ tm.tm_year -= 1900;
+ *when = utc_mktime(&tm);
+
+}
+
+static void uemis_duration(char *buffer, void *_duration)
+{
+ duration_t *duration = _duration;
+ duration->seconds = atof(buffer) * 60 + 0.5;
+}
+
/* 0 - air ; 1 - nitrox1 ; 2 - nitrox2 ; 3 = nitrox3 */
static int uemis_gas_template;
percent(buffer, &dive->cylinder[index].gasmix.o2);
}
-static int uemis_dive_match(struct dive *dive, const char *name, int len, char *buf)
+static int uemis_dive_match(struct dive **divep, const char *name, int len, char *buf)
{
+ struct dive *dive = *divep;
+
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(".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) ||
+ MATCH(".dive.val.float", uemis_duration, &dive->duration) ||
+ MATCH(".dive.val.ts", uemis_ts, &dive->when) ||
+ MATCH(".dive.val.bin", uemis_parse_divelog_binary, divep) ||
0;
}
free(buffer);
}
-static int uddf_dive_match(struct dive *dive, const char *name, int len, char *buf)
+static int uddf_dive_match(struct dive **divep, const char *name, int len, char *buf)
{
+ struct dive *dive = *divep;
+
return MATCH(".datetime", uddf_datetime, &dive->when) ||
MATCH(".diveduration", duration, &dive->duration) ||
MATCH(".greatestdepth", depth, &dive->maxdepth) ||
}
/* 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)
+static void try_to_fill_dive(struct dive **divep, 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))
+ if (uemis_dive_match(divep, name, len, buf))
return;
break;
case DIVINGLOG:
- if (divinglog_dive_match(dive, name, len, buf))
+ if (divinglog_dive_match(divep, name, len, buf))
return;
break;
case UDDF:
- if (uddf_dive_match(dive, name, len, buf))
+ if (uddf_dive_match(divep, name, len, buf))
return;
break;
break;
}
+ struct dive *dive = *divep;
+
if (MATCH(".number", get_index, &dive->number))
return;
if (MATCH(".date", divedate, &dive->when))
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))
if (type->description)
return;
- cuft = type->size.mliter / 28317.0;
+ cuft = ml_to_cuft(type->size.mliter);
cuft *= to_ATM(type->workingpressure);
- psi = type->workingpressure.mbar / 68.95;
+ psi = to_PSI(type->workingpressure);
switch (psi) {
case 2300 ... 2500: /* 2400 psi: LP tank */
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 */
+ 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;
return;
}
if (dive) {
- try_to_fill_dive(dive, name, buf);
+ try_to_fill_dive(&dive, name, buf);
return;
}
}
traverse(n->children);
}
-static void suunto_importer(void)
-{
- import_source = SUUNTO;
- input_units = SI_units;
-}
-
static void uemis_importer(void)
{
import_source = UEMIS;
{ "P", sample_start, sample_end },
/* Import type recognition */
- { "SUUNTO", suunto_importer },
{ "Divinglog", DivingLog_importer },
{ "pre_dive", uemis_importer },
+ { "dives", uemis_importer },
{ "uddf", uddf_importer },
{ NULL, }
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;
- doc = xmlReadFile(filename, NULL, 0);
+ 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 = xmlReadMemory(mem.buffer, mem.size, filename, NULL, 0);
if (!doc) {
fprintf(stderr, "Failed to parse '%s'.\n", filename);
if (error != NULL)
set_filename(filename);
reset_all();
dive_start();
+#ifdef XSLT
+ doc = test_xslt_transforms(doc);
+#endif
traverse(xmlDocGetRootElement(doc));
dive_end();
xmlFreeDoc(doc);
{
LIBXML_TEST_VERSION
}
+
+#ifdef XSLT
+
+/* Maybe we'll want a environment variable that can override this.. */
+static const char *xslt_path = XSLT ":xslt:.";
+
+static xsltStylesheetPtr try_get_stylesheet(const char *path, int len, const char *name)
+{
+ xsltStylesheetPtr ret;
+ int namelen = strlen(name);
+ char *filename = malloc(len+1+namelen+1);
+
+ if (!filename)
+ return NULL;
+
+ memcpy(filename, path, len);
+ filename[len] = G_DIR_SEPARATOR;
+ memcpy(filename + len + 1, name, namelen+1);
+
+ ret = NULL;
+ if (!access(filename, R_OK))
+ ret = xsltParseStylesheetFile(filename);
+ free(filename);
+
+ return ret;
+}
+
+static xsltStylesheetPtr get_stylesheet(const char *name)
+{
+ const char *path = xslt_path, *next;
+
+ do {
+ int len;
+ xsltStylesheetPtr ret;
+
+ next = strchr(path, ':');
+ len = strlen(path);
+ if (next) {
+ len = next - path;
+ next++;
+ }
+ ret = try_get_stylesheet(path, len, name);
+ if (ret)
+ return ret;
+ } while ((path = next) != NULL);
+
+ return NULL;
+}
+
+static struct xslt_files {
+ const char *root;
+ const char *file;
+} xslt_files[] = {
+ { "SUUNTO", "SuuntoSDM.xslt" },
+ { "JDiveLog", "jdivelog2subsurface.xslt" },
+ { NULL, }
+};
+
+xmlDoc *test_xslt_transforms(xmlDoc *doc)
+{
+ struct xslt_files *info = xslt_files;
+ xmlDoc *transformed;
+ xsltStylesheetPtr xslt = NULL;
+ xmlNode *root_element = xmlDocGetRootElement(doc);
+
+ while ((info->root) && (strcasecmp(root_element->name, info->root) != 0)) {
+ info++;
+ }
+
+ if (info->root) {
+ xmlSubstituteEntitiesDefault(1);
+ xslt = get_stylesheet(info->file);
+ if (xslt == NULL)
+ return doc;
+ transformed = xsltApplyStylesheet(xslt, doc, NULL);
+ xmlFreeDoc(doc);
+ xsltFreeStylesheet(xslt);
+ return transformed;
+ }
+ return doc;
+}
+#endif