wireshark/epan/tvbuff_subset.c

283 lines
7.6 KiB
C

/* tvbuff_subset.c
*
* Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include "tvbuff.h"
#include "tvbuff-int.h"
#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
#include "exceptions.h"
typedef struct {
/** The backing tvbuff_t */
struct tvbuff *tvb;
/** The offset of 'tvb' to which I'm privy */
guint offset;
/** The length of 'tvb' to which I'm privy */
guint length;
} tvb_backing_t;
struct tvb_subset {
struct tvbuff tvb;
tvb_backing_t subset;
};
static guint
subset_offset(const tvbuff_t *tvb, const guint counter)
{
const struct tvb_subset *subset_tvb = (const struct tvb_subset *) tvb;
const tvbuff_t *member = subset_tvb->subset.tvb;
return tvb_offset_from_real_beginning_counter(member, counter + subset_tvb->subset.offset);
}
static void *
subset_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
{
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
return tvb_memcpy(subset_tvb->subset.tvb, target, subset_tvb->subset.offset + abs_offset, abs_length);
}
static const guint8 *
subset_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
{
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
return tvb_get_ptr(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
}
static gint
subset_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
{
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
gint result;
result = tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
if (result == -1)
return result;
/*
* Make the result relative to the beginning of the tvbuff we
* were handed, *not* relative to the beginning of its parent
* tvbuff.
*/
return result - subset_tvb->subset.offset;
}
static gint
subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
{
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
gint result;
result = tvb_ws_mempbrk_pattern_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, pattern, found_needle);
if (result == -1)
return result;
/*
* Make the result relative to the beginning of the tvbuff we
* were handed, *not* relative to the beginning of its parent
* tvbuff.
*/
return result - subset_tvb->subset.offset;
}
static tvbuff_t *
subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
{
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
return tvb_clone_offset_len(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
}
static const struct tvb_ops tvb_subset_ops = {
sizeof(struct tvb_subset), /* size */
NULL, /* free */
subset_offset, /* offset */
subset_get_ptr, /* get_ptr */
subset_memcpy, /* memcpy */
subset_find_guint8, /* find_guint8 */
subset_pbrk_guint8, /* pbrk_guint8 */
subset_clone, /* clone */
};
static tvbuff_t *
tvb_new_with_subset(tvbuff_t *backing, const guint reported_length,
const guint subset_tvb_offset, const guint subset_tvb_length)
{
tvbuff_t *tvb = tvb_new(&tvb_subset_ops);
struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
subset_tvb->subset.offset = subset_tvb_offset;
subset_tvb->subset.length = subset_tvb_length;
subset_tvb->subset.tvb = backing;
tvb->length = subset_tvb_length;
/*
* The contained length must not exceed what remains in the
* backing tvbuff.
*/
tvb->contained_length = MIN(reported_length, backing->contained_length - subset_tvb_offset);
tvb->flags = backing->flags;
tvb->reported_length = reported_length;
tvb->initialized = TRUE;
/* Optimization. If the backing buffer has a pointer to contiguous, real data,
* then we can point directly to our starting offset in that buffer */
if (backing->real_data != NULL) {
tvb->real_data = backing->real_data + subset_tvb_offset;
}
/*
* The top-level data source of this tvbuff is the top-level
* data source of its parent.
*/
tvb->ds_tvb = backing->ds_tvb;
return tvb;
}
tvbuff_t *
tvb_new_subset_length_caplen(tvbuff_t *backing, const gint backing_offset, const gint backing_length, const gint reported_length)
{
tvbuff_t *tvb;
guint subset_tvb_offset;
guint subset_tvb_length;
guint actual_reported_length;
DISSECTOR_ASSERT(backing && backing->initialized);
THROW_ON(reported_length < -1, ReportedBoundsError);
tvb_check_offset_length(backing, backing_offset, backing_length,
&subset_tvb_offset,
&subset_tvb_length);
if (reported_length == -1)
actual_reported_length = backing->reported_length - subset_tvb_offset;
else
actual_reported_length = (guint)reported_length;
tvb = tvb_new_with_subset(backing, actual_reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);
return tvb;
}
tvbuff_t *
tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint reported_length)
{
gint captured_length;
gint actual_reported_length;
tvbuff_t *tvb;
guint subset_tvb_offset;
guint subset_tvb_length;
DISSECTOR_ASSERT(backing && backing->initialized);
THROW_ON(reported_length < -1, ReportedBoundsError);
if (reported_length == -1)
actual_reported_length = backing->reported_length;
else
actual_reported_length = reported_length;
/*
* Cut the captured length short, so it doesn't go past the subset's
* reported length.
*/
captured_length = tvb_captured_length_remaining(backing, backing_offset);
THROW_ON(captured_length < 0, BoundsError);
if (captured_length > actual_reported_length)
captured_length = actual_reported_length;
tvb_check_offset_length(backing, backing_offset, captured_length,
&subset_tvb_offset,
&subset_tvb_length);
/*
* If the requested reported length is "to the end of the buffer",
* subtract the offset from the total length. We do this now, because
* the user might have passed in a negative offset.
*/
if (reported_length == -1) {
THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
actual_reported_length -= subset_tvb_offset;
}
tvb = tvb_new_with_subset(backing, (guint)actual_reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);
return tvb;
}
tvbuff_t *
tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset)
{
tvbuff_t *tvb;
guint subset_tvb_offset;
guint subset_tvb_length;
guint reported_length;
tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
&subset_tvb_offset,
&subset_tvb_length);
THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
reported_length = backing->reported_length - subset_tvb_offset;
tvb = tvb_new_with_subset(backing, reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);
return tvb;
}
tvbuff_t *
tvb_new_proxy(tvbuff_t *backing)
{
tvbuff_t *tvb;
if (backing)
tvb = tvb_new_with_subset(backing, backing->reported_length, 0, backing->length);
else
tvb = tvb_new_real_data(NULL, 0, 0);
tvb->ds_tvb = tvb;
return tvb;
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/