/epan/tvbuff.c
C | 3263 lines | 1938 code | 479 blank | 846 comment | 352 complexity | 646822b1306509f30d99c22c7c91629b MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /* tvbuff.c
- *
- * Testy, Virtual(-izable) Buffer of guint8*'s
- *
- * "Testy" -- the buffer gets mad when an attempt to access data
- * beyond the bounds of the buffer. An exception is thrown.
- *
- * "Virtual" -- the buffer can have its own data, can use a subset of
- * the data of a backing tvbuff, or can be a composite of
- * other tvbuffs.
- *
- * $Id$
- *
- * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
- *
- * Code to convert IEEE floating point formats to native floating point
- * derived from code Copyright (c) Ashok Narayanan, 2000
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include "config.h"
- #include <string.h>
- #ifdef HAVE_LIBZ
- #include <zlib.h>
- #endif
- #include "wsutil/pint.h"
- #include "tvbuff.h"
- #include "tvbuff-int.h"
- #include "strutil.h"
- #include "emem.h"
- #include "charsets.h"
- #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
- static guint64
- _tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits);
- tvbuff_t *
- tvb_new(const struct tvb_ops *ops)
- {
- tvbuff_t *tvb;
- gsize size = ops->tvb_size ? ops->tvb_size : sizeof(*tvb);
- g_assert(size >= sizeof(*tvb));
- tvb = (tvbuff_t *) g_slice_alloc(size);
- tvb->previous = NULL;
- tvb->next = NULL;
- tvb->ops = ops;
- tvb->initialized = FALSE;
- tvb->flags = 0;
- tvb->length = 0;
- tvb->reported_length = 0;
- tvb->real_data = NULL;
- tvb->raw_offset = -1;
- tvb->ds_tvb = NULL;
- return tvb;
- }
- static void
- tvb_free_internal(tvbuff_t *tvb)
- {
- gsize size;
- DISSECTOR_ASSERT(tvb);
- if (tvb->ops->tvb_free)
- tvb->ops->tvb_free(tvb);
- size = (tvb->ops->tvb_size) ? tvb->ops->tvb_size : sizeof(*tvb);
- g_slice_free1(size, tvb);
- }
- /* XXX: just call tvb_free_chain();
- * Not removed so that existing dissectors using tvb_free() need not be changed.
- * I'd argue that existing calls to tvb_free() should have actually beeen
- * calls to tvb_free_chain() although the calls were OK as long as no
- * subsets, etc had been created on the tvb. */
- void
- tvb_free(tvbuff_t *tvb)
- {
- tvb_free_chain(tvb);
- }
- void
- tvb_free_chain(tvbuff_t *tvb)
- {
- tvbuff_t *next_tvb;
- DISSECTOR_ASSERT(tvb);
- DISSECTOR_ASSERT_HINT(tvb->previous==NULL, "tvb_free_chain(): tvb must be initial tvb in chain");
- while (tvb) {
- next_tvb=tvb->next;
- DISSECTOR_ASSERT_HINT((next_tvb==NULL) || (tvb==next_tvb->previous), "tvb_free_chain(): corrupt tvb chain ?");
- tvb_free_internal(tvb);
- tvb = next_tvb;
- }
- }
- tvbuff_t *
- tvb_new_chain(tvbuff_t *parent, tvbuff_t *backing)
- {
- tvbuff_t *tvb = tvb_new_proxy(backing);
- tvb_add_to_chain(parent, tvb);
- return tvb;
- }
- void
- tvb_add_to_chain(tvbuff_t *parent, tvbuff_t *child)
- {
- DISSECTOR_ASSERT(parent);
- DISSECTOR_ASSERT(child);
- DISSECTOR_ASSERT(!child->next);
- DISSECTOR_ASSERT(!child->previous);
- child->next = parent->next;
- child->previous = parent;
- if (parent->next)
- parent->next->previous = child;
- parent->next = child;
- }
- /*
- * Check whether that offset goes more than one byte past the
- * end of the buffer.
- *
- * If not, return 0; otherwise, return exception
- */
- static inline int
- validate_offset(const tvbuff_t *tvb, const guint abs_offset)
- {
- int exception;
- if (G_LIKELY(abs_offset <= tvb->length))
- exception = 0;
- else if (abs_offset <= tvb->reported_length)
- exception = BoundsError;
- else {
- if (tvb->flags & TVBUFF_FRAGMENT)
- exception = FragmentBoundsError;
- else
- exception = ReportedBoundsError;
- }
- return exception;
- }
- static int
- compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
- {
- int exception;
- if (offset >= 0) {
- /* Positive offset - relative to the beginning of the packet. */
- if ((guint) offset > tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- exception = FragmentBoundsError;
- } else {
- exception = ReportedBoundsError;
- }
- return exception;
- }
- else if ((guint) offset > tvb->length) {
- return BoundsError;
- }
- else {
- *offset_ptr = offset;
- }
- }
- else {
- /* Negative offset - relative to the end of the packet. */
- if ((guint) -offset > tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- exception = FragmentBoundsError;
- } else {
- exception = ReportedBoundsError;
- }
- return exception;
- }
- else if ((guint) -offset > tvb->length) {
- return BoundsError;
- }
- else {
- *offset_ptr = tvb->length + offset;
- }
- }
- return 0;
- }
- static int
- compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offset_ptr, guint *rem_len)
- {
- int exception;
- exception = compute_offset(tvb, offset, offset_ptr);
- if (!exception)
- *rem_len = tvb->length - *offset_ptr;
- return exception;
- }
- /* Computes the absolute offset and length based on a possibly-negative offset
- * and a length that is possible -1 (which means "to the end of the data").
- * Returns integer indicating whether the offset is in bounds (0) or
- * not (exception number). The integer ptrs are modified with the new offset and length.
- * No exception is thrown.
- *
- * XXX - we return success (0), if the offset is positive and right
- * after the end of the tvbuff (i.e., equal to the length). We do this
- * so that a dissector constructing a subset tvbuff for the next protocol
- * will get a zero-length tvbuff, not an exception, if there's no data
- * left for the next protocol - we want the next protocol to be the one
- * that gets an exception, so the error is reported as an error in that
- * protocol rather than the containing protocol. */
- static int
- check_offset_length_no_exception(const tvbuff_t *tvb,
- const gint offset, gint const length_val,
- guint *offset_ptr, guint *length_ptr)
- {
- guint end_offset;
- int exception;
- DISSECTOR_ASSERT(offset_ptr);
- DISSECTOR_ASSERT(length_ptr);
- /* Compute the offset */
- exception = compute_offset(tvb, offset, offset_ptr);
- if (exception)
- return exception;
- if (length_val < -1) {
- /* XXX - ReportedBoundsError? */
- return BoundsError;
- }
- /* Compute the length */
- if (length_val == -1)
- *length_ptr = tvb->length - *offset_ptr;
- else
- *length_ptr = length_val;
- /*
- * Compute the offset of the first byte past the length.
- */
- end_offset = *offset_ptr + *length_ptr;
- /*
- * Check for an overflow
- */
- if (end_offset < *offset_ptr)
- exception = BoundsError;
- else
- exception = validate_offset(tvb, end_offset);
- return exception;
- }
- /* Checks (+/-) offset and length and throws an exception if
- * either is out of bounds. Sets integer ptrs to the new offset
- * and length. */
- static void
- check_offset_length(const tvbuff_t *tvb,
- const gint offset, gint const length_val,
- guint *offset_ptr, guint *length_ptr)
- {
- int exception;
- exception = check_offset_length_no_exception(tvb, offset, length_val, offset_ptr, length_ptr);
- if (exception)
- THROW(exception);
- }
- void
- tvb_check_offset_length(const tvbuff_t *tvb,
- const gint offset, gint const length_val,
- guint *offset_ptr, guint *length_ptr)
- {
- check_offset_length(tvb, offset, length_val, offset_ptr, length_ptr);
- }
- static const unsigned char left_aligned_bitmask[] = {
- 0xff,
- 0x80,
- 0xc0,
- 0xe0,
- 0xf0,
- 0xf8,
- 0xfc,
- 0xfe
- };
- tvbuff_t *
- tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
- {
- tvbuff_t *sub_tvb = NULL;
- guint32 byte_offset;
- gint32 datalen, i;
- guint8 left, right, remaining_bits, *buf;
- const guint8 *data;
- byte_offset = bit_offset >> 3;
- left = bit_offset % 8; /* for left-shifting */
- right = 8 - left; /* for right-shifting */
- if (no_of_bits == -1) {
- datalen = tvb_length_remaining(tvb, byte_offset);
- remaining_bits = 0;
- } else {
- datalen = no_of_bits >> 3;
- remaining_bits = no_of_bits % 8;
- if (remaining_bits) {
- datalen++;
- }
- }
- /* already aligned -> shortcut */
- if ((left == 0) && (remaining_bits == 0)) {
- return tvb_new_subset(tvb, byte_offset, datalen, -1);
- }
- DISSECTOR_ASSERT(datalen>0);
- /* if at least one trailing byte is available, we must use the content
- * of that byte for the last shift (i.e. tvb_get_ptr() must use datalen + 1
- * if non extra byte is available, the last shifted byte requires
- * special treatment
- */
- if (tvb_length_remaining(tvb, byte_offset) > datalen) {
- data = tvb_get_ptr(tvb, byte_offset, datalen + 1);
- /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */
- buf = (guint8 *)g_malloc(datalen);
- /* shift tvb data bit_offset bits to the left */
- for (i = 0; i < datalen; i++)
- buf[i] = (data[i] << left) | (data[i+1] >> right);
- } else {
- data = tvb_get_ptr(tvb, byte_offset, datalen);
- /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */
- buf = (guint8 *)g_malloc(datalen);
- /* shift tvb data bit_offset bits to the left */
- for (i = 0; i < (datalen-1); i++)
- buf[i] = (data[i] << left) | (data[i+1] >> right);
- buf[datalen-1] = data[datalen-1] << left; /* set last octet */
- }
- buf[datalen-1] &= left_aligned_bitmask[remaining_bits];
- sub_tvb = tvb_new_child_real_data(tvb, buf, datalen, datalen);
- tvb_set_free_cb(sub_tvb, g_free);
- return sub_tvb;
- }
- static tvbuff_t *
- tvb_generic_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
- {
- tvbuff_t *cloned_tvb;
- guint8 *data = (guint8 *) g_malloc(len);
- tvb_memcpy(tvb, data, offset, len);
- cloned_tvb = tvb_new_real_data(data, len, len);
- tvb_set_free_cb(cloned_tvb, g_free);
- return cloned_tvb;
- }
- tvbuff_t *
- tvb_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
- {
- if (tvb->ops->tvb_clone) {
- tvbuff_t *cloned_tvb;
- cloned_tvb = tvb->ops->tvb_clone(tvb, offset, len);
- if (cloned_tvb)
- return cloned_tvb;
- }
- return tvb_generic_clone_offset_len(tvb, offset, len);
- }
- tvbuff_t *
- tvb_clone(tvbuff_t *tvb)
- {
- return tvb_clone_offset_len(tvb, 0, tvb->length);
- }
- guint
- tvb_length(const tvbuff_t *tvb)
- {
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- return tvb->length;
- }
- gint
- tvb_length_remaining(const tvbuff_t *tvb, const gint offset)
- {
- guint abs_offset, rem_length;
- int exception;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
- if (exception)
- return -1;
- return rem_length;
- }
- guint
- tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset)
- {
- guint abs_offset, rem_length;
- int exception;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
- if (exception)
- THROW(exception);
- if (rem_length == 0) {
- /*
- * This routine ensures there's at least one byte available.
- * There aren't any bytes available, so throw the appropriate
- * exception.
- */
- if (abs_offset >= tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- } else
- THROW(BoundsError);
- }
- return rem_length;
- }
- /* Validates that 'length' bytes are available starting from
- * offset (pos/neg). Does not throw an exception. */
- gboolean
- tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length)
- {
- guint abs_offset, abs_length;
- int exception;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length);
- if (exception)
- return FALSE;
- return TRUE;
- }
- /* Validates that 'length' bytes are available starting from
- * offset (pos/neg). Throws an exception if they aren't. */
- void
- tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length)
- {
- guint abs_offset, abs_length;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- /*
- * -1 doesn't mean "until end of buffer", as that's pointless
- * for this routine. We must treat it as a Really Large Positive
- * Number, so that we throw an exception; we throw
- * ReportedBoundsError, as if it were past even the end of a
- * reassembled packet, and past the end of even the data we
- * didn't capture.
- *
- * We do the same with other negative lengths.
- */
- if (length < 0) {
- THROW(ReportedBoundsError);
- }
- check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
- }
- gboolean
- tvb_offset_exists(const tvbuff_t *tvb, const gint offset)
- {
- guint abs_offset;
- int exception;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- exception = compute_offset(tvb, offset, &abs_offset);
- if (exception)
- return FALSE;
- if (abs_offset < tvb->length) {
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
- guint
- tvb_reported_length(const tvbuff_t *tvb)
- {
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- return tvb->reported_length;
- }
- gint
- tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
- {
- guint abs_offset;
- int exception;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- exception = compute_offset(tvb, offset, &abs_offset);
- if (exception)
- return -1;
- if (tvb->reported_length >= abs_offset)
- return tvb->reported_length - abs_offset;
- else
- return -1;
- }
- /* Set the reported length of a tvbuff to a given value; used for protocols
- * whose headers contain an explicit length and where the calling
- * dissector's payload may include padding as well as the packet for
- * this protocol.
- * Also adjusts the data length. */
- void
- tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
- {
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- if (reported_length > tvb->reported_length)
- THROW(ReportedBoundsError);
- tvb->reported_length = reported_length;
- if (reported_length < tvb->length)
- tvb->length = reported_length;
- }
- #if 0
- static const guint8*
- first_real_data_ptr(tvbuff_t *tvb)
- {
- tvbuff_t *member;
- switch(tvb->type) {
- case TVBUFF_REAL_DATA:
- return tvb->real_data;
- case TVBUFF_SUBSET:
- member = tvb->tvbuffs.subset.tvb;
- return first_real_data_ptr(member);
- case TVBUFF_COMPOSITE:
- member = tvb->tvbuffs.composite.tvbs->data;
- return first_real_data_ptr(member);
- }
- DISSECTOR_ASSERT_NOT_REACHED();
- return NULL;
- }
- #endif
- guint
- tvb_offset_from_real_beginning_counter(const tvbuff_t *tvb, const guint counter)
- {
- if (tvb->ops->tvb_offset)
- return tvb->ops->tvb_offset(tvb, counter);
- DISSECTOR_ASSERT_NOT_REACHED();
- return 0;
- }
- guint
- tvb_offset_from_real_beginning(const tvbuff_t *tvb)
- {
- return tvb_offset_from_real_beginning_counter(tvb, 0);
- }
- static const guint8*
- ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint length, int *pexception)
- {
- guint abs_offset, abs_length;
- int exception;
- exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length);
- if (exception) {
- if (pexception)
- *pexception = exception;
- return NULL;
- }
- /*
- * We know that all the data is present in the tvbuff, so
- * no exceptions should be thrown.
- */
- if (tvb->real_data)
- return tvb->real_data + abs_offset;
- if (tvb->ops->tvb_get_ptr)
- return tvb->ops->tvb_get_ptr(tvb, abs_offset, abs_length);
- DISSECTOR_ASSERT_NOT_REACHED();
- return NULL;
- }
- static const guint8*
- ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length)
- {
- int exception = 0;
- const guint8 *p;
- p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
- if (p == NULL) {
- DISSECTOR_ASSERT(exception > 0);
- THROW(exception);
- }
- return p;
- }
- static const guint8*
- fast_ensure_contiguous(tvbuff_t *tvb, const gint offset, const guint length)
- {
- guint end_offset;
- guint u_offset;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- /* We don't check for overflow in this fast path so we only handle simple types */
- DISSECTOR_ASSERT(length <= 8);
- if (offset < 0 || !tvb->real_data) {
- return ensure_contiguous(tvb, offset, length);
- }
- u_offset = offset;
- end_offset = u_offset + length;
- if (end_offset <= tvb->length) {
- return tvb->real_data + u_offset;
- }
- if (end_offset > tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- /* not reached */
- }
- THROW(BoundsError);
- /* not reached */
- return NULL;
- }
- static const guint8*
- guint8_pbrk(const guint8* haystack, size_t haystacklen, const guint8 *needles, guchar *found_needle)
- {
- gchar tmp[256] = { 0 };
- const guint8 *haystack_end;
- while (*needles)
- tmp[*needles++] = 1;
- haystack_end = haystack + haystacklen;
- while (haystack < haystack_end) {
- if (tmp[*haystack]) {
- if (found_needle)
- *found_needle = *haystack;
- return haystack;
- }
- haystack++;
- }
- return NULL;
- }
- /************** ACCESSORS **************/
- void *
- tvb_memcpy(tvbuff_t *tvb, void *target, const gint offset, size_t length)
- {
- guint abs_offset, abs_length;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- /*
- * XXX - we should eliminate the "length = -1 means 'to the end
- * of the tvbuff'" convention, and use other means to achieve
- * that; this would let us eliminate a bunch of checks for
- * negative lengths in cases where the protocol has a 32-bit
- * length field.
- *
- * Allowing -1 but throwing an assertion on other negative
- * lengths is a bit more work with the length being a size_t;
- * instead, we check for a length <= 2^31-1.
- */
- DISSECTOR_ASSERT(length <= 0x7FFFFFFF);
- check_offset_length(tvb, offset, (gint) length, &abs_offset, &abs_length);
- if (tvb->real_data) {
- return memcpy(target, tvb->real_data + abs_offset, abs_length);
- }
- if (tvb->ops->tvb_memcpy)
- return tvb->ops->tvb_memcpy(tvb, target, abs_offset, abs_length);
- /* XXX, fallback to slower method */
- DISSECTOR_ASSERT_NOT_REACHED();
- return NULL;
- }
- /*
- * XXX - this doesn't treat a length of -1 as an error.
- * If it did, this could replace some code that calls
- * "tvb_ensure_bytes_exist()" and then allocates a buffer and copies
- * data to it.
- *
- * "composite_get_ptr()" depends on -1 not being
- * an error; does anything else depend on this routine treating -1 as
- * meaning "to the end of the buffer"?
- */
- void *
- tvb_memdup(tvbuff_t *tvb, const gint offset, size_t length)
- {
- guint abs_offset, abs_length;
- void *duped;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, (gint) length, &abs_offset, &abs_length);
- duped = g_malloc(abs_length);
- return tvb_memcpy(tvb, duped, abs_offset, abs_length);
- }
- /*
- * XXX - this doesn't treat a length of -1 as an error.
- * If it did, this could replace some code that calls
- * "tvb_ensure_bytes_exist()" and then allocates a buffer and copies
- * data to it.
- *
- * "composite_get_ptr()" depends on -1 not being
- * an error; does anything else depend on this routine treating -1 as
- * meaning "to the end of the buffer"?
- *
- * This function allocates memory from a buffer with packet lifetime.
- * You do not have to free this buffer, it will be automatically freed
- * when wireshark starts decoding the next packet.
- * Do not use this function if you want the allocated memory to be persistent
- * after the current packet has been dissected.
- */
- void *
- ep_tvb_memdup(tvbuff_t *tvb, const gint offset, size_t length)
- {
- guint abs_offset, abs_length;
- void *duped;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, (gint) length, &abs_offset, &abs_length);
- duped = ep_alloc(abs_length);
- return tvb_memcpy(tvb, duped, abs_offset, abs_length);
- }
- const guint8*
- tvb_get_ptr(tvbuff_t *tvb, const gint offset, const gint length)
- {
- return ensure_contiguous(tvb, offset, length);
- }
- /* ---------------- */
- guint8
- tvb_get_guint8(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint8));
- return *ptr;
- }
- guint16
- tvb_get_ntohs(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
- return pntohs(ptr);
- }
- guint32
- tvb_get_ntoh24(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 3);
- return pntoh24(ptr);
- }
- guint32
- tvb_get_ntohl(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
- return pntohl(ptr);
- }
- guint64
- tvb_get_ntoh40(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 5);
- return pntoh40(ptr);
- }
- guint64
- tvb_get_ntoh48(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 6);
- return pntoh48(ptr);
- }
- guint64
- tvb_get_ntoh56(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 7);
- return pntoh56(ptr);
- }
- guint64
- tvb_get_ntoh64(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
- return pntoh64(ptr);
- }
- /*
- * Stuff for IEEE float handling on platforms that don't have IEEE
- * format as the native floating-point format.
- *
- * For now, we treat only the VAX as such a platform.
- *
- * XXX - other non-IEEE boxes that can run UNIX include some Crays,
- * and possibly other machines.
- *
- * It appears that the official Linux port to System/390 and
- * zArchitecture uses IEEE format floating point (not a
- * huge surprise).
- *
- * I don't know whether there are any other machines that
- * could run Wireshark and that don't use IEEE format.
- * As far as I know, all of the main commercial microprocessor
- * families on which OSes that support Wireshark can run
- * use IEEE format (x86, 68k, SPARC, MIPS, PA-RISC, Alpha,
- * IA-64, and so on).
- */
- #if defined(vax)
- #include <math.h>
- /*
- * Single-precision.
- */
- #define IEEE_SP_NUMBER_WIDTH 32 /* bits in number */
- #define IEEE_SP_EXP_WIDTH 8 /* bits in exponent */
- #define IEEE_SP_MANTISSA_WIDTH 23 /* IEEE_SP_NUMBER_WIDTH - 1 - IEEE_SP_EXP_WIDTH */
- #define IEEE_SP_SIGN_MASK 0x80000000
- #define IEEE_SP_EXPONENT_MASK 0x7F800000
- #define IEEE_SP_MANTISSA_MASK 0x007FFFFF
- #define IEEE_SP_INFINITY IEEE_SP_EXPONENT_MASK
- #define IEEE_SP_IMPLIED_BIT (1 << IEEE_SP_MANTISSA_WIDTH)
- #define IEEE_SP_INFINITE ((1 << IEEE_SP_EXP_WIDTH) - 1)
- #define IEEE_SP_BIAS ((1 << (IEEE_SP_EXP_WIDTH - 1)) - 1)
- static int
- ieee_float_is_zero(const guint32 w)
- {
- return ((w & ~IEEE_SP_SIGN_MASK) == 0);
- }
- static gfloat
- get_ieee_float(const guint32 w)
- {
- long sign;
- long exponent;
- long mantissa;
- sign = w & IEEE_SP_SIGN_MASK;
- exponent = w & IEEE_SP_EXPONENT_MASK;
- mantissa = w & IEEE_SP_MANTISSA_MASK;
- if (ieee_float_is_zero(w)) {
- /* number is zero, unnormalized, or not-a-number */
- return 0.0;
- }
- #if 0
- /*
- * XXX - how to handle this?
- */
- if (IEEE_SP_INFINITY == exponent) {
- /*
- * number is positive or negative infinity, or a special value
- */
- return (sign? MINUS_INFINITY: PLUS_INFINITY);
- }
- #endif
- exponent = ((exponent >> IEEE_SP_MANTISSA_WIDTH) - IEEE_SP_BIAS) -
- IEEE_SP_MANTISSA_WIDTH;
- mantissa |= IEEE_SP_IMPLIED_BIT;
- if (sign)
- return -mantissa * pow(2, exponent);
- else
- return mantissa * pow(2, exponent);
- }
- /*
- * Double-precision.
- * We assume that if you don't have IEEE floating-point, you have a
- * compiler that understands 64-bit integral quantities.
- */
- #define IEEE_DP_NUMBER_WIDTH 64 /* bits in number */
- #define IEEE_DP_EXP_WIDTH 11 /* bits in exponent */
- #define IEEE_DP_MANTISSA_WIDTH 52 /* IEEE_DP_NUMBER_WIDTH - 1 - IEEE_DP_EXP_WIDTH */
- #define IEEE_DP_SIGN_MASK 0x8000000000000000LL
- #define IEEE_DP_EXPONENT_MASK 0x7FF0000000000000LL
- #define IEEE_DP_MANTISSA_MASK 0x000FFFFFFFFFFFFFLL
- #define IEEE_DP_INFINITY IEEE_DP_EXPONENT_MASK
- #define IEEE_DP_IMPLIED_BIT (1LL << IEEE_DP_MANTISSA_WIDTH)
- #define IEEE_DP_INFINITE ((1 << IEEE_DP_EXP_WIDTH) - 1)
- #define IEEE_DP_BIAS ((1 << (IEEE_DP_EXP_WIDTH - 1)) - 1)
- static int
- ieee_double_is_zero(const guint64 w)
- {
- return ((w & ~IEEE_SP_SIGN_MASK) == 0);
- }
- static gdouble
- get_ieee_double(const guint64 w)
- {
- gint64 sign;
- gint64 exponent;
- gint64 mantissa;
- sign = w & IEEE_DP_SIGN_MASK;
- exponent = w & IEEE_DP_EXPONENT_MASK;
- mantissa = w & IEEE_DP_MANTISSA_MASK;
- if (ieee_double_is_zero(w)) {
- /* number is zero, unnormalized, or not-a-number */
- return 0.0;
- }
- #if 0
- /*
- * XXX - how to handle this?
- */
- if (IEEE_DP_INFINITY == exponent) {
- /*
- * number is positive or negative infinity, or a special value
- */
- return (sign? MINUS_INFINITY: PLUS_INFINITY);
- }
- #endif
- exponent = ((exponent >> IEEE_DP_MANTISSA_WIDTH) - IEEE_DP_BIAS) -
- IEEE_DP_MANTISSA_WIDTH;
- mantissa |= IEEE_DP_IMPLIED_BIT;
- if (sign)
- return -mantissa * pow(2, exponent);
- else
- return mantissa * pow(2, exponent);
- }
- #endif
- /*
- * Fetches an IEEE single-precision floating-point number, in
- * big-endian form, and returns a "float".
- *
- * XXX - should this be "double", in case there are IEEE single-
- * precision numbers that won't fit in some platform's native
- * "float" format?
- */
- gfloat
- tvb_get_ntohieee_float(tvbuff_t *tvb, const int offset)
- {
- #if defined(vax)
- return get_ieee_float(tvb_get_ntohl(tvb, offset));
- #else
- union {
- gfloat f;
- guint32 w;
- } ieee_fp_union;
- ieee_fp_union.w = tvb_get_ntohl(tvb, offset);
- return ieee_fp_union.f;
- #endif
- }
- /*
- * Fetches an IEEE double-precision floating-point number, in
- * big-endian form, and returns a "double".
- */
- gdouble
- tvb_get_ntohieee_double(tvbuff_t *tvb, const int offset)
- {
- #if defined(vax)
- union {
- guint32 w[2];
- guint64 dw;
- } ieee_fp_union;
- #else
- union {
- gdouble d;
- guint32 w[2];
- } ieee_fp_union;
- #endif
- #ifdef WORDS_BIGENDIAN
- ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset);
- ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset+4);
- #else
- ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset+4);
- ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset);
- #endif
- #if defined(vax)
- return get_ieee_double(ieee_fp_union.dw);
- #else
- return ieee_fp_union.d;
- #endif
- }
- guint16
- tvb_get_letohs(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
- return pletohs(ptr);
- }
- guint32
- tvb_get_letoh24(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 3);
- return pletoh24(ptr);
- }
- guint32
- tvb_get_letohl(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
- return pletohl(ptr);
- }
- guint64
- tvb_get_letoh40(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 5);
- return pletoh40(ptr);
- }
- guint64
- tvb_get_letoh48(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 6);
- return pletoh48(ptr);
- }
- guint64
- tvb_get_letoh56(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, 7);
- return pletoh56(ptr);
- }
- guint64
- tvb_get_letoh64(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
- return pletoh64(ptr);
- }
- /*
- * Fetches an IEEE single-precision floating-point number, in
- * little-endian form, and returns a "float".
- *
- * XXX - should this be "double", in case there are IEEE single-
- * precision numbers that won't fit in some platform's native
- * "float" format?
- */
- gfloat
- tvb_get_letohieee_float(tvbuff_t *tvb, const int offset)
- {
- #if defined(vax)
- return get_ieee_float(tvb_get_letohl(tvb, offset));
- #else
- union {
- gfloat f;
- guint32 w;
- } ieee_fp_union;
- ieee_fp_union.w = tvb_get_letohl(tvb, offset);
- return ieee_fp_union.f;
- #endif
- }
- /*
- * Fetches an IEEE double-precision floating-point number, in
- * little-endian form, and returns a "double".
- */
- gdouble
- tvb_get_letohieee_double(tvbuff_t *tvb, const int offset)
- {
- #if defined(vax)
- union {
- guint32 w[2];
- guint64 dw;
- } ieee_fp_union;
- #else
- union {
- gdouble d;
- guint32 w[2];
- } ieee_fp_union;
- #endif
- #ifdef WORDS_BIGENDIAN
- ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset+4);
- ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset);
- #else
- ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset);
- ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset+4);
- #endif
- #if defined(vax)
- return get_ieee_double(ieee_fp_union.dw);
- #else
- return ieee_fp_union.d;
- #endif
- }
- /* Fetch an IPv4 address, in network byte order.
- * We do *not* convert them to host byte order; we leave them in
- * network byte order. */
- guint32
- tvb_get_ipv4(tvbuff_t *tvb, const gint offset)
- {
- const guint8 *ptr;
- guint32 addr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
- memcpy(&addr, ptr, sizeof addr);
- return addr;
- }
- /* Fetch an IPv6 address. */
- void
- tvb_get_ipv6(tvbuff_t *tvb, const gint offset, struct e_in6_addr *addr)
- {
- const guint8 *ptr;
- ptr = ensure_contiguous(tvb, offset, sizeof(*addr));
- memcpy(addr, ptr, sizeof *addr);
- }
- /* Fetch a GUID. */
- void
- tvb_get_ntohguid(tvbuff_t *tvb, const gint offset, e_guid_t *guid)
- {
- ensure_contiguous(tvb, offset, sizeof(*guid));
- guid->data1 = tvb_get_ntohl(tvb, offset);
- guid->data2 = tvb_get_ntohs(tvb, offset + 4);
- guid->data3 = tvb_get_ntohs(tvb, offset + 6);
- tvb_memcpy(tvb, guid->data4, offset + 8, sizeof guid->data4);
- }
- void
- tvb_get_letohguid(tvbuff_t *tvb, const gint offset, e_guid_t *guid)
- {
- ensure_contiguous(tvb, offset, sizeof(*guid));
- guid->data1 = tvb_get_letohl(tvb, offset);
- guid->data2 = tvb_get_letohs(tvb, offset + 4);
- guid->data3 = tvb_get_letohs(tvb, offset + 6);
- tvb_memcpy(tvb, guid->data4, offset + 8, sizeof guid->data4);
- }
- /*
- * NOTE: to support code written when proto_tree_add_item() took a
- * gboolean as its last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", we treat any non-zero value of
- * "representation" as meaning "little-endian".
- */
- void
- tvb_get_guid(tvbuff_t *tvb, const gint offset, e_guid_t *guid, const guint representation)
- {
- if (representation) {
- tvb_get_letohguid(tvb, offset, guid);
- } else {
- tvb_get_ntohguid(tvb, offset, guid);
- }
- }
- static const guint8 inverse_bit_mask8[] = {
- 0xff,
- 0x7f,
- 0x3f,
- 0x1f,
- 0x0f,
- 0x07,
- 0x03,
- 0x01
- };
- static const guint8 bit_mask8[] = {
- 0x00,
- 0x01,
- 0x03,
- 0x07,
- 0x0f,
- 0x1f,
- 0x3f,
- 0x7f,
- 0xff
- };
- /* Get 1 - 8 bits */
- guint8
- tvb_get_bits8(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits)
- {
- return (guint8)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
- }
- /* Get 1 - 16 bits */
- void
- tvb_get_bits_buf(tvbuff_t *tvb, guint bit_offset, gint no_of_bits, guint8 *buf, gboolean lsb0)
- {
- guint8 bit_mask, bit_shift;
- /* Byte align offset */
- gint offset = bit_offset >> 3;
- bit_offset = bit_offset & 0x7;
- bit_mask = (lsb0) ? 0xff : inverse_bit_mask8[bit_offset];
- bit_shift = (lsb0) ? bit_offset : (8 - bit_offset);
- if (G_LIKELY(bit_offset != 0)) {
- guint16 value = (guint16) tvb_get_guint8(tvb, offset);
- while (no_of_bits >= 8) {
- offset++;
- value = ((value & bit_mask) << 8) | tvb_get_guint8(tvb, offset);
- if (lsb0)
- *buf++ = (guint8) (GUINT16_SWAP_LE_BE(value) >> bit_shift);
- else
- *buf++ = (guint8) (value >> bit_shift);
- no_of_bits -= 8;
- }
- /* something left? */
- if (no_of_bits > 0) {
- guint8 tot_no_bits = bit_offset+no_of_bits;
- /* Overlaps with next byte? Get next byte */
- if (tot_no_bits > 8) {
- offset++;
- value = ((value & bit_mask) << 8) | tvb_get_guint8(tvb, offset);
- }
- if (lsb0) {
- if (tot_no_bits > 8)
- value = (GUINT16_SWAP_LE_BE(value) >> bit_offset) & (bit_mask8[no_of_bits]);
- else
- value = (value >> bit_offset) & (bit_mask8[no_of_bits]);
- /* value = (value & ((1 << tot_no_bits)-1)) >> bit_offset; */
- } else {
- if (tot_no_bits > 8)
- value = value >> (16 - tot_no_bits);
- else
- value = (value & bit_mask) >> (8-tot_no_bits);
- }
- *buf = (guint8) value;
- }
- } else {
- /* fast code path for bit_offset == 0 */
- while (no_of_bits >= 8) {
- *buf++ = tvb_get_guint8(tvb, offset);
- offset++;
- no_of_bits -= 8;
- }
- /* something left? */
- if (no_of_bits > 0) {
- if (lsb0)
- *buf = tvb_get_guint8(tvb, offset) & bit_mask8[no_of_bits]; /* read: ((1 << no_of_bits)-1) */
- else
- *buf = tvb_get_guint8(tvb, offset) >> (8-no_of_bits);
- }
- }
- }
- guint8 *
- ep_tvb_get_bits(tvbuff_t *tvb, guint bit_offset, gint no_of_bits, gboolean lsb0)
- {
- gint no_of_bytes;
- guint8 *buf;
- /* XXX, no_of_bits == -1 -> to end of tvb? */
- if (no_of_bits < 0) {
- DISSECTOR_ASSERT_NOT_REACHED();
- }
- no_of_bytes = (no_of_bits >> 3) + ((no_of_bits & 0x7) != 0); /* ceil(no_of_bits / 8.0) */
- buf = (guint8 *)ep_alloc(no_of_bytes);
- tvb_get_bits_buf(tvb, bit_offset, no_of_bits, buf, lsb0);
- return buf;
- }
- /* Get 9 - 16 bits */
- guint16
- tvb_get_bits16(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits,const guint encoding _U_)
- {
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint16)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
- }
- /* Get 1 - 32 bits */
- guint32
- tvb_get_bits32(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding _U_)
- {
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint32)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
- }
- /* Get 1 - 64 bits */
- guint64
- tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding _U_)
- {
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return _tvb_get_bits64(tvb, bit_offset, no_of_bits);
- }
- /*
- * This function will dissect a sequence of bits that does not need to be byte aligned; the bits
- * set will be shown in the tree as ..10 10.. and the integer value returned if return_value is set.
- * Offset should be given in bits from the start of the tvb.
- * The function tolerates requests for more than 64 bits, but will only return the least significant 64 bits.
- */
- static guint64
- _tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits)
- {
- guint64 value;
- guint octet_offset = bit_offset >> 3;
- guint8 required_bits_in_first_octet = 8 - (bit_offset % 8);
- if(required_bits_in_first_octet > total_no_of_bits)
- {
- /* the required bits don't extend to the end of the first octet */
- guint8 right_shift = required_bits_in_first_octet - total_no_of_bits;
- value = (tvb_get_guint8(tvb, octet_offset) >> right_shift) & bit_mask8[total_no_of_bits % 8];
- }
- else
- {
- guint8 remaining_bit_length = total_no_of_bits;
- /* get the bits up to the first octet boundary */
- value = 0;
- required_bits_in_first_octet %= 8;
- if(required_bits_in_first_octet != 0)
- {
- value = tvb_get_guint8(tvb, octet_offset) & bit_mask8[required_bits_in_first_octet];
- remaining_bit_length -= required_bits_in_first_octet;
- octet_offset ++;
- }
- /* take the biggest words, shorts or octets that we can */
- while (remaining_bit_length > 7)
- {
- switch (remaining_bit_length >> 4)
- {
- case 0:
- /* 8 - 15 bits. (note that 0 - 7 would have dropped out of the while() loop) */
- value <<= 8;
- value += tvb_get_guint8(tvb, octet_offset);
- remaining_bit_length -= 8;
- octet_offset ++;
- break;
- case 1:
- /* 16 - 31 bits */
- value <<= 16;
- value += tvb_get_ntohs(tvb, octet_offset);
- remaining_bit_length -= 16;
- octet_offset += 2;
- break;
- case 2:
- case 3:
- /* 32 - 63 bits */
- value <<= 32;
- value += tvb_get_ntohl(tvb, octet_offset);
- remaining_bit_length -= 32;
- octet_offset += 4;
- break;
- default:
- /* 64 bits (or more???) */
- value = tvb_get_ntoh64(tvb, octet_offset);
- remaining_bit_length -= 64;
- octet_offset += 8;
- break;
- }
- }
- /* get bits from any partial octet at the tail */
- if(remaining_bit_length)
- {
- value <<= remaining_bit_length;
- value += (tvb_get_guint8(tvb, octet_offset) >> (8 - remaining_bit_length));
- }
- }
- return value;
- }
- /* Get 1 - 32 bits (should be deprecated as same as tvb_get_bits32??) */
- guint32
- tvb_get_bits(tvbuff_t *tvb, const guint bit_offset, const gint no_of_bits, const guint encoding _U_)
- {
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint32)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
- }
- static gint
- tvb_find_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
- {
- const guint8 *ptr;
- const guint8 *result;
- ptr = tvb_get_ptr(tvb, abs_offset, limit);
- result = (const guint8 *) memchr(ptr, needle, limit);
- if (!result)
- return -1;
- return (gint) ((result - ptr) + abs_offset);
- }
- /* Find first occurrence of needle in tvbuff, starting at offset. Searches
- * at most maxlength number of bytes; if maxlength is -1, searches to
- * end of tvbuff.
- * Returns the offset of the found needle, or -1 if not found.
- * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
- * in that case, -1 will be returned if the boundary is reached before
- * finding needle. */
- gint
- tvb_find_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 needle)
- {
- const guint8 *result;
- guint abs_offset;
- guint tvbufflen;
- guint limit;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen);
- /* Only search to end of tvbuff, w/o throwing exception. */
- if (maxlength == -1) {
- /* No maximum length specified; search to end of tvbuff. */
- limit = tvbufflen;
- }
- else if (tvbufflen < (guint) maxlength) {
- /* Maximum length goes past end of tvbuff; search to end
- of tvbuff. */
- limit = tvbufflen;
- }
- else {
- /* Maximum length doesn't go past end of tvbuff; search
- to that value. */
- limit = maxlength;
- }
- /* If we have real data, perform our search now. */
- if (tvb->real_data) {
- result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
- if (result == NULL) {
- return -1;
- }
- else {
- return (gint) (result - tvb->real_data);
- }
- }
- if (tvb->ops->tvb_find_guint8)
- return tvb->ops->tvb_find_guint8(tvb, abs_offset, limit, needle);
- return tvb_find_guint8_generic(tvb, offset, limit, needle);
- }
- static gint
- tvb_pbrk_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
- {
- const guint8 *ptr;
- const guint8 *result;
- ptr = tvb_get_ptr(tvb, abs_offset, limit);
- result = guint8_pbrk(ptr, limit, needles, found_needle);
- if (!result)
- return -1;
- return (gint) ((result - ptr) + abs_offset);
- }
- /* Find first occurrence of any of the needles in tvbuff, starting at offset.
- * Searches at most maxlength number of bytes; if maxlength is -1, searches
- * to end of tvbuff.
- * Returns the offset of the found needle, or -1 if not found.
- * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
- * in that case, -1 will be returned if the boundary is reached before
- * finding needle. */
- gint
- tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 *needles, guchar *found_needle)
- {
- const guint8 *result;
- guint abs_offset;
- guint tvbufflen;
- guint limit;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen);
- /* Only search to end of tvbuff, w/o throwing exception. */
- if (maxlength == -1) {
- /* No maximum length specified; search to end of tvbuff. */
- limit = tvbufflen;
- }
- else if (tvbufflen < (guint) maxlength) {
- /* Maximum length goes past end of tvbuff; search to end
- of tvbuff. */
- limit = tvbufflen;
- }
- else {
- /* Maximum length doesn't go past end of tvbuff; search
- to that value. */
- limit = maxlength;
- }
- /* If we have real data, perform our search now. */
- if (tvb->real_data) {
- result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles, found_needle);
- if (result == NULL) {
- return -1;
- }
- else {
- return (gint) (result - tvb->real_data);
- }
- }
- if (tvb->ops->tvb_pbrk_guint8)
- return tvb->ops->tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle);
- return tvb_pbrk_guint8_generic(tvb, abs_offset, limit, needles, found_needle);
- }
- /* Find size of stringz (NUL-terminated string) by looking for terminating
- * NUL. The size of the string includes the terminating NUL.
- *
- * If the NUL isn't found, it throws the appropriate exception.
- */
- guint
- tvb_strsize(tvbuff_t *tvb, const gint offset)
- {
- guint abs_offset, junk_length;
- gint nul_offset;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
- nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
- if (nul_offset == -1) {
- /*
- * OK, we hit the end of the tvbuff, so we should throw
- * an exception.
- *
- * Did we hit the end of the captured data, or the end
- * of the actual data? If there's less captured data
- * than actual data, we presumably hit the end of the
- * captured data, otherwise we hit the end of the actual
- * data.
- */
- if (tvb->length < tvb->reported_length) {
- THROW(BoundsError);
- } else {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- }
- }
- return (nul_offset - abs_offset) + 1;
- }
- /* UTF-16/UCS-2 version of tvb_strsize */
- /* Returns number of bytes including the (two-bytes) null terminator */
- guint
- tvb_unicode_strsize(tvbuff_t *tvb, const gint offset)
- {
- guint i = 0;
- gunichar2 uchar;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- do {
- /* Endianness doesn't matter when looking for null */
- uchar = tvb_get_ntohs(tvb, offset + i);
- i += 2;
- } while(uchar != 0);
- return i;
- }
- /* Find length of string by looking for end of string ('\0'), up to
- * 'maxlength' characters'; if 'maxlength' is -1, searches to end
- * of tvbuff.
- * Returns -1 if 'maxlength' reached before finding EOS. */
- gint
- tvb_strnlen(tvbuff_t *tvb, const gint offset, const guint maxlength)
- {
- gint result_offset;
- guint abs_offset, junk_length;
- DISSECTOR_ASSERT(tvb && tvb->initialized);
- check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
- result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
- if (result_offset == -1) {
- return -1;
- }
- else {
- return result_offset - abs_offset;
- }
- }
- /*
- * Implement strneql etc
- */
- /*
- * Call strncmp after checking if enough chars left, returning 0 if
- * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
- */
- gint
- tvb_strneql(tvbuff_t *tvb, const gint offset, const gchar *str, const size_t size)
- {
- const guint8 *ptr;
- ptr = ensure_contiguous_no_exception(tvb, offset, (gint)size, NULL);
- if (ptr) {
- int cmp = strncmp((const char *)ptr, str, size);
- /*
- * Return 0 if equal, -1 otherwise.
- */
- return (cmp == 0 ? 0 : -1);
- } else {
- /*
- * Not enough characters in the tvbuff to match the
- * string.
- */
- return -1;
- }
- }
- /*
- * Call g_ascii_strncasecmp after checking if enough chars left, returning
- * 0 if it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
- */
- gint
- tvb_strncaseeql(tvbuff_t *tvb, const gint offset, const gchar *str, const size_t size)
- {
- const guint8 *ptr;
- ptr = ensure_contiguous_no_exception(tvb, offset, (gint)size, NULL);
- if (ptr) {
- int cmp = g_ascii_strncasecmp((const char *)ptr, str, size);
- /*
- * Return 0 if equal, -1 otherwise.
- */
- return (cmp == 0 ? 0 : -1);
- } else {
- /*
- * Not enough characters in the tvbuff to match the
- * string.
- */
- return -1;
- }
- }
- /*
- * Call memcmp after checking if enough chars left, returning 0 if
- * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
- */
- gint
- tvb_memeql(tvbuff_t *tvb, const gint offset, const guint8 *str, size_t size)
- {
- const guint8 *ptr;
- ptr = ensure_contiguous_no_exception(tvb, offset, (gint) size, NULL);
- if (ptr) {
- int cmp = memcmp(ptr, str, size);
- /*
- * Return 0 if equal, -1 otherwise.
- */
- return (cmp == 0 ? 0 : -1);
- } else {
- /*
- * Not enough characters in the tvbuff to match the
- * string.
- */
- return -1;
- }
- }
- /* Convert a string from Unicode to ASCII. At the moment we fake it by
- * replacing all non-ASCII characters with a '.' )-: The caller must
- * free the result returned. The len parameter is the number of guint16's
- * to convert from Unicode. */
- /* XXX - this function has been superceded by tvb_get_unicode_string() */
- char *
- tvb_fake_unicode(tvbuff_t *tvb, int offset, const int len, const gboolean little_endian)
- {
- char *buffer;
- int i;
- guint16 character;
- /* Make sure we have enough data before allocating the buffer,
- so we don't blow up if the length is huge. */
- tvb_ensure_bytes_exist(tvb, offset, 2*len);
- /* We know we won't throw an exception, so we don't have to worry
- about leaking this buffer. */
- buffer = (char *)g_malloc(len + 1);
- for (i = 0; i < len; i++) {
- character = little_endian ? tvb_get_letohs(tvb, offset)
- : tvb_get_ntohs(tvb, offset);
- buffer[i] = character < 256 ? character : '.';
- offset += 2;
- }
- buffer[len] = 0;
- return buffer;
- }
- /* Convert a string from Unicode to ASCII. At the moment we fake it by
- * replacing all non-ASCII characters with a '.' )-: The len parameter is
- * the number of guint16's to convert from Unicode.
- *
- * This function allocates memory from a buffer with packet lifetime.
- * You do not have to free this buffer, it will be automatically freed
- * when wireshark starts decoding the next packet.
- */
- /* XXX: This has been replaced by tvb_get_ephemeral_unicode_string() */
- char *
- tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, const int len, const gboolean little_endian)
- {
- char *buffer;
- int i;
- guint16 character;
- /* Make sure we have enough data before allocating the buffer,
- so we don't blow up if the length is huge. */
- tvb_ensure_bytes_exist(tvb, offset, 2*len);
- /* We know we won't throw an exception, so we don't have to worry
- about leaking this buffer. */
- buffer = (char *)ep_alloc(len + 1);
- for (i = 0; i < len; i++) {
- character = little_endian ? tvb_get_letohs(tvb, offset)
- : tvb_get_ntohs(tvb, offset);
- buffer[i] = character < 256 ? character : '.';
- offset += 2;
- }
- buffer[len] = 0;
- return buffer;
- }
- /*
- * Format the data in the tvb from offset for length ...
- */
- gchar *
- tvb_format_text(tvbuff_t *tvb, const gint offset, const gint size)
- {
- const guint8 *ptr;
- gint len;
- len = (size > 0) ? size : 0;
- if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
- len = tvb_length_remaining(tvb, offset);
- ptr = ensure_contiguous(tvb, offset, len);
- }
- return format_text(ptr, len);
- }
- /*
- * Format the data in the tvb from offset for length ...
- */
- gchar *
- tvb_format_text_wsp(tvbuff_t *tvb, const gint offset, const gint size)
- {
- const guint8 *ptr;
- gint len;
- len = (size > 0) ? size : 0;
- if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
- len = tvb_length_remaining(tvb, offset);
- ptr = ensure_contiguous(tvb, offset, len);
- }
- return format_text_wsp(ptr, len);
- }
- /*
- * Like "tvb_format_text()", but for null-padded strings; don't show
- * the null padding characters as "\000".
- */
- gchar *
- tvb_format_stringzpad(tvbuff_t *tvb, const gint offset, const gint size)
- {
- const guint8 *ptr, *p;
- gint len;
- gint stringlen;
- len = (size > 0) ? size : 0;
- if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
- len = tvb_length_remaining(tvb, offset);
- ptr = ensure_contiguous(tvb, offset, len);
- }
- for (p = ptr, stringlen = 0; stringlen < len && *p != '\0'; p++, stringlen++)
- ;
- return format_text(ptr, stringlen);
- }
- /*
- * Like "tvb_format_text_wsp()", but for null-padded strings; don't show
- * the null padding characters as "\000".
- */
- gchar *
- tvb_format_stringzpad_wsp(tvbuff_t *tvb, const gint offset, const gint size)
- {
- const guint8 *ptr, *p;
- gint len;
- gint stringlen;
- len = (size > 0) ? size : 0;
- if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
- len = tvb_length_remaining(tvb, offset);
- ptr = ensure_contiguous(tvb, offset, len);
- }
- for (p = ptr, stringlen = 0; stringlen < len && *p != '\0'; p++, stringlen++)
- ;
- return format_text_wsp(ptr, stringlen);
- }
- /*
- * Given a tvbuff, an offset, and a length, allocate a buffer big enough
- * to hold a non-null-terminated string of that length at that offset,
- * plus a trailing '\0', copy the string into it, and return a pointer
- * to the string.
- *
- * Throws an exception if the tvbuff ends before the string does.
- */
- guint8 *
- tvb_get_string(tvbuff_t *tvb, const gint offset, const gint length)
- {
- const guint8 *ptr;
- guint8 *strbuf = NULL;
- tvb_ensure_bytes_exist(tvb, offset, length);
- ptr = ensure_contiguous(tvb, offset, length);
- strbuf = (guint8 *)g_malloc(length + 1);
- if (length != 0) {
- memcpy(strbuf, ptr, length);
- }
- strbuf[length] = '\0';
- return strbuf;
- }
- /*
- * Unicode (UTF-16) version of tvb_get_string()
- * XXX - this is UCS-2, not UTF-16, as it doesn't handle surrogate pairs
- *
- * Encoding paramter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN
- *
- * Specify length in bytes
- *
- * Returns an UTF-8 string that must be freed by the caller
- */
- gchar *
- tvb_get_unicode_string(tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
- {
- gunichar2 uchar;
- gint i; /* Byte counter for tvbuff */
- GString *strbuf = NULL;
- tvb_ensure_bytes_exist(tvb, offset, length);
- strbuf = g_string_new(NULL);
- for(i = 0; i < length; i += 2) {
- if (encoding == ENC_BIG_ENDIAN)
- uchar = tvb_get_ntohs(tvb, offset + i);
- else
- uchar = tvb_get_letohs(tvb, offset + i);
- g_string_append_unichar(strbuf, uchar);
- }
- return g_string_free(strbuf, FALSE);
- }
- /*
- * Given a tvbuff, an offset, a length, and an encoding, allocate a
- * buffer big enoug…
Large files files are truncated, but you can click here to view the full file