+static inline void
+validate_single_byte_ascii_encoding(const guint encoding)
+{
+ const guint enc = encoding & ~ENC_STR_MASK;
+
+ switch (enc) {
+ case ENC_UTF_16:
+ case ENC_UCS_2:
+ case ENC_UCS_4:
+ case ENC_3GPP_TS_23_038_7BITS:
+ case ENC_EBCDIC:
+ REPORT_DISSECTOR_BUG("Invalid string encoding type passed to tvb_get_string_XXX");
+ break;
+ default:
+ break;
+ }
+ /* make sure something valid was set */
+ if (enc == 0)
+ REPORT_DISSECTOR_BUG("No string encoding type passed to tvb_get_string_XXX");
+}
+
+GByteArray*
+tvb_get_string_bytes(tvbuff_t *tvb, const gint offset, const gint length,
+ const guint encoding, GByteArray *bytes, gint *endoff)
+{
+ const gchar *ptr = (gchar*) tvb_get_raw_string(wmem_packet_scope(), tvb, offset, length);
+ const gchar *begin = ptr;
+ const gchar *end = NULL;
+ GByteArray *retval = NULL;
+
+ errno = EDOM;
+
+ validate_single_byte_ascii_encoding(encoding);
+
+ if (endoff) *endoff = 0;
+
+ while (*begin == ' ') begin++;
+
+ if (*begin && bytes) {
+ if (hex_str_to_bytes_encoding(begin, bytes, &end, encoding, FALSE)) {
+ if (bytes->len > 0) {
+ if (endoff) *endoff = offset + (gint)(end - ptr);
+ errno = 0;
+ retval = bytes;
+ }
+ }
+ }
+
+ return retval;
+}
+
+/* support hex-encoded time values? */
+nstime_t*
+tvb_get_string_time(tvbuff_t *tvb, const gint offset, const gint length,
+ const guint encoding, nstime_t *ns, gint *endoff)
+{
+ const gchar *begin = (gchar*) tvb_get_raw_string(wmem_packet_scope(), tvb, offset, length);
+ const gchar *ptr = begin;
+ const gchar *end = NULL;
+ struct tm tm;
+ nstime_t* retval = NULL;
+ char sign = '+';
+ int off_hr = 0;
+ int off_min = 0;
+ int num_chars = 0;
+ gboolean matched = FALSE;
+
+ errno = EDOM;
+
+ validate_single_byte_ascii_encoding(encoding);
+
+ DISSECTOR_ASSERT(ns);
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_isdst = -1;
+ ns->secs = 0;
+ ns->nsecs = 0;
+
+ while (*ptr == ' ') ptr++;
+
+ if (*ptr) {
+ /* note: sscanf is known to be inconsistent across platforms with respect
+ to whether a %n is counted as a return value or not, so we have to use
+ '>=' a lot */
+ if ((encoding & ENC_ISO_8601_DATE_TIME) == ENC_ISO_8601_DATE_TIME) {
+ /* TODO: using sscanf this many times is probably slow; might want
+ to parse it by hand in the future */
+ /* 2014-04-07T05:41:56+00:00 */
+ if (sscanf(ptr, "%d-%d-%d%*c%d:%d:%d%c%d:%d%n",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &tm.tm_hour,
+ &tm.tm_min,
+ &tm.tm_sec,
+ &sign,
+ &off_hr,
+ &off_min,
+ &num_chars) >= 9)
+ {
+ matched = TRUE;
+ }
+ /* no seconds is ok */
+ else if (sscanf(ptr, "%d-%d-%d%*c%d:%d%c%d:%d%n",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &tm.tm_hour,
+ &tm.tm_min,
+ &sign,
+ &off_hr,
+ &off_min,
+ &num_chars) >= 8)
+ {
+ matched = TRUE;
+ }
+ /* 2007-04-05T14:30:56Z */
+ else if (sscanf(ptr, "%d-%d-%d%*c%d:%d:%dZ%n",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &tm.tm_hour,
+ &tm.tm_min,
+ &tm.tm_sec,
+ &num_chars) >= 6)
+ {
+ matched = TRUE;
+ off_hr = 0;
+ off_min = 0;
+ }
+ /* 2007-04-05T14:30Z no seconds is ok */
+ else if (sscanf(ptr, "%d-%d-%d%*c%d:%dZ%n",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &tm.tm_hour,
+ &tm.tm_min,
+ &num_chars) >= 5)
+ {
+ matched = TRUE;
+ off_hr = 0;
+ off_min = 0;
+ }
+
+ if (matched) {
+ errno = 0;
+ end = ptr + num_chars;
+ tm.tm_mon--;
+ if (tm.tm_year > 1900) tm.tm_year -= 1900;
+ if (sign == '-') off_hr = -off_hr;
+ }
+ }
+ else if (encoding & ENC_ISO_8601_DATE) {
+ /* 2014-04-07 */
+ if (sscanf(ptr, "%d-%d-%d%n",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &num_chars) >= 3)
+ {
+ errno = 0;
+ end = ptr + num_chars;
+ tm.tm_mon--;
+ if (tm.tm_year > 1900) tm.tm_year -= 1900;
+ }
+ }
+ else if (encoding & ENC_ISO_8601_TIME) {
+ /* 2014-04-07 */
+ if (sscanf(ptr, "%d:%d:%d%n",
+ &tm.tm_hour,
+ &tm.tm_min,
+ &tm.tm_sec,
+ &num_chars) >= 2)
+ {
+ /* what should we do about day/month/year? */
+ /* setting it to "now" for now */
+ time_t time_now = time(NULL);
+ struct tm *tm_now = gmtime(&time_now);
+ tm.tm_year = tm_now->tm_year;
+ tm.tm_mon = tm_now->tm_mon;
+ tm.tm_mday = tm_now->tm_mday;
+ end = ptr + num_chars;
+ errno = 0;
+
+ }
+ }
+ else if (encoding & ENC_RFC_822 || encoding & ENC_RFC_1123) {
+ if (encoding & ENC_RFC_822) {
+ /* this will unfortunately match ENC_RFC_1123 style
+ strings too, partially - probably need to do this the long way */
+ end = strptime(ptr, "%a, %d %b %y %H:%M:%S", &tm);
+ if (!end) end = strptime(ptr, "%a, %d %b %y %H:%M", &tm);
+ if (!end) end = strptime(ptr, "%d %b %y %H:%M:%S", &tm);
+ if (!end) end = strptime(ptr, "%d %b %y %H:%M", &tm);
+ }
+ else if (encoding & ENC_RFC_1123) {
+ end = strptime(ptr, "%a, %d %b %Y %H:%M:%S", &tm);
+ if (!end) end = strptime(ptr, "%a, %d %b %Y %H:%M", &tm);
+ if (!end) end = strptime(ptr, "%d %b %Y %H:%M:%S", &tm);
+ if (!end) end = strptime(ptr, "%d %b %Y %H:%M", &tm);
+ }
+ if (end) {
+ errno = 0;
+ if (*end == ' ') end++;
+ if (g_ascii_strncasecmp(end, "UT", 2) == 0)
+ {
+ end += 2;
+ }
+ else if (g_ascii_strncasecmp(end, "GMT", 3) == 0)
+ {
+ end += 3;
+ }
+ else if (sscanf(end, "%c%2d%2d%n",
+ &sign,
+ &off_hr,
+ &off_min,
+ &num_chars) < 3)
+ {
+ errno = ERANGE;
+ }
+ if (sign == '-') off_hr = -off_hr;
+ }
+ }
+ }
+
+ if (errno == 0) {
+ ns->secs = mktime_utc (&tm);
+ if (off_hr > 0)
+ ns->secs += (off_hr * 3600) + (off_min * 60);
+ else if (off_hr < 0)
+ ns->secs -= ((-off_hr) * 3600) + (off_min * 60);
+ retval = ns;
+ if (endoff)
+ *endoff = (gint)(offset + (end - begin));
+ }
+
+ return retval;
+}
+