static int nmea_reader_update_time( NmeaReader* r, Token tok ) { int hour, minute; double seconds; struct tm tm; time_t fix_time; if (tok.p + 6 > tok.end) return -1; if (r->utc_year <= 2000) { r->utc_year = 1970; r->utc_mon = 1; r->utc_day = 1; } hour = str2int(tok.p, tok.p+2); minute = str2int(tok.p+2, tok.p+4); seconds = str2float(tok.p+4, tok.end); tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = (int) seconds; tm.tm_year = r->utc_year - 1900; tm.tm_mon = r->utc_mon - 1; tm.tm_mday = r->utc_day; fix_time = utc_mktime( &tm ); r->fix.timestamp = (long long)fix_time * 1000; return 0; }
static bool imap_mktime(struct tm *tm, time_t *time_r) { *time_r = utc_mktime(tm); if (*time_r != (time_t)-1) return TRUE; /* the date is outside valid range for time_t. it might still be technically valid though, so try to handle this case. with 64bit time_t the full 0..9999 year range is valid. */ if (tm->tm_year <= 100) { /* too old. time_t can be signed or unsigned, handle both cases. */ *time_r = (time_t)-1 < (int)0 ? INT_MIN : 0; } else { /* too high. return the highest allowed value. we shouldn't get here with 64bit time_t, but handle that anyway. */ /* APPLE */ if (time_t_max_bits() == 32 || time_t_max_bits() == 64) *time_r = (1UL << (time_t_max_bits()-1)) - 1; else *time_r = (1UL << time_t_max_bits()) - 1; } return FALSE; }
static timestamp_t parse_date(const char *date) { int hour, min, sec; struct tm tm; char *p; memset(&tm, 0, sizeof(tm)); tm.tm_mday = strtol(date, &p, 10); if (tm.tm_mday < 1 || tm.tm_mday > 31) return 0; for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) { if (!memcmp(p, monthname(tm.tm_mon), 3)) break; } if (tm.tm_mon > 11) return 0; date = p + 3; tm.tm_year = strtol(date, &p, 10); if (date == p) return 0; if (tm.tm_year < 70) tm.tm_year += 2000; if (tm.tm_year < 100) tm.tm_year += 1900; if (sscanf(p, "%d:%d:%d", &hour, &min, &sec) != 3) return 0; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; return utc_mktime(&tm); }
static void divedate(char *buffer, void *_when) { int d,m,y; time_t *when = _when; int success = 0; success = tm.tm_sec | tm.tm_min | 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; } else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) { tm.tm_year = y; tm.tm_mon = m-1; tm.tm_mday = d; } else { fprintf(stderr, "Unable to parse date '%s'\n", buffer); success = 0; } if (success) *when = utc_mktime(&tm); free(buffer); }
static void divetime(char *buffer, void *_when) { int h,m,s = 0; timestamp_t *when = _when; if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) { cur_tm.tm_hour = h; cur_tm.tm_min = m; cur_tm.tm_sec = s; *when = utc_mktime(&cur_tm); } }
static void update_time(timestamp_t *when, const char *line) { unsigned h, m, s = 0; struct tm tm; if (sscanf(line, "%02u:%02u:%02u", &h, &m, &s) < 2) return; utc_mkdate(*when, &tm); tm.tm_hour = h; tm.tm_min = m; tm.tm_sec = s; *when = utc_mktime(&tm); }
static dive_trip_t *create_new_trip(int yyyy, int mm, int dd) { dive_trip_t *trip = calloc(1, sizeof(dive_trip_t)); struct tm tm = { 0 }; /* We'll fill in the real data from the trip descriptor file */ tm.tm_year = yyyy; tm.tm_mon = mm-1; tm.tm_mday = dd; trip->when = utc_mktime(&tm); return trip; }
static void update_date(timestamp_t *when, const char *line) { unsigned yyyy, mm, dd; struct tm tm; if (sscanf(line, "%04u-%02u-%02u", &yyyy, &mm, &dd) != 3) return; utc_mkdate(*when, &tm); tm.tm_year = yyyy - 1900; tm.tm_mon = mm - 1; tm.tm_mday = dd; *when = utc_mktime(&tm); }
/* helper function to parse the Uemis data structures */ static void uemis_ts(char *buffer, void *_when) { struct tm tm; timestamp_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 divetime(char *buffer, void *_when) { int h,m,s = 0; 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); } free(buffer); }
time64_t time64_from(const char* format, const char* src) { time64_t v; struct tm64 tm64; #if defined(OS_WINDOWS) FILETIME ft; SYSTEMTIME st; memset(&tm64, 0, sizeof(tm64)); time64_scanf(&tm64, format, src); if(!TIME64_VALID_SYSTEM_TIME(tm64)) return 0; st.wYear = (WORD)(tm64.year + 1900); st.wMonth = (WORD)(tm64.month + 1); st.wDay = (WORD)tm64.day; st.wDayOfWeek = (WORD)tm64.wday; st.wHour = (WORD)tm64.hour; st.wMinute = (WORD)tm64.minute; st.wSecond = (WORD)tm64.second; st.wMilliseconds = (WORD)tm64.millisecond; SystemTimeToFileTime(&st, &ft); v = (((unsigned __int64)ft.dwHighDateTime << 32) | (unsigned __int64)ft.dwLowDateTime) / 10000; // to ms v -= 0xA9730B66800; /* 11644473600000LL */ // January 1, 1601 (UTC) -> January 1, 1970 (UTC). #else struct tm t; memset(&tm64, 0, sizeof(tm64)); tm64.day = 1; time64_scanf(&tm64, format, src); if(!TIME64_VALID_SYSTEM_TIME(tm64)) return 0; t.tm_year = tm64.year; t.tm_mon = tm64.month; t.tm_mday = tm64.day; t.tm_wday = tm64.wday; t.tm_hour = tm64.hour; t.tm_min = tm64.minute; t.tm_sec = tm64.second; // v = mktime(&t); v = utc_mktime(&t); v *= 1000; v += tm64.millisecond; #endif return v; }
/* Libdivecomputer: "2011-03-20 10:22:38" */ static void divedatetime(char *buffer, void *_when) { int y,m,d; int hr,min,sec; timestamp_t *when = _when; if (sscanf(buffer, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hr, &min, &sec) == 6) { 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); } }
//TODO: This should be moved to C-Code. time_t ShiftImageTimesDialog::epochFromExiv(EXIFInfo *exif) { struct tm tm; int year, month, day, hour, min, sec; if (strlen(exif->DateTimeOriginal.c_str())) sscanf(exif->DateTimeOriginal.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec); else sscanf(exif->DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec); tm.tm_year = year; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; return (utc_mktime(&tm)); }
void SG_time__parseRFC850(SG_context* pCtx,const char* pszInputString, SG_int64 * pTime, SG_int64 * pReturnedLocalTime) { int scanOK = 0; char trash[4]; int day = 0; int month = 0; int year = 0; int hour = 0; int minute = 0; int second = 0; char monthstr[4]; char tz[4]; struct tm t; SG_UNUSED(pCtx); SG_UNUSED(pszInputString); #if defined(WINDOWS) scanOK = sscanf_s(pszInputString, "%3s, %d %3s %d %d:%d:%d %3s", trash, sizeof(trash), &day, monthstr, sizeof(monthstr), &year, &hour, &minute, &second, tz, sizeof(tz)); #else scanOK = sscanf(pszInputString, "%3s, %d %3s %d %d:%d:%d %3s", trash, &day, monthstr, &year, &hour, &minute, &second, tz); #endif if ((scanOK != 8) || (strcmp("GMT", tz) != 0)) { SG_ERR_THROW_RETURN(SG_ERR_ARGUMENT_OUT_OF_RANGE); } SG_ERR_CHECK_RETURN( _lookupMonth(pCtx, monthstr, &month) ); t.tm_min = minute; t.tm_hour = hour; t.tm_sec = second; t.tm_year = year - 1900; t.tm_mon = month; t.tm_mday = day; *pTime = (SG_int64)utc_mktime(&t) * 1000; *pReturnedLocalTime = (SG_int64)mktime(&t) * 1000; }
static bool iso8601_date_do_parse(const unsigned char *data, size_t size, struct tm *tm_r, time_t *timestamp_r, int *timezone_offset_r) { struct iso8601_date_parser parser; time_t timestamp; memset(&parser, 0, sizeof(parser)); parser.cur = data; parser.end = data + size; if (iso8601_date_parse_date_time(&parser) <= 0) return FALSE; parser.tm.tm_isdst = -1; timestamp = utc_mktime(&parser.tm); if (timestamp == (time_t)-1) return FALSE; *timezone_offset_r = parser.timezone_offset; *tm_r = parser.tm; *timestamp_r = timestamp - parser.timezone_offset * 60; return TRUE; }
static void divedate(char *buffer, void *_when) { int d,m,y; int hh,mm,ss; timestamp_t *when = _when; hh = 0; mm = 0; ss = 0; if (sscanf(buffer, "%d.%d.%d %d:%d:%d", &d, &m, &y, &hh, &mm, &ss) >= 3) { /* This is ok, and we got at least the date */ } else if (sscanf(buffer, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) >= 3) { /* This is also ok */ } else { fprintf(stderr, "Unable to parse date '%s'\n", buffer); return; } cur_tm.tm_year = y; cur_tm.tm_mon = m-1; cur_tm.tm_mday = d; cur_tm.tm_hour = hh; cur_tm.tm_min = mm; cur_tm.tm_sec = ss; *when = utc_mktime(&cur_tm); }
/* * 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; timestamp_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); 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); }
bool http_date_parse(const unsigned char *data, size_t size, time_t *timestamp_r) { struct http_date_parser parser; time_t timestamp; memset(&parser, 0, sizeof(parser)); parser.cur = data; parser.end = data + size; if (http_date_parse_format_any(&parser) <= 0) return FALSE; if (parser.cur != parser.end) return FALSE; parser.tm.tm_isdst = -1; timestamp = utc_mktime(&parser.tm); if (timestamp == (time_t)-1) return FALSE; *timestamp_r = timestamp; return TRUE; }
int parse_txt_file(const char *filename, const char *csv) { struct memblock memtxt, memcsv; if (readfile(filename, &memtxt) < 0) { return report_error(translate("gettextFromC", "Failed to read '%s'"), filename); } /* * MkVI stores some information in .txt file but the whole profile and events are stored in .csv file. First * make sure the input .txt looks like proper MkVI file, then start parsing the .csv. */ if (MATCH(memtxt.buffer, "MkVI_Config") == 0) { int d, m, y, he; int hh = 0, mm = 0, ss = 0; int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1; bool has_depth = false, has_setpoint = false, has_ndl = false; char *lineptr, *key, *value; int cur_cylinder_index = 0; unsigned int prev_time = 0; struct dive *dive; struct divecomputer *dc; struct tm cur_tm; value = parse_mkvi_value(memtxt.buffer, "Dive started at"); if (sscanf(value, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) != 6) { free(value); return -1; } free(value); cur_tm.tm_year = y; cur_tm.tm_mon = m - 1; cur_tm.tm_mday = d; cur_tm.tm_hour = hh; cur_tm.tm_min = mm; cur_tm.tm_sec = ss; dive = alloc_dive(); dive->when = utc_mktime(&cur_tm);; dive->dc.model = strdup("Poseidon MkVI Discovery"); value = parse_mkvi_value(memtxt.buffer, "Rig Serial number"); dive->dc.deviceid = atoi(value); free(value); dive->dc.divemode = CCR; dive->dc.no_o2sensors = 2; dive->cylinder[cur_cylinder_index].cylinder_use = OXYGEN; dive->cylinder[cur_cylinder_index].type.size.mliter = 3000; dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000; dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6"); dive->cylinder[cur_cylinder_index].gasmix.o2.permille = 1000; cur_cylinder_index++; dive->cylinder[cur_cylinder_index].cylinder_use = DILUENT; dive->cylinder[cur_cylinder_index].type.size.mliter = 3000; dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000; dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6"); value = parse_mkvi_value(memtxt.buffer, "Helium percentage"); he = atoi(value); free(value); value = parse_mkvi_value(memtxt.buffer, "Nitrogen percentage"); dive->cylinder[cur_cylinder_index].gasmix.o2.permille = (100 - atoi(value) - he) * 10; free(value); dive->cylinder[cur_cylinder_index].gasmix.he.permille = he * 10; cur_cylinder_index++; lineptr = strstr(memtxt.buffer, "Dive started at"); while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) { ++lineptr; // Skip over '\n' key = next_mkvi_key(lineptr); if (!key) break; value = parse_mkvi_value(lineptr, key); if (!value) { free(key); break; } add_extra_data(&dive->dc, key, value); free(key); free(value); } dc = &dive->dc; /* * Read samples from the CSV file. A sample contains all the lines with same timestamp. The CSV file has * the following format: * * timestamp, type, value * * And following fields are of interest to us: * * 6 sensor1 * 7 sensor2 * 8 depth * 13 o2 tank pressure * 14 diluent tank pressure * 20 o2 setpoint * 39 water temp */ if (readfile(csv, &memcsv) < 0) { free(dive); return report_error(translate("gettextFromC", "Poseidon import failed: unable to read '%s'"), csv); } lineptr = memcsv.buffer; for (;;) { struct sample *sample; int type; int value; int sampletime; int gaschange = 0; /* Collect all the information for one sample */ sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value); has_depth = false; has_setpoint = false; has_ndl = false; sample = prepare_sample(dc); /* * There was a bug in MKVI download tool that resulted in erroneous sample * times. This fix should work similarly as the vendor's own. */ sample->time.seconds = cur_sampletime < 0xFFFF * 3 / 4 ? cur_sampletime : prev_time; prev_time = sample->time.seconds; do { int i = sscanf(lineptr, "%d,%d,%d", &sampletime, &type, &value); switch (i) { case 3: switch (type) { case 0: //Mouth piece position event: 0=OC, 1=CC, 2=UN, 3=NC switch (value) { case 0: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position OC")); break; case 1: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position CC")); break; case 2: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position unknown")); break; case 3: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position not connected")); break; } break; case 3: //Power Off event add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Power off")); break; case 4: //Battery State of Charge in % #ifdef SAMPLE_EVENT_BATTERY add_event(dc, cur_sampletime, SAMPLE_EVENT_BATTERY, 0, value, QT_TRANSLATE_NOOP("gettextFromC", "battery")); #endif break; case 6: //PO2 Cell 1 Average add_sample_data(sample, POSEIDON_SENSOR1, value); break; case 7: //PO2 Cell 2 Average add_sample_data(sample, POSEIDON_SENSOR2, value); break; case 8: //Depth * 2 has_depth = true; prev_depth = value; add_sample_data(sample, POSEIDON_DEPTH, value); break; //9 Max Depth * 2 //10 Ascent/Descent Rate * 2 case 11: //Ascent Rate Alert >10 m/s add_event(dc, cur_sampletime, SAMPLE_EVENT_ASCENT, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "ascent")); break; case 13: //O2 Tank Pressure add_sample_pressure(sample, 0, lrint(value * 1000)); break; case 14: //Diluent Tank Pressure add_sample_pressure(sample, 1, lrint(value * 1000)); break; //16 Remaining dive time #1? //17 related to O2 injection case 20: //PO2 Setpoint has_setpoint = true; prev_setpoint = value; add_sample_data(sample, POSEIDON_SETPOINT, value); break; case 22: //End of O2 calibration Event: 0 = OK, 2 = Failed, rest of dive setpoint 1.0 if (value == 2) add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration failed")); add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration")); break; case 25: //25 Max Ascent depth add_sample_data(sample, POSEIDON_CEILING, value); break; case 31: //Start of O2 calibration Event add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_BEGIN, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration")); break; case 37: //Remaining dive time #2? has_ndl = true; prev_ndl = value; add_sample_data(sample, POSEIDON_NDL, value); break; case 39: // Water Temperature in Celcius add_sample_data(sample, POSEIDON_TEMP, value); break; case 85: //He diluent part in % gaschange += value << 16; break; case 86: //O2 diluent part in % gaschange += value; break; //239 Unknown, maybe PO2 at sensor validation? //240 Unknown, maybe PO2 at sensor validation? //247 Unknown, maybe PO2 Cell 1 during pressure test //248 Unknown, maybe PO2 Cell 2 during pressure test //250 PO2 Cell 1 //251 PO2 Cell 2 default: break; } /* sample types */ break; case EOF: break; default: printf("Unable to parse input: %s\n", lineptr); break; } lineptr = strchr(lineptr, '\n'); if (!lineptr || !*lineptr) break; lineptr++; /* Grabbing next sample time */ sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value); } while (sampletime == cur_sampletime); if (gaschange) add_event(dc, cur_sampletime, SAMPLE_EVENT_GASCHANGE2, 0, gaschange, QT_TRANSLATE_NOOP("gettextFromC", "gaschange")); if (!has_depth) add_sample_data(sample, POSEIDON_DEPTH, prev_depth); if (!has_setpoint && prev_setpoint >= 0) add_sample_data(sample, POSEIDON_SETPOINT, prev_setpoint); if (!has_ndl && prev_ndl >= 0) add_sample_data(sample, POSEIDON_NDL, prev_ndl); finish_sample(dc); if (!lineptr || !*lineptr) break; } record_dive(dive); return 1; } else { return 0; } return 0; }
/* * Dive directory, name is [[yyyy-]mm-]nn-ddd-hh:mm:ss[~hex], * and 'timeoff' points to what should be the time part of * the name (the first digit of the hour). * * The root path will be of the form yyyy/mm[/tripdir], */ static int dive_directory(const char *root, const char *name, int timeoff) { int yyyy = -1, mm = -1, dd = -1; int h, m, s; int mday_off, month_off, year_off; struct tm tm; /* Skip the '-' before the time */ mday_off = timeoff; if (!mday_off || name[--mday_off] != '-') return GIT_WALK_SKIP; /* Skip the day name */ while (mday_off > 0 && name[--mday_off] != '-') /* nothing */; mday_off = mday_off - 2; month_off = mday_off - 3; year_off = month_off - 5; if (mday_off < 0) return GIT_WALK_SKIP; /* Get the time of day */ if (sscanf(name+timeoff, "%d:%d:%d", &h, &m, &s) != 3) return GIT_WALK_SKIP; if (!validate_time(h, m, s)) return GIT_WALK_SKIP; /* * Using the "git_tree_walk()" interface is simple, but * it kind of sucks as an interface because there is * no sane way to pass the hierarchy to the callbacks. * The "payload" is a fixed one-time thing: we'd like * the "current trip" to be passed down to the dives * that get parsed under that trip, but we can't. * * So "active_trip" is not the trip that is in the hierarchy * _above_ us, it's just the trip that was _before_ us. But * if a dive is not in a trip at all, we can't tell. * * We could just do a better walker that passes the * return value around, but we hack around this by * instead looking at the one hierarchical piece of * data we have: the pathname to the current entry. * * This is pretty hacky. The magic '8' is the length * of a pathname of the form 'yyyy/mm/'. */ if (strlen(root) == 8) finish_active_trip(); /* * Get the date. The day of the month is in the dive directory * name, the year and month might be in the path leading up * to it. */ dd = atoi(name + mday_off); if (year_off < 0) { if (sscanf(root, "%d/%d", &yyyy, &mm) != 2) return GIT_WALK_SKIP; } else yyyy = atoi(name + year_off); if (month_off >= 0) mm = atoi(name + month_off); if (!validate_date(yyyy, mm, dd)) return GIT_WALK_SKIP; /* Ok, close enough. We've gotten sufficient information */ memset(&tm, 0, sizeof(tm)); tm.tm_hour = h; tm.tm_min = m; tm.tm_sec = s; tm.tm_year = yyyy - 1900; tm.tm_mon = mm-1; tm.tm_mday = dd; finish_active_dive(); active_dive = create_new_dive(utc_mktime(&tm)); return GIT_WALK_OK; }
static int dive_cb(const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) { int rc; parser_t *parser = NULL; device_data_t *devdata = userdata; dc_datetime_t dt = {0}; struct tm tm; struct dive *dive; rc = create_parser(devdata, &parser); if (rc != PARSER_STATUS_SUCCESS) { fprintf(stderr, "Unable to create parser for %s", devdata->name); return rc; } rc = parser_set_data(parser, data, size); if (rc != PARSER_STATUS_SUCCESS) { fprintf(stderr, "Error registering the data."); parser_destroy(parser); return rc; } dive = alloc_dive(); rc = parser_get_datetime(parser, &dt); if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { fprintf(stderr, "Error parsing the datetime."); parser_destroy (parser); return rc; } tm.tm_year = dt.year; tm.tm_mon = dt.month-1; tm.tm_mday = dt.day; tm.tm_hour = dt.hour; tm.tm_min = dt.minute; tm.tm_sec = dt.second; dive->when = utc_mktime(&tm); // Parse the divetime. printf("Parsing the divetime.\n"); unsigned int divetime = 0; rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime); if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { fprintf(stderr, "Error parsing the divetime."); parser_destroy(parser); return rc; } dive->duration.seconds = divetime; // Parse the maxdepth. printf("Parsing the maxdepth.\n"); double maxdepth = 0.0; rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth); if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { fprintf(stderr, "Error parsing the maxdepth."); parser_destroy(parser); return rc; } dive->maxdepth.mm = maxdepth * 1000 + 0.5; // Parse the gas mixes. printf("Parsing the gas mixes.\n"); unsigned int ngases = 0; rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases); if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { fprintf(stderr, "Error parsing the gas mix count."); parser_destroy(parser); return rc; } rc = parse_gasmixes(dive, parser, ngases); if (rc != PARSER_STATUS_SUCCESS) { fprintf(stderr, "Error parsing the gas mix."); parser_destroy(parser); return rc; } // Initialize the sample data. rc = parse_samples(&dive, parser); if (rc != PARSER_STATUS_SUCCESS) { fprintf(stderr, "Error parsing the samples."); parser_destroy(parser); return rc; } parser_destroy(parser); /* If we already saw this dive, abort. */ if (find_dive(dive, devdata)) return 0; record_dive(dive); return 1; }
static int dive_cb(const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) { int rc; dc_parser_t *parser = NULL; device_data_t *devdata = userdata; dc_datetime_t dt = {0}; struct tm tm; struct dive *dive; rc = create_parser(devdata, &parser); if (rc != DC_STATUS_SUCCESS) { dev_info(devdata, _("Unable to create parser for %s %s"), devdata->vendor, devdata->product); return rc; } rc = dc_parser_set_data(parser, data, size); if (rc != DC_STATUS_SUCCESS) { dev_info(devdata, _("Error registering the data")); dc_parser_destroy(parser); return rc; } import_dive_number++; dive = alloc_dive(); rc = dc_parser_get_datetime(parser, &dt); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { dev_info(devdata, _("Error parsing the datetime")); dc_parser_destroy(parser); return rc; } tm.tm_year = dt.year; tm.tm_mon = dt.month-1; tm.tm_mday = dt.day; tm.tm_hour = dt.hour; tm.tm_min = dt.minute; tm.tm_sec = dt.second; dive->when = utc_mktime(&tm); // Parse the divetime. dev_info(devdata, _("Dive %d: %s %d %04d"), import_dive_number, monthname(tm.tm_mon), tm.tm_mday, year(tm.tm_year)); unsigned int divetime = 0; rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { dev_info(devdata, _("Error parsing the divetime")); dc_parser_destroy(parser); return rc; } dive->duration.seconds = divetime; // Parse the maxdepth. double maxdepth = 0.0; rc = dc_parser_get_field(parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { dev_info(devdata, _("Error parsing the maxdepth")); dc_parser_destroy(parser); return rc; } dive->maxdepth.mm = maxdepth * 1000 + 0.5; // Parse the gas mixes. unsigned int ngases = 0; rc = dc_parser_get_field(parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { dev_info(devdata, _("Error parsing the gas mix count")); dc_parser_destroy(parser); return rc; } // Check if the libdivecomputer version already supports salinity double salinity = 1.03; #ifdef DC_FIELD_SALINITY rc = dc_parser_get_field(parser, DC_FIELD_SALINITY, 0, &salinity); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { dev_info(devdata, _("Error obtaining water salinity")); dc_parser_destroy(parser); return rc; } #endif dive->salinity = salinity * 10000.0 + 0.5; rc = parse_gasmixes(devdata, dive, parser, ngases); if (rc != DC_STATUS_SUCCESS) { dev_info(devdata, _("Error parsing the gas mix")); dc_parser_destroy(parser); return rc; } // Initialize the sample data. rc = parse_samples(devdata, &dive, parser); if (rc != DC_STATUS_SUCCESS) { dev_info(devdata, _("Error parsing the samples")); dc_parser_destroy(parser); return rc; } dc_parser_destroy(parser); /* If we already saw this dive, abort. */ if (!devdata->force_download && find_dive(dive, devdata)) return 0; dive->downloaded = TRUE; record_dive(dive); mark_divelist_changed(TRUE); return 1; }
static void cochran_parse_dive(const unsigned char *decode, unsigned mod, const unsigned char *in, unsigned size, struct dive_table *table) { unsigned char *buf = malloc(size); struct dive *dive; struct divecomputer *dc; struct tm tm = {0}; uint32_t csum[5]; double max_depth, avg_depth, min_temp; unsigned int duration = 0, corrupt_dive = 0; /* * The scrambling has odd boundaries. I think the boundaries * match some data structure size, but I don't know. They were * discovered the same way we dynamically discover the decode * size: automatically looking for least random output. * * The boundaries are also this confused "off-by-one" thing, * the same way the file size is off by one. It's as if the * cochran software forgot to write one byte at the beginning. */ partial_decode(0, 0x0fff, decode, 1, mod, in, size, buf); partial_decode(0x0fff, 0x1fff, decode, 0, mod, in, size, buf); partial_decode(0x1fff, 0x2fff, decode, 0, mod, in, size, buf); partial_decode(0x2fff, 0x48ff, decode, 0, mod, in, size, buf); /* * This is not all the descrambling you need - the above are just * what appears to be the fixed-size blocks. The rest is also * scrambled, but there seems to be size differences in the data, * so this just descrambles part of it: */ if (size < 0x4914 + config.logbook_size) { // Analyst calls this a "Corrupt Beginning Summary" free(buf); return; } // Decode log entry (512 bytes + random prefix) partial_decode(0x48ff, 0x4914 + config.logbook_size, decode, 0, mod, in, size, buf); unsigned int sample_size = size - 0x4914 - config.logbook_size; int g; unsigned int sample_pre_offset = 0, sample_end_offset = 0; // Decode sample data partial_decode(0x4914 + config.logbook_size, size, decode, 0, mod, in, size, buf); #ifdef COCHRAN_DEBUG // Display pre-logbook data puts("\nPre Logbook Data\n"); cochran_debug_write(buf, 0x4914); // Display log book puts("\nLogbook Data\n"); cochran_debug_write(buf + 0x4914, config.logbook_size + 0x400); // Display sample data puts("\nSample Data\n"); #endif dive = alloc_dive(); dc = &dive->dc; unsigned char *log = (buf + 0x4914); switch (config.type) { case TYPE_GEMINI: case TYPE_COMMANDER: if (config.type == TYPE_GEMINI) { dc->model = "Gemini"; dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no fill_default_cylinder(&dive->cylinder[0]); dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256 + log[CMD_O2_PERCENT + 1]) * 10; dive->cylinder[0].gasmix.he.permille = 0; } else { dc->model = "Commander"; dc->deviceid = array_uint32_le(buf + 0x31e); // serial no for (g = 0; g < 2; g++) { fill_default_cylinder(&dive->cylinder[g]); dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256 + log[CMD_O2_PERCENT + g * 2 + 1]) * 10; dive->cylinder[g].gasmix.he.permille = 0; } } tm.tm_year = log[CMD_YEAR]; tm.tm_mon = log[CMD_MON] - 1; tm.tm_mday = log[CMD_DAY]; tm.tm_hour = log[CMD_HOUR]; tm.tm_min = log[CMD_MIN]; tm.tm_sec = log[CMD_SEC]; tm.tm_isdst = -1; dive->when = dc->when = utc_mktime(&tm); dive->number = log[CMD_NUMBER] + log[CMD_NUMBER + 1] * 256 + 1; dc->duration.seconds = (log[CMD_BT] + log[CMD_BT + 1] * 256) * 60; dc->surfacetime.seconds = (log[CMD_SIT] + log[CMD_SIT + 1] * 256) * 60; dc->maxdepth.mm = lrint((log[CMD_MAX_DEPTH] + log[CMD_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->meandepth.mm = lrint((log[CMD_AVG_DEPTH] + log[CMD_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((log[CMD_MIN_TEMP] / 32) - 1.8); dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 * (double) log[CMD_ALTITUDE] * 250 * FEET, 5.25588) * 1000); dc->salinity = 10000 + 150 * log[CMD_WATER_CONDUCTIVITY]; SHA1(log + CMD_NUMBER, 2, (unsigned char *)csum); dc->diveid = csum[0]; if (log[CMD_MAX_DEPTH] == 0xff && log[CMD_MAX_DEPTH + 1] == 0xff) corrupt_dive = 1; sample_pre_offset = array_uint32_le(log + CMD_PREDIVE_OFFSET); sample_end_offset = array_uint32_le(log + CMD_END_OFFSET); break; case TYPE_EMC: dc->model = "EMC"; dc->deviceid = array_uint32_le(buf + 0x31e); // serial no for (g = 0; g < 4; g++) { fill_default_cylinder(&dive->cylinder[g]); dive->cylinder[g].gasmix.o2.permille = (log[EMC_O2_PERCENT + g * 2] / 256 + log[EMC_O2_PERCENT + g * 2 + 1]) * 10; dive->cylinder[g].gasmix.he.permille = (log[EMC_HE_PERCENT + g * 2] / 256 + log[EMC_HE_PERCENT + g * 2 + 1]) * 10; } tm.tm_year = log[EMC_YEAR]; tm.tm_mon = log[EMC_MON] - 1; tm.tm_mday = log[EMC_DAY]; tm.tm_hour = log[EMC_HOUR]; tm.tm_min = log[EMC_MIN]; tm.tm_sec = log[EMC_SEC]; tm.tm_isdst = -1; dive->when = dc->when = utc_mktime(&tm); dive->number = log[EMC_NUMBER] + log[EMC_NUMBER + 1] * 256 + 1; dc->duration.seconds = (log[EMC_BT] + log[EMC_BT + 1] * 256) * 60; dc->surfacetime.seconds = (log[EMC_SIT] + log[EMC_SIT + 1] * 256) * 60; dc->maxdepth.mm = lrint((log[EMC_MAX_DEPTH] + log[EMC_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->meandepth.mm = lrint((log[EMC_AVG_DEPTH] + log[EMC_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((log[EMC_MIN_TEMP] - 32) / 1.8); dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 * (double) log[EMC_ALTITUDE] * 250 * FEET, 5.25588) * 1000); dc->salinity = 10000 + 150 * (log[EMC_WATER_CONDUCTIVITY] & 0x3); SHA1(log + EMC_NUMBER, 2, (unsigned char *)csum); dc->diveid = csum[0]; if (log[EMC_MAX_DEPTH] == 0xff && log[EMC_MAX_DEPTH + 1] == 0xff) corrupt_dive = 1; sample_pre_offset = array_uint32_le(log + EMC_PREDIVE_OFFSET); sample_end_offset = array_uint32_le(log + EMC_END_OFFSET); break; } // Use the log information to determine actual profile sample size // Otherwise we will get surface time at end of dive. if (sample_pre_offset < sample_end_offset && sample_end_offset != 0xffffffff) sample_size = sample_end_offset - sample_pre_offset; cochran_parse_samples(dive, buf + 0x4914, buf + 0x4914 + config.logbook_size, sample_size, &duration, &max_depth, &avg_depth, &min_temp); // Check for corrupt dive if (corrupt_dive) { dc->maxdepth.mm = lrint(max_depth * FEET * 1000); dc->meandepth.mm = lrint(avg_depth * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((min_temp - 32) / 1.8); dc->duration.seconds = duration; } record_dive_to_table(dive, table); mark_divelist_changed(true); free(buf); }
int mbox_from_parse(const unsigned char *msg, size_t size, time_t *time_r, int *tz_offset_r, char **sender_r) { const unsigned char *msg_start, *sender_end, *msg_end; struct tm tm; int esc, alt_stamp, timezone_secs = 0, seen_timezone = FALSE; time_t t; *time_r = (time_t)-1; *sender_r = NULL; /* <sender> <date> <moreinfo> */ msg_start = msg; msg_end = msg + size; /* get sender */ if (msg < msg_end && *msg == '"') { /* "x y z"@domain - skip the quoted part */ esc = FALSE; msg++; while (msg < msg_end && (*msg != '"' || esc)) { if (*msg == '\r' || *msg == '\n') return -1; esc = *msg == '\\'; msg++; } msg++; } while (msg < msg_end && *msg != ' ') { if (*msg == '\r' || *msg == '\n') return -1; msg++; } sender_end = msg; while (msg < msg_end && *msg == ' ') msg++; /* next 29 chars should be in the date in asctime() format, eg. "Thu Nov 9 22:33:52 2001 +0300" - Some put the timezone before the year - Some use a named timezone before or after year, which we ignore - Some don't include seconds (-3) - Some don't include timezone (-5) */ if (msg+29-3-5 > msg_end) return -1; memset(&tm, 0, sizeof(tm)); /* skip weekday */ msg += 4; /* month */ if (mbox_parse_month(msg, &tm) < 0) { /* Try alternate timestamp: "Thu, 9 Nov 2002 22:33:52" */ alt_stamp = TRUE; msg++; if (!i_isdigit(msg[0])) return -1; tm.tm_mday = msg[0]-'0'; msg++; if (i_isdigit(msg[0])) { tm.tm_mday = tm.tm_mday*10 + msg[0]-'0'; msg++; } if (msg[0] != ' ') return -1; msg++; if (mbox_parse_month(msg, &tm) < 0) return -1; msg += 4; if (mbox_parse_year(msg, &tm) < 0) return -1; msg += 5; } else { alt_stamp = FALSE; msg += 4; /* day. single digit is usually preceded by extra space */ if (msg[0] == ' ') msg++; if (msg[1] == ' ') { if (!i_isdigit(msg[0])) return -1; tm.tm_mday = msg[0]-'0'; msg += 2; } else { if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ') return -1; tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; } } if (tm.tm_mday == 0) tm.tm_mday = 1; /* hour */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':') return -1; tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; /* minute */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) return -1; tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 2; /* optional second */ if (msg[0] == ':') { msg++; if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) return -1; tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 2; if (!alt_stamp) { if (msg[0] == ' ') msg++; else return -1; } } else if (!alt_stamp) { if (msg[0] != ' ') return -1; msg++; } /* optional named timezone */ if (alt_stamp) ; else if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || !i_isdigit(msg[2]) || !i_isdigit(msg[3])) { /* skip to next space */ while (msg < msg_end && *msg != ' ') { if (*msg == '\r' || *msg == '\n') return -1; msg++; } if (msg+5 > msg_end) return -1; msg++; } else if ((msg[0] == '-' || msg[0] == '+') && i_isdigit(msg[1]) && i_isdigit(msg[2]) && i_isdigit(msg[3]) && i_isdigit(msg[4]) && msg[5] == ' ') { /* numeric timezone, use it */ seen_timezone = TRUE; timezone_secs = (msg[1]-'0') * 10*60*60 + (msg[2]-'0') * 60*60 + (msg[3]-'0') * 10 + (msg[4]-'0'); if (msg[0] == '-') timezone_secs = -timezone_secs; msg += 6; } if (!alt_stamp) { /* year */ if (mbox_parse_year(msg, &tm) < 0) return -1; msg += 4; } tm.tm_isdst = -1; if (!seen_timezone && msg != msg_end && msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') && i_isdigit(msg[2]) && i_isdigit(msg[3]) && i_isdigit(msg[4]) && i_isdigit(msg[5])) { seen_timezone = TRUE; timezone_secs = (msg[2]-'0') * 10*60*60 + (msg[3]-'0') * 60*60 + (msg[4]-'0') * 10 + (msg[5]-'0'); if (msg[1] == '-') timezone_secs = -timezone_secs; } if (seen_timezone) { t = utc_mktime(&tm); if (t == (time_t)-1) return -1; t -= timezone_secs; *time_r = t; *tz_offset_r = timezone_secs/60; } else { /* assume local timezone */ *time_r = mktime(&tm); *tz_offset_r = utc_offset(localtime(time_r), *time_r); } *sender_r = i_strdup_until(msg_start, sender_end); return 0; }
static bool message_date_parser_tokens(struct message_date_parser_context *ctx, time_t *timestamp_r, int *timezone_offset_r) { struct tm tm; const unsigned char *value; size_t i, len; int ret; /* [weekday_name "," ] dd month_name [yy]yy hh:mi[:ss] timezone */ memset(&tm, 0, sizeof(tm)); rfc822_skip_lwsp(&ctx->parser); /* skip the optional weekday */ if (next_token(ctx, &value, &len) <= 0) return FALSE; if (len == 3) { if (*ctx->parser.data != ',') return FALSE; ctx->parser.data++; rfc822_skip_lwsp(&ctx->parser); if (next_token(ctx, &value, &len) <= 0) return FALSE; } /* dd */ if (len < 1 || len > 2 || !i_isdigit(value[0])) return FALSE; tm.tm_mday = value[0]-'0'; if (len == 2) { if (!i_isdigit(value[1])) return FALSE; tm.tm_mday = (tm.tm_mday * 10) + (value[1]-'0'); } /* month name */ if (next_token(ctx, &value, &len) <= 0 || len < 3) return FALSE; for (i = 0; i < 12; i++) { if (i_memcasecmp(month_names[i], value, 3) == 0) { tm.tm_mon = i; break; } } if (i == 12) return FALSE; /* [yy]yy */ if (next_token(ctx, &value, &len) <= 0 || (len != 2 && len != 4)) return FALSE; for (i = 0; i < len; i++) { if (!i_isdigit(value[i])) return FALSE; tm.tm_year = tm.tm_year * 10 + (value[i]-'0'); } if (len == 2) { /* two digit year, assume 1970+ */ if (tm.tm_year < 70) tm.tm_year += 100; } else { if (tm.tm_year < 1900) return FALSE; tm.tm_year -= 1900; } /* hh, allow also single digit */ if (next_token(ctx, &value, &len) <= 0 || len < 1 || len > 2 || !i_isdigit(value[0])) return FALSE; tm.tm_hour = value[0]-'0'; if (len == 2) { if (!i_isdigit(value[1])) return FALSE; tm.tm_hour = tm.tm_hour * 10 + (value[1]-'0'); } /* :mm (may be the last token) */ if (!IS_TIME_SEP(*ctx->parser.data)) return FALSE; ctx->parser.data++; rfc822_skip_lwsp(&ctx->parser); if (next_token(ctx, &value, &len) < 0 || len != 2 || !i_isdigit(value[0]) || !i_isdigit(value[1])) return FALSE; tm.tm_min = (value[0]-'0') * 10 + (value[1]-'0'); /* [:ss] */ if (ctx->parser.data != ctx->parser.end && IS_TIME_SEP(*ctx->parser.data)) { ctx->parser.data++; rfc822_skip_lwsp(&ctx->parser); if (next_token(ctx, &value, &len) <= 0 || len != 2 || !i_isdigit(value[0]) || !i_isdigit(value[1])) return FALSE; tm.tm_sec = (value[0]-'0') * 10 + (value[1]-'0'); } if ((ret = next_token(ctx, &value, &len)) < 0) return FALSE; if (ret == 0) { /* missing timezone */ *timezone_offset_r = 0; } else { /* timezone */ *timezone_offset_r = parse_timezone(value, len); } tm.tm_isdst = -1; *timestamp_r = utc_mktime(&tm); if (*timestamp_r == (time_t)-1) return FALSE; *timestamp_r -= *timezone_offset_r * 60; return TRUE; }