diff options
Diffstat (limited to 'parse-xml.c')
-rw-r--r-- | parse-xml.c | 445 |
1 files changed, 349 insertions, 96 deletions
diff --git a/parse-xml.c b/parse-xml.c index 9f1e64a0e..c5ed21a54 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -21,6 +21,10 @@ int verbose, quit; int metric = 1; +int last_xml_version = -1; +bool abort_read_of_old_file = false; +bool v2_question_shown = false; +bool imported_via_xslt = false; static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params); @@ -128,6 +132,7 @@ const struct units IMPERIAL_units = IMPERIAL_UNITS; #define MAX_EVENT_NAME 128 static struct divecomputer *cur_dc; static struct dive *cur_dive; +static struct dive_site *cur_dive_site; static dive_trip_t *cur_trip = NULL; static struct sample *cur_sample; static struct picture *cur_picture; @@ -746,6 +751,9 @@ static void try_to_match_autogroup(const char *name, char *buf) void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx) { + /* sanity check so we don't crash */ + if (idx < 0 || idx >= MAX_CYLINDERS) + return; /* The gas switch event format is insane for historical reasons */ struct gasmix *mix = &dive->cylinder[idx].gasmix; int o2 = get_o2(mix); @@ -933,10 +941,8 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu return; if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2])) // up to 3 CCR sensors return; - if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint)) { - cur_dive->dc.divemode = CCR; + if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint)) return; - } if (MATCH("heartbeat", get_uint8, &sample->heartbeat)) return; if (MATCH("bearing", get_bearing, &sample->bearing)) @@ -968,22 +974,20 @@ void try_to_fill_userid(const char *name, char *buf) static const char *country, *city; -static void divinglog_place(char *place, char **location) +static void divinglog_place(char *place, uint32_t *uuid) { - char buffer[1024], *p; - int len; + char buffer[1024]; - 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; + snprintf(buffer, sizeof(buffer), + "%s%s%s%s%s", + place, + city ? ", " : "", + city ? city : "", + country ? ", " : "", + country ? country : ""); + *uuid = get_dive_site_uuid_by_name(buffer, NULL); + if (*uuid == 0) + *uuid = create_dive_site(buffer); city = NULL; country = NULL; @@ -1005,7 +1009,7 @@ static int divinglog_dive_match(struct dive *dive, const char *name, char *buf) MATCH("names.buddy", utf8_string, &dive->buddy) || MATCH("name.country", utf8_string, &country) || MATCH("name.city", utf8_string, &city) || - MATCH("name.place", divinglog_place, &dive->location) || + MATCH("name.place", divinglog_place, &dive->dive_site_uuid) || 0; } @@ -1127,23 +1131,119 @@ degrees_t parse_degrees(char *buf, char **end) static void gps_lat(char *buffer, struct dive *dive) { char *end; - - dive->latitude = parse_degrees(buffer, &end); + degrees_t latitude = parse_degrees(buffer, &end); + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) { + dive->dive_site_uuid = create_dive_site_with_gps(NULL, latitude, (degrees_t){0}); + } else { + if (ds->latitude.udeg && ds->latitude.udeg != latitude.udeg) + fprintf(stderr, "Oops, changing the latitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); + ds->latitude = latitude; + } } static void gps_long(char *buffer, struct dive *dive) { char *end; + degrees_t longitude = parse_degrees(buffer, &end); + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) { + dive->dive_site_uuid = create_dive_site_with_gps(NULL, (degrees_t){0}, longitude); + } else { + if (ds->longitude.udeg && ds->longitude.udeg != longitude.udeg) + fprintf(stderr, "Oops, changing the longitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); + ds->longitude = longitude; + } - dive->longitude = parse_degrees(buffer, &end); } -static void gps_location(char *buffer, struct dive *dive) +static void gps_location(char *buffer, struct dive_site *ds) { char *end; - dive->latitude = parse_degrees(buffer, &end); - dive->longitude = parse_degrees(end, &end); + ds->latitude = parse_degrees(buffer, &end); + ds->longitude = parse_degrees(end, &end); +} + +/* this is in qthelper.cpp, so including the .h file is a pain */ +extern const char *printGPSCoords(int lat, int lon); +extern void add_geo_information_for_loockup(degrees_t latitude, degrees_t longitude, uint32_t uuid); + +static void gps_in_dive(char *buffer, struct dive *dive) +{ + char *end; + struct dive_site *ds = NULL; + degrees_t latitude = parse_degrees(buffer, &end); + degrees_t longitude = parse_degrees(end, &end); + fprintf(stderr, "got lat %f lon %f\n", latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + uint32_t uuid = dive->dive_site_uuid; + if (uuid == 0) { + uuid = get_dive_site_uuid_by_gps(latitude, longitude, &ds); + if (ds) { + fprintf(stderr, "found dive site {%s} with these coordinates\n", ds->name); + dive->dive_site_uuid = uuid; + } else { + fprintf(stderr, "found no uuid in dive, no existing dive site with these coordinates, creating a new divesite without name and above GPS\n"); + dive->dive_site_uuid = create_dive_site_with_gps("", latitude, longitude); + ds = get_dive_site_by_uuid(dive->dive_site_uuid); + } + } else { + fprintf(stderr, "found uuid in dive, checking to see if we should add GPS\n"); + ds = get_dive_site_by_uuid(uuid); + if (dive_site_has_gps_location(ds) && + (latitude.udeg != 0 || longitude.udeg != 0) && + (ds->latitude.udeg != latitude.udeg || ds->longitude.udeg != longitude.udeg)) { + // Houston, we have a problem + fprintf(stderr, "dive site uuid in dive, but gps location (%10.6f/%10.6f) different from dive location (%10.6f/%10.6f)\n", + ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0, + latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + ds->notes = add_to_string(ds->notes, translate("gettextFromC", "multiple gps locations for this dive site; also %s\n"), + printGPSCoords(latitude.udeg, longitude.udeg)); + } else { + fprintf(stderr, "let's add the gps coordinates to divesite with uuid %8x and name %s\n", ds->uuid, ds->name ?: "(none)"); + ds->latitude = latitude; + ds->longitude = longitude; + } + } + if (ds && (!ds->notes || strstr(ds->notes, "countrytag:") == NULL)) + add_geo_information_for_loockup(latitude, longitude, dive->dive_site_uuid); +} + +static void add_dive_site(char *buffer, struct dive *dive) +{ + fprintf(stderr, "add_dive_site with name %s\n", buffer); + int size = trimspace(buffer); + if(size) { + uint32_t uuid = dive->dive_site_uuid; + struct dive_site *ds = get_dive_site_by_uuid(uuid); + if (uuid && !ds) { + // that's strange - we have a uuid but it doesn't exist - let's just ignore it + fprintf(stderr, "dive contains a non-existing dive site uuid %x\n", dive->dive_site_uuid); + uuid = 0; + } + if (!uuid) + // if the dive doesn't have a uuid, check if there's already a dive site by this name + uuid = get_dive_site_uuid_by_name(buffer, &ds); + if (ds) { + // we have a uuid, let's hope there isn't a different name + fprintf(stderr, "have existing site with name {%s} gps %f/%f ", ds->name, ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0); + if (same_string(ds->name, "")) { + fprintf(stderr, "so now add name {%s}\n", buffer); + ds->name = copy_string(buffer); + } else if (!same_string(ds->name, buffer)) { + // coin toss, let's just keep the first name we found and add the new one to the notes + fprintf(stderr, "which means the dive already links to dive site of different name {%s} / {%s}\n", ds->name, buffer); + ds->notes = add_to_string(ds->notes, translate("gettextFromC", "additional name for site: %s\n"), buffer); + } else { + // add the existing dive site to the current dive + fprintf(stderr, "we have an existing location, using {%s}\n", ds->name); + dive->dive_site_uuid = uuid; + } + } else { + fprintf(stderr, "no uuid, create new dive site with name {%s}\n", buffer); + dive->dive_site_uuid = create_dive_site(buffer); + } + } } static void gps_picture_location(char *buffer, struct picture *pic) @@ -1173,7 +1273,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) default: break; } - + if (MATCH("divesiteid", hex_value, &dive->dive_site_uuid)) + return; if (MATCH("number", get_index, &dive->number)) return; if (MATCH("tags", divetags, &dive->tag_list)) @@ -1199,13 +1300,15 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH("gps.picture", gps_picture_location, cur_picture)) return; + if (MATCH("hash.picture", utf8_string, &cur_picture->hash)) + 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)) + if (MATCH("gps", gps_in_dive, dive)) return; - if (MATCH("Place", gps_location, dive)) + if (MATCH("Place", gps_in_dive, dive)) return; if (MATCH("latitude", gps_lat, dive)) return; @@ -1219,9 +1322,9 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH("lon", gps_long, dive)) return; - if (MATCH("location", utf8_string, &dive->location)) + if (MATCH("location", add_dive_site, dive)) return; - if (MATCH("name.dive", utf8_string, &dive->location)) + if (MATCH("name.dive", add_dive_site, dive)) return; if (MATCH("suit", utf8_string, &dive->suit)) return; @@ -1290,6 +1393,27 @@ static void try_to_fill_trip(dive_trip_t **dive_trip_p, const char *name, char * nonmatch("trip", name, buf); } +/* We're processing a divesite entry - try to fill the components */ +static void try_to_fill_dive_site(struct dive_site **ds_p, const char *name, char *buf) +{ + start_match("divesite", name, buf); + + struct dive_site *ds = *ds_p; + + if (MATCH("uuid", hex_value, &ds->uuid)) + return; + if (MATCH("name", utf8_string, &ds->name)) + return; + if (MATCH("description", utf8_string, &ds->description)) + return; + if (MATCH("notes", utf8_string, &ds->notes)) + return; + if (MATCH("gps", gps_location, ds)) + return; + + nonmatch("divesite", name, buf); +} + /* * While in some formats file boundaries are dive boundaries, in many * others (as for example in our native format) there are @@ -1305,7 +1429,7 @@ static void try_to_fill_trip(dive_trip_t **dive_trip_p, const char *name, char * static bool is_dive(void) { return (cur_dive && - (cur_dive->location || cur_dive->when || cur_dive->dc.samples)); + (cur_dive->dive_site_uuid || cur_dive->when || cur_dive->dc.samples)); } static void reset_dc_info(struct divecomputer *dc) @@ -1349,6 +1473,32 @@ static void dc_settings_end(void) reset_dc_settings(); } +static void dive_site_start(void) +{ + if (cur_dive_site) + return; + cur_dive_site = calloc(1, sizeof(struct dive_site)); +} + +static void dive_site_end(void) +{ + if (!cur_dive_site) + return; + if (cur_dive_site->uuid) { + uint32_t tmp = create_dive_site_with_gps(cur_dive_site->name, cur_dive_site->latitude, cur_dive_site->longitude); + struct dive_site *ds = get_dive_site_by_uuid(tmp); + ds->uuid = cur_dive_site->uuid; + ds->notes = cur_dive_site->notes; + ds->description = cur_dive_site->description; + if (verbose > 3) + printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); + } + free(cur_dive_site); + cur_dive_site = NULL; +} + +// now we need to add the code to parse the parts of the divesite enry + static void dive_start(void) { if (cur_dive) @@ -1527,37 +1677,54 @@ static void userid_stop(void) in_userid = false; } -static void entry(const char *name, char *buf) +static bool entry(const char *name, char *buf) { + if (!strncmp(name, "version.program", sizeof("version.program") - 1) || + !strncmp(name, "version.divelog", sizeof("version.divelog") - 1)) { + last_xml_version = atoi(buf); + if (last_xml_version < 3 && !v2_question_shown && !imported_via_xslt) { + // let's ask the user what they want to do about reverse geo coding + // and warn them that opening older XML files can take a while + // since C code shouldn't call the UI we set a global flag and bail + // from reading the file for now + abort_read_of_old_file = true; + return false; + } + } if (in_userid) { try_to_fill_userid(name, buf); - return; + return true; } if (in_settings) { try_to_fill_dc_settings(name, buf); try_to_match_autogroup(name, buf); - return; + return true; + } + if (cur_dive_site) { + try_to_fill_dive_site(&cur_dive_site, name, buf); + return true; } if (!cur_event.deleted) { try_to_fill_event(name, buf); - return; + return true; } if (cur_sample) { try_to_fill_sample(cur_sample, name, buf); - return; + return true; } if (cur_dc) { try_to_fill_dc(cur_dc, name, buf); - return; + return true; } if (cur_dive) { try_to_fill_dive(cur_dive, name, buf); - return; + return true; } if (cur_trip) { try_to_fill_trip(&cur_trip, name, buf); - return; + return true; } + return true; } static const char *nodename(xmlNode *node, char *buf, int len) @@ -1599,7 +1766,7 @@ static const char *nodename(xmlNode *node, char *buf, int len) #define MAXNAME 32 -static void visit_one_node(xmlNode *node) +static bool visit_one_node(xmlNode *node) { char *content; static char buffer[MAXNAME]; @@ -1607,28 +1774,29 @@ static void visit_one_node(xmlNode *node) content = node->content; if (!content || xmlIsBlankNode(node)) - return; + return true; name = nodename(node, buffer, sizeof(buffer)); - entry(name, content); + return entry(name, content); } -static void traverse(xmlNode *root); +static bool traverse(xmlNode *root); -static void traverse_properties(xmlNode *node) +static bool traverse_properties(xmlNode *node) { xmlAttr *p; + bool ret = true; for (p = node->properties; p; p = p->next) - traverse(p->children); + if ((ret = traverse(p->children)) == false) + break; + return ret; } -static void visit(xmlNode *n) +static bool visit(xmlNode *n) { - visit_one_node(n); - traverse_properties(n); - traverse(n->children); + return visit_one_node(n) && traverse_properties(n) && traverse(n->children); } static void DivingLog_importer(void) @@ -1666,6 +1834,7 @@ static struct nesting { } nesting[] = { { "divecomputerid", dc_settings_start, dc_settings_end }, { "settings", settings_start, settings_end }, + { "site", dive_site_start, dive_site_end }, { "dive", dive_start, dive_end }, { "Dive", dive_start, dive_end }, { "trip", trip_start, trip_end }, @@ -1690,15 +1859,17 @@ static struct nesting { { NULL, } }; -static void traverse(xmlNode *root) +static bool traverse(xmlNode *root) { xmlNode *n; + bool ret = true; for (n = root; n; n = n->next) { struct nesting *rule = nesting; if (!n->name) { - visit(n); + if ((ret = visit(n)) == false) + break; continue; } @@ -1710,10 +1881,12 @@ static void traverse(xmlNode *root) if (rule->start) rule->start(); - visit(n); + if ((ret = visit(n)) == false) + break; if (rule->end) rule->end(); } + return ret; } /* Per-file reset */ @@ -1760,6 +1933,7 @@ int parse_xml_buffer(const char *url, const char *buffer, int size, { xmlDoc *doc; const char *res = preprocess_divelog_de(buffer); + int ret = 0; target_table = table; doc = xmlReadMemory(res, strlen(res), url, NULL, 0); @@ -1774,11 +1948,14 @@ int parse_xml_buffer(const char *url, const char *buffer, int size, reset_all(); dive_start(); doc = test_xslt_transforms(doc, params); - traverse(xmlDocGetRootElement(doc)); + if (!traverse(xmlDocGetRootElement(doc))) { + // we decided to give up on parsing... why? + ret = -1; + } dive_end(); xmlFreeDoc(doc); - - return 0; + imported_via_xslt = false; + return ret; } void parse_mkvi_buffer(struct membuffer *txt, struct membuffer *csv, const char *starttime) @@ -1861,13 +2038,24 @@ extern int dm4_events(void *handle, int columns, char **data, char **column) strcpy(cur_event.name, "deco"); break; case 22: + case 32: /* 22 Mandatory safety stop violation */ + /* 32 Deep stop violation */ strcpy(cur_event.name, "violation"); break; + case 30: + /* Tissue level warning */ + strcpy(cur_event.name, "tissue warning"); + break; + case 37: + /* Tank pressure alarm */ + strcpy(cur_event.name, "tank pressure"); + break; case 257: /* 257 Dive active */ - /* This seems to be given after surface - * when descending again. Ignoring it. */ + /* This seems to be given after surface when + * descending again. */ + strcpy(cur_event.name, "surface"); break; case 258: /* 258 Bookmark */ @@ -1878,6 +2066,23 @@ extern int dm4_events(void *handle, int columns, char **data, char **column) strcpy(cur_event.name, "bookmark"); } break; + case 259: + /* Deep stop */ + strcpy(cur_event.name, "Deep stop"); + break; + case 260: + /* Deep stop */ + strcpy(cur_event.name, "Deep stop cleared"); + break; + case 266: + /* Mandatory safety stop activated */ + strcpy(cur_event.name, "safety stop (mandatory)"); + break; + case 267: + /* Mandatory safety stop deactivated */ + /* DM5 shows this only on event list, not on the + * profile so skipping as well for now */ + break; default: strcpy(cur_event.name, "unknown"); cur_event.value = atoi(data[2]); @@ -1889,6 +2094,44 @@ extern int dm4_events(void *handle, int columns, char **data, char **column) return 0; } +extern int dm5_cylinders(void *handle, int columns, char **data, char **column) +{ + cylinder_start(); + if (data[7] && atoi(data[7]) > 0 && atoi(data[7]) < 350000) + cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[7]); + if (data[8] && atoi(data[8]) > 0 && atoi(data[8]) < 350000) + cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[8])); + if (data[6]) { + /* DM5 shows tank size of 12 liters when the actual + * value is 0 (and using metric units). So we just use + * the same 12 liters when size is not available */ + if (atof(data[6]) == 0.0 && cur_dive->cylinder[cur_cylinder_index].start.mbar) + cur_dive->cylinder[cur_cylinder_index].type.size.mliter = 12000; + else + cur_dive->cylinder[cur_cylinder_index].type.size.mliter = (atof(data[6])) * 1000; + } + if (data[2]) + cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atoi(data[2]) * 10; + if (data[3]) + cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atoi(data[3]) * 10; + cylinder_end(); + return 0; +} + +extern int dm5_gaschange(void *handle, int columns, char **data, char **column) +{ + event_start(); + if (data[0]) + cur_event.time.seconds = atoi(data[0]); + if (data[1]) { + strcpy(cur_event.name, "gaschange"); + cur_event.value = atof(data[1]); + } + event_end(); + + return 0; +} + extern int dm4_tags(void *handle, int columns, char **data, char **column) { if (data[0]) @@ -2031,7 +2274,9 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) char *err = NULL; char get_events_template[] = "select * from Mark where DiveId = %d"; char get_tags_template[] = "select Text from DiveTag where DiveId = %d"; - char get_events[64]; + char get_cylinders_template[] = "select * from DiveMixture where DiveId = %d"; + char get_gaschange_template[] = "select GasChangeTime,Oxygen,Helium from DiveGasChange join DiveMixture on DiveGasChange.DiveMixtureId=DiveMixture.DiveMixtureId where DiveId = %d"; + char get_events[512]; dive_start(); cur_dive->number = atoi(data[0]); @@ -2050,12 +2295,13 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) */ settings_start(); dc_settings_start(); - if (data[4]) + if (data[4]) { utf8_string(data[4], &cur_settings.dc.serial_nr); + cur_settings.dc.deviceid = atoi(data[4]); + } if (data[5]) utf8_string(data[5], &cur_settings.dc.model); - cur_settings.dc.deviceid = 0xffffffff; dc_settings_end(); settings_end(); @@ -2066,30 +2312,21 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) if (data[9]) cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); - /* - * TODO: handle multiple cylinders - */ - cylinder_start(); - if (data[22] && atoi(data[22]) > 0) - cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[22]); - else if (data[10] && atoi(data[10]) > 0) - cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[10]); - if (data[23] && atoi(data[23]) > 0) - cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[23])); - if (data[11] && atoi(data[11]) > 0) - cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[11])); - if (data[12]) - cur_dive->cylinder[cur_cylinder_index].type.size.mliter = (atof(data[12])) * 1000; - if (data[13]) - cur_dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = (atoi(data[13])); - if (data[20]) - cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atoi(data[20]) * 10; - if (data[21]) - cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atoi(data[21]) * 10; - cylinder_end(); + if (data[4]) { + cur_dive->dc.deviceid = atoi(data[4]); + } + if (data[5]) + utf8_string(data[5], &cur_dive->dc.model); + + snprintf(get_events, sizeof(get_events) - 1, get_cylinders_template, cur_dive->number); + retval = sqlite3_exec(handle, get_events, &dm5_cylinders, 0, &err); + if (retval != SQLITE_OK) { + fprintf(stderr, "%s", translate("gettextFromC", "Database query dm5_cylinders failed.\n")); + return 1; + } if (data[14]) - cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) * 1000); + cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) / 100); interval = data[16] ? atoi(data[16]) : 0; sampleBlob = (unsigned const char *)data[24]; @@ -2141,6 +2378,13 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) } } + snprintf(get_events, sizeof(get_events) - 1, get_gaschange_template, cur_dive->number); + retval = sqlite3_exec(handle, get_events, &dm5_gaschange, 0, &err); + if (retval != SQLITE_OK) { + fprintf(stderr, "%s", translate("gettextFromC", "Database query dm5_gaschange failed.\n")); + return 1; + } + snprintf(get_events, sizeof(get_events) - 1, get_events_template, cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm4_events, 0, &err); if (retval != SQLITE_OK) { @@ -2191,7 +2435,7 @@ int parse_dm5_buffer(sqlite3 *handle, const char *url, const char *buffer, int s /* StartTime is converted from Suunto's nano seconds to standard * time. We also need epoch, not seconds since year 1. */ - char get_dives[] = "select D.DiveId,StartTime/10000000-62135596800,Note,Duration,SourceSerialNumber,Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,D.StartPressure,D.EndPressure,Size,CylinderWorkPressure,SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,Oxygen,Helium,MIX.StartPressure,MIX.EndPressure,SampleBlob FROM Dive AS D JOIN DiveMixture AS MIX ON D.DiveId=MIX.DiveId"; + char get_dives[] = "select DiveId,StartTime/10000000-62135596800,Note,Duration,coalesce(SourceSerialNumber,SerialNumber),Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,StartPressure,EndPressure,'','',SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,'','','','',SampleBlob FROM Dive where Deleted is null"; retval = sqlite3_exec(handle, get_dives, &dm5_dive, handle, &err); @@ -2291,7 +2535,7 @@ extern int shearwater_dive(void *param, int columns, char **data, char **column) cur_dive->when = (time_t)(atol(data[1])); if (data[2]) - utf8_string(data[2], &cur_dive->location); + add_dive_site(data[2], cur_dive); if (data[3]) utf8_string(data[3], &cur_dive->buddy); if (data[4]) @@ -2388,19 +2632,21 @@ extern int cobalt_visibility(void *handle, int columns, char **data, char **colu extern int cobalt_location(void *handle, int columns, char **data, char **column) { + static char *location = NULL; if (data[0]) { - if (cur_dive->location) { - char *tmp = malloc(strlen(cur_dive->location) + strlen(data[0]) + 4); + if (location) { + char *tmp = malloc(strlen(location) + strlen(data[0]) + 4); if (!tmp) return -1; - sprintf(tmp, "%s / %s", cur_dive->location, data[0]); - free(cur_dive->location); - cur_dive->location = tmp; + sprintf(tmp, "%s / %s", location, data[0]); + free(location); + location = NULL; + cur_dive->dive_site_uuid = create_dive_site(tmp); + free(tmp); } else { - utf8_string(data[0], &cur_dive->location); + location = strdup(data[0]); } } - return 0; } @@ -2448,13 +2694,20 @@ extern int cobalt_dive(void *param, int columns, char **data, char **column) */ settings_start(); dc_settings_start(); - if (data[9]) + if (data[9]) { utf8_string(data[9], &cur_settings.dc.serial_nr); + cur_settings.dc.deviceid = atoi(data[9]); + cur_settings.dc.model = strdup("Cobalt import"); + } - cur_settings.dc.deviceid = 0xffffffff; dc_settings_end(); settings_end(); + if (data[9]) { + cur_dive->dc.deviceid = atoi(data[9]); + cur_dive->dc.model = strdup("Cobalt import"); + } + snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, cur_dive->number); retval = sqlite3_exec(handle, get_buffer, &cobalt_cylinders, 0, &err); if (retval != SQLITE_OK) { @@ -2529,7 +2782,7 @@ int parse_cobalt_buffer(sqlite3 *handle, const char *url, const char *buffer, in char *err = NULL; target_table = table; - char get_dives[] = "select Id,strftime('%s',DiveStartTime),LocationId,'buddy','notes',Units,(MaxDepthPressure*10000/SurfacePressure)-10000,DiveMinutes,SurfacePressure,SerialNumber,'model' from Dive"; + char get_dives[] = "select Id,strftime('%s',DiveStartTime),LocationId,'buddy','notes',Units,(MaxDepthPressure*10000/SurfacePressure)-10000,DiveMinutes,SurfacePressure,SerialNumber,'model' from Dive where IsViewDeleted = 0"; retval = sqlite3_exec(handle, get_dives, &cobalt_dive, handle, &err); @@ -2563,8 +2816,8 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size) // (ptr[7] << 8) + ptr[6] Is "Serial" snprintf(serial, sizeof(serial), "%d", (ptr[7] << 8) + ptr[6]); cur_dc->serial = strdup(serial); - // Dive start time in seconds since 2000-01-01 12:00 UTC +0 - cur_dc->when = (ptr[11] << 24) + (ptr[10] << 16) + (ptr[9] << 8) + ptr[8] + 946728000; + // Dive start time in seconds since 2000-01-01 00:00 + cur_dc->when = (ptr[11] << 24) + (ptr[10] << 16) + (ptr[9] << 8) + ptr[8] + 946684800; cur_dive->when = cur_dc->when; cur_dc->duration.seconds = ((ptr[14] & 0xFE) << 16) + (ptr[13] << 8) + ptr[12]; @@ -2903,7 +3156,7 @@ static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params) } free((void *)attribute); } - + imported_via_xslt = true; xmlSubstituteEntitiesDefault(1); xslt = get_stylesheet(info->file); if (xslt == NULL) { |