Change what iso8601_to_nstime() and unix_epoch_to_nstime() return.

Instead of rturning an 8-bit(!) integer giving the number of characters
parsed, have them return a pointer to the first character *after* the
string that was parsed, similarly to what strto*() (and Wireshark's
wrappers for them in wsutil) and strptime() return.

This cleans up some code that uses those routines.

For the 3GPP 32.423 trace files, we also reject files where there isn't
an ISO 8601-format time where we expect there to be one.  (Having the
string-format date/time routines return NULL on an error means you have
to think about what to do on failure.)
This commit is contained in:
Guy Harris 2023-09-09 13:36:23 -07:00 committed by Gerald Combs
parent e1b885728a
commit 656f00ef29
8 changed files with 61 additions and 54 deletions

View File

@ -1449,7 +1449,7 @@ main(int argc, char *argv[])
nstime_t in_time;
check_startstop = TRUE;
if ((0 < iso8601_to_nstime(&in_time, ws_optarg, ISO8601_DATETIME)) || (0 < unix_epoch_to_nstime(&in_time, ws_optarg))) {
if ((NULL != iso8601_to_nstime(&in_time, ws_optarg, ISO8601_DATETIME)) || (NULL != unix_epoch_to_nstime(&in_time, ws_optarg))) {
if (opt == 'A') {
nstime_copy(&starttime, &in_time);
have_starttime = TRUE;

View File

@ -246,10 +246,12 @@ absolute_val_from_string(fvalue_t *fv, const char *s, size_t len _U_, char **err
return TRUE;
/* Try ISO 8601 format. */
if (iso8601_to_nstime(&fv->value.time, s, ISO8601_DATETIME) == strlen(s))
endptr = iso8601_to_nstime(&fv->value.time, s, ISO8601_DATETIME);
/* Check whether it parsed all of the string */
if (endptr != NULL && *endptr == '\0')
return TRUE;
/* Try other legacy formats. */
/* No - try other legacy formats. */
memset(&tm, 0, sizeof(tm));
/* Let the computer figure out if it's DST. */
tm.tm_isdst = -1;

View File

@ -1809,15 +1809,15 @@ tvb_get_string_time(tvbuff_t *tvb, const gint offset, const gint length,
if (*ptr) {
if ((encoding & ENC_ISO_8601_DATE_TIME) == ENC_ISO_8601_DATE_TIME) {
if ((num_chars = iso8601_to_nstime(ns, ptr, ISO8601_DATETIME))) {
end = ptr + num_chars;
} else {
if (!(end = iso8601_to_nstime(ns, ptr, ISO8601_DATETIME))) {
goto fail;
}
} else if ((encoding & ENC_ISO_8601_DATE_TIME_BASIC) == ENC_ISO_8601_DATE_TIME_BASIC) {
if ((num_chars = iso8601_to_nstime(ns, ptr, ISO8601_DATETIME_BASIC))) {
end = ptr + num_chars;
} else {
if (!(end = iso8601_to_nstime(ns, ptr, ISO8601_DATETIME_BASIC))) {
goto fail;
}
} else {

View File

@ -47,7 +47,7 @@ static gboolean eri_enb_log_get_packet(FILE_T fh, wtap_rec* rec,
length = length - 1;
}
if (0 < iso8601_to_nstime(&packet_time, line+1, ISO8601_DATETIME)) {
if (NULL != iso8601_to_nstime(&packet_time, line+1, ISO8601_DATETIME)) {
rec->ts.secs = packet_time.secs;
rec->ts.nsecs = packet_time.nsecs;
rec->presence_flags |= WTAP_HAS_TS;

View File

@ -652,7 +652,8 @@ nettrace_3gpp_32_423_file_open(wtap *wth, int *err, gchar **err_info)
{
char magic_buf[MAGIC_BUF_SIZE+1];
int bytes_read;
char *curr_pos;
const char *curr_pos;
nstime_t start_time;
nettrace_3gpp_32_423_file_info_t *file_info;
gint64 start_offset;
@ -689,10 +690,15 @@ nettrace_3gpp_32_423_file_open(wtap *wth, int *err, gchar **err_info)
return WTAP_OPEN_NOT_MINE;
}
curr_pos += CLEN(c_begin_time);
/* Next we expect an ISO 8601-format time */
curr_pos = iso8601_to_nstime(&start_time, curr_pos, ISO8601_DATETIME);
if (!curr_pos) {
return WTAP_OPEN_NOT_MINE;
}
/* Ok it's our file. From here we'll need to free memory */
file_info = g_new0(nettrace_3gpp_32_423_file_info_t, 1);
curr_pos += iso8601_to_nstime(&file_info->start_time, curr_pos, ISO8601_DATETIME);
file_info->start_time = start_time;
file_info->start_offset = start_offset + (curr_pos - magic_buf);
file_info->buffer = g_byte_array_sized_new(RINGBUFFER_START_SIZE);
g_byte_array_append(file_info->buffer, curr_pos, (guint)(bytes_read - (curr_pos - magic_buf)));

View File

@ -277,7 +277,8 @@ nsfiletime_to_nstime(nstime_t *nstime, guint64 nsfiletime)
* parses a character string for a date and time given in
* ISO 8601 date-time format (eg: 2014-04-07T05:41:56.782+00:00)
* and converts to an nstime_t
* returns number of chars parsed on success, or 0 on failure
* returns pointer to the first character after the last character
* parsed on success, or NULL on failure
*
* NB. ISO 8601 is actually a lot more flexible than the above format,
* much to a developer's chagrin. The "basic format" is distinguished from
@ -299,7 +300,7 @@ nsfiletime_to_nstime(nstime_t *nstime, guint64 nsfiletime)
* YYYY-Www-D, YYYY-DDD, etc. For a relatively easy introduction to
* these formats, see wikipedia: https://en.wikipedia.org/wiki/ISO_8601
*/
guint8
const char *
iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
{
struct tm tm;
@ -308,8 +309,6 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
guint frac = 0;
gint off_hr = 0;
gint off_min = 0;
guint8 ret_val = 0;
const char *start = ptr;
char sign = '\0';
gboolean has_separator = FALSE;
gboolean have_offset = FALSE;
@ -322,7 +321,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
* separator. */
for (n_scanned = 0; n_scanned < 4; n_scanned++) {
if (!g_ascii_isdigit(*ptr)) {
return 0;
return NULL;
}
tm.tm_year *= 10;
tm.tm_year += *ptr++ - '0';
@ -330,7 +329,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
if (*ptr == '-') {
switch (format) {
case ISO8601_DATETIME_BASIC:
return 0;
return NULL;
case ISO8601_DATETIME:
case ISO8601_DATETIME_AUTO:
@ -341,7 +340,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
} else if (g_ascii_isdigit(*ptr)) {
switch (format) {
case ISO8601_DATETIME:
return 0;
return NULL;
case ISO8601_DATETIME_BASIC:
case ISO8601_DATETIME_AUTO:
@ -349,7 +348,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
has_separator = FALSE;
};
} else {
return 0;
return NULL;
}
tm.tm_year -= 1900; /* struct tm expects number of years since 1900 */
@ -375,7 +374,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
ptr += n_chars;
}
else {
return 0;
return NULL;
}
if (*ptr == 'T' || *ptr == ' ') {
@ -388,7 +387,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
/* Allow no separator between date and time iff we have no
separator between units. (Some extended formats may negotiate
no separator here, so this could be changed.) */
return 0;
return NULL;
}
/* Now we're on to the time part. We'll require a minimum of hours and
@ -403,7 +402,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
}
else {
/* didn't get hours and minutes */
return 0;
return NULL;
}
/* Test for (whole) seconds */
@ -413,7 +412,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
if (1 > sscanf(ptr, has_separator ? ":%2u%n" : "%2u%n",
&tm.tm_sec, &n_chars)) {
/* Couldn't get them */
return 0;
return NULL;
}
ptr += n_chars;
@ -453,7 +452,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
/* Validate what we got so far. mktime() doesn't care about strange
values but we should at least start with something valid */
if (!tm_is_valid(&tm)) {
return 0;
return NULL;
}
/* Check for a time zone offset */
@ -508,8 +507,7 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
nstime->secs = mktime(&tm);
}
nstime->nsecs = frac;
ret_val = (guint)(ptr-start);
return ret_val;
return ptr;
}
/*
@ -518,11 +516,12 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
* a floating point number containing a Unix epoch date-time
* format (e.g. 1600000000.000 for Sun Sep 13 05:26:40 AM PDT 2020)
* and converts to an nstime_t
* returns number of chars parsed on success, or 0 on failure
* returns pointer to the first character after the last character
* parsed on success, or NULL on failure
*
* Reference: https://en.wikipedia.org/wiki/Unix_time
*/
guint8
const char *
unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
{
gint64 secs;
@ -530,8 +529,6 @@ unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
gint n_chars = 0;
guint frac = 0;
guint8 ret_val = 0;
const char *start = ptr;
nstime_set_unset(nstime);
@ -540,18 +537,18 @@ unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
* might be 64-bit.
*/
if (!ws_strtoi64(ptr, &ptr_new, &secs)) {
return 0;
return NULL;
}
/* For now, reject times before the Epoch. */
if (secs < 0) {
return 0;
return NULL;
}
/* Make sure it fits. */
nstime->secs = (time_t) secs;
if (nstime->secs != secs) {
return 0;
return NULL;
}
/* Now let's test for fractional seconds */
@ -583,10 +580,7 @@ unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
frac = 0;
}
nstime->nsecs = frac;
/* return pointer shift */
ret_val = (guint)(ptr_new-start);
return ret_val;
return ptr_new;
}
size_t nstime_to_iso8601(char *buf, size_t buf_size, const nstime_t *nstime)

View File

@ -129,15 +129,15 @@ typedef enum {
ISO8601_DATETIME_AUTO, /** Autodetect the presence of separators */
} iso8601_fmt_e;
/** parse an ISO 8601 format datetime string to nstime, returns number of
chars parsed on success, 0 on failure.
/** parse an ISO 8601 format datetime string to nstime, returns pointer
to the first character after the last character, NULL on failure
Note that nstime is set to unset in the case of failure */
WS_DLL_PUBLIC guint8 iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format);
WS_DLL_PUBLIC const char * iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format);
/** parse an Unix epoch timestamp format datetime string to nstime, returns
number of chars parsed on success, 0 on failure.
pointer to the first character after the last character, NULL on failure
Note that nstime is set to unset in the case of failure */
WS_DLL_PUBLIC guint8 unix_epoch_to_nstime(nstime_t *nstime, const char *ptr);
WS_DLL_PUBLIC const char * unix_epoch_to_nstime(nstime_t *nstime, const char *ptr);
#define NSTIME_ISO8601_BUFSIZE sizeof("YYYY-MM-DDTHH:MM:SS.123456789Z")

View File

@ -576,7 +576,7 @@ static void test_int64_to_str_back(void)
void test_nstime_from_iso8601(void)
{
char *str;
size_t chars;
const char *endp;
nstime_t result, expect;
struct tm tm1;
@ -593,8 +593,9 @@ void test_nstime_from_iso8601(void)
str = "2013-05-30T23:45:25.349124";
expect.secs = mktime(&tm1);
expect.nsecs = 349124 * 1000;
chars = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_cmpuint(chars, ==, strlen(str));
endp = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_nonnull(endp);
g_assert(*endp == '\0');
g_assert_cmpint(result.secs, ==, expect.secs);
g_assert_cmpint(result.nsecs, ==, expect.nsecs);
@ -602,8 +603,9 @@ void test_nstime_from_iso8601(void)
str = "2013-05-30T23:45:25.349124Z";
expect.secs = mktime_utc(&tm1);
expect.nsecs = 349124 * 1000;
chars = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_cmpuint(chars, ==, strlen(str));
endp = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_nonnull(endp);
g_assert(*endp == '\0');
g_assert_cmpint(result.secs, ==, expect.secs);
g_assert_cmpint(result.nsecs, ==, expect.nsecs);
@ -611,8 +613,9 @@ void test_nstime_from_iso8601(void)
str = "2013-05-30T23:45:25.349124+01:00";
expect.secs = mktime_utc(&tm1) - 1 * 60 * 60;
expect.nsecs = 349124 * 1000;
chars = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_cmpuint(chars, ==, strlen(str));
endp = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_nonnull(endp);
g_assert(*endp == '\0');
g_assert_cmpint(result.secs, ==, expect.secs);
g_assert_cmpint(result.nsecs, ==, expect.nsecs);
@ -620,8 +623,9 @@ void test_nstime_from_iso8601(void)
str = "2013-05-30T23:45:25.349124+0100";
expect.secs = mktime_utc(&tm1) - 1 * 60 * 60;
expect.nsecs = 349124 * 1000;
chars = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_cmpuint(chars, ==, strlen(str));
endp = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_nonnull(endp);
g_assert(*endp == '\0');
g_assert_cmpint(result.secs, ==, expect.secs);
g_assert_cmpint(result.nsecs, ==, expect.nsecs);
@ -629,8 +633,9 @@ void test_nstime_from_iso8601(void)
str = "2013-05-30T23:45:25.349124+01";
expect.secs = mktime_utc(&tm1) - 1 * 60 * 60;
expect.nsecs = 349124 * 1000;
chars = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_cmpuint(chars, ==, strlen(str));
endp = iso8601_to_nstime(&result, str, ISO8601_DATETIME_AUTO);
g_assert_nonnull(endp);
g_assert(*endp == '\0');
g_assert_cmpint(result.secs, ==, expect.secs);
g_assert_cmpint(result.nsecs, ==, expect.nsecs);
}