3 * Testy, Virtual(-izable) Buffer of guint8*'s
5 * "Testy" -- the buffer gets mad when an attempt to access data
6 * beyond the bounds of the buffer. An exception is thrown.
8 * "Virtual" -- the buffer can have its own data, can use a subset of
9 * the data of a backing tvbuff, or can be a composite of
12 * $Id: tvbuff.c,v 1.60 2004/02/19 05:19:10 guy Exp $
14 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
16 * Code to convert IEEE floating point formats to native floating point
17 * derived from code Copyright (c) Ashok Narayanan, 2000
19 * Ethereal - Network traffic analyzer
20 * By Gerald Combs <gerald@ethereal.com>
21 * Copyright 1998 Gerald Combs
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
49 ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
53 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length);
55 /* We dole out tvbuff's from this memchunk. */
56 GMemChunk *tvbuff_mem_chunk = NULL;
61 if (!tvbuff_mem_chunk)
62 tvbuff_mem_chunk = g_mem_chunk_create(tvbuff_t, 20, G_ALLOC_AND_FREE);
69 g_mem_chunk_destroy(tvbuff_mem_chunk);
71 tvbuff_mem_chunk = NULL;
78 tvb_init(tvbuff_t *tvb, tvbuff_type type)
80 tvb_backing_t *backing;
81 tvb_comp_t *composite;
84 tvb->initialized = FALSE;
87 tvb->reported_length = 0;
89 tvb->real_data = NULL;
95 case TVBUFF_REAL_DATA:
100 backing = &tvb->tvbuffs.subset;
106 case TVBUFF_COMPOSITE:
107 composite = &tvb->tvbuffs.composite;
108 composite->tvbs = NULL;
109 composite->start_offsets = NULL;
110 composite->end_offsets = NULL;
117 tvb_new(tvbuff_type type)
121 tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
130 tvb_free(tvbuff_t* tvb)
132 tvbuff_t *member_tvb;
133 tvb_comp_t *composite;
138 if (tvb->usage_count == 0) {
140 case TVBUFF_REAL_DATA:
143 * XXX - do this with a union?
145 tvb->free_cb((gpointer)tvb->real_data);
150 /* This will be NULL if tvb_new_subset() fails because
151 * reported_length < -1 */
152 if (tvb->tvbuffs.subset.tvb) {
153 tvb_decrement_usage_count(tvb->tvbuffs.subset.tvb, 1);
157 case TVBUFF_COMPOSITE:
158 composite = &tvb->tvbuffs.composite;
159 for (slist = composite->tvbs; slist != NULL ; slist = slist->next) {
160 member_tvb = slist->data;
161 tvb_decrement_usage_count(member_tvb, 1);
164 g_slist_free(composite->tvbs);
166 if (composite->start_offsets)
167 g_free(composite->start_offsets);
168 if (composite->end_offsets)
169 g_free(composite->end_offsets);
170 if (tvb->real_data) {
172 * XXX - do this with a union?
174 g_free((gpointer)tvb->real_data);
181 g_slist_free(tvb->used_in);
184 g_chunk_free(tvb, tvbuff_mem_chunk);
189 tvb_increment_usage_count(tvbuff_t* tvb, guint count)
191 tvb->usage_count += count;
193 return tvb->usage_count;
197 tvb_decrement_usage_count(tvbuff_t* tvb, guint count)
199 if (tvb->usage_count <= count) {
200 tvb->usage_count = 1;
205 tvb->usage_count -= count;
206 return tvb->usage_count;
212 tvb_free_chain(tvbuff_t* tvb)
216 /* Recursively call tvb_free_chain() */
217 for (slist = tvb->used_in; slist != NULL ; slist = slist->next) {
218 tvb_free_chain( (tvbuff_t*)slist->data );
221 /* Stop the recursion */
228 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
230 g_assert(tvb->type == TVBUFF_REAL_DATA);
235 add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
237 tvb->used_in = g_slist_prepend(tvb->used_in, used_in);
238 tvb_increment_usage_count(tvb, 1);
242 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
244 g_assert(parent->initialized);
245 g_assert(child->initialized);
246 g_assert(child->type == TVBUFF_REAL_DATA);
247 add_to_used_in_list(parent, child);
251 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
253 g_assert(tvb->type == TVBUFF_REAL_DATA);
254 g_assert(!tvb->initialized);
256 if (reported_length < -1) {
257 THROW(ReportedBoundsError);
260 tvb->real_data = data;
261 tvb->length = length;
262 tvb->reported_length = reported_length;
263 tvb->initialized = TRUE;
267 tvb_new_real_data(const guint8* data, guint length, gint reported_length)
269 static tvbuff_t *last_tvb=NULL;
272 tvb = tvb_new(TVBUFF_REAL_DATA);
277 /* remember this tvb in case we throw an exception and
278 * lose the pointer to it.
282 tvb_set_real_data(tvb, data, length, reported_length);
285 * This is the top-level real tvbuff for this data source,
286 * so its data source tvbuff is itself.
290 /* ok no exception so we dont need to remember it any longer */
296 /* Computes the absolute offset and length based on a possibly-negative offset
297 * and a length that is possible -1 (which means "to the end of the data").
298 * Returns TRUE/FALSE indicating whether the offset is in bounds or
299 * not. The integer ptrs are modified with the new offset and length.
300 * No exception is thrown.
302 * XXX - we return TRUE, not FALSE, if the offset is positive and right
303 * after the end of the tvbuff (i.e., equal to the length). We do this
304 * so that a dissector constructing a subset tvbuff for the next protocol
305 * will get a zero-length tvbuff, not an exception, if there's no data
306 * left for the next protocol - we want the next protocol to be the one
307 * that gets an exception, so the error is reported as an error in that
308 * protocol rather than the containing protocol. */
310 compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
311 guint *offset_ptr, guint *length_ptr, int *exception)
313 g_assert(offset_ptr);
314 g_assert(length_ptr);
316 /* Compute the offset */
318 /* Positive offset - relative to the beginning of the packet. */
319 if ((guint) offset > tvb->reported_length) {
321 *exception = ReportedBoundsError;
325 else if ((guint) offset > tvb->length) {
327 *exception = BoundsError;
332 *offset_ptr = offset;
336 /* Negative offset - relative to the end of the packet. */
337 if ((guint) -offset > tvb->reported_length) {
339 *exception = ReportedBoundsError;
343 else if ((guint) -offset > tvb->length) {
345 *exception = BoundsError;
350 *offset_ptr = tvb->length + offset;
354 /* Compute the length */
357 /* XXX - ReportedBoundsError? */
358 *exception = BoundsError;
362 else if (length == -1) {
363 *length_ptr = tvb->length - *offset_ptr;
366 *length_ptr = length;
374 check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
375 guint *offset_ptr, guint *length_ptr, int *exception)
379 g_assert(tvb->initialized);
381 if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
386 * Compute the offset of the first byte past the length.
388 end_offset = *offset_ptr + *length_ptr;
391 * Check for an overflow, and clamp "end_offset" at the maximum
392 * if we got an overflow - that should force us to indicate that
393 * we're past the end of the tvbuff.
395 if (end_offset < *offset_ptr)
396 end_offset = UINT_MAX;
399 * Check whether that offset goes more than one byte past the
402 * If not, return TRUE; otherwise, return FALSE and, if "exception"
403 * is non-null, return the appropriate exception through it.
405 if (end_offset <= tvb->length) {
408 else if (end_offset <= tvb->reported_length) {
410 *exception = BoundsError;
416 *exception = ReportedBoundsError;
421 g_assert_not_reached();
424 /* Checks (+/-) offset and length and throws an exception if
425 * either is out of bounds. Sets integer ptrs to the new offset
428 check_offset_length(tvbuff_t *tvb, gint offset, gint length,
429 guint *offset_ptr, guint *length_ptr)
433 if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
434 g_assert(exception > 0);
442 tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
443 gint backing_offset, gint backing_length, gint reported_length)
445 g_assert(tvb->type == TVBUFF_SUBSET);
446 g_assert(!tvb->initialized);
448 if (reported_length < -1) {
449 THROW(ReportedBoundsError);
452 check_offset_length(backing, backing_offset, backing_length,
453 &tvb->tvbuffs.subset.offset,
454 &tvb->tvbuffs.subset.length);
456 tvb->tvbuffs.subset.tvb = backing;
457 tvb->length = tvb->tvbuffs.subset.length;
459 if (reported_length == -1) {
460 tvb->reported_length = backing->reported_length - tvb->tvbuffs.subset.offset;
463 tvb->reported_length = reported_length;
465 tvb->initialized = TRUE;
466 add_to_used_in_list(backing, tvb);
468 /* Optimization. If the backing buffer has a pointer to contiguous, real data,
469 * then we can point directly to our starting offset in that buffer */
470 if (backing->real_data != NULL) {
471 tvb->real_data = backing->real_data + tvb->tvbuffs.subset.offset;
477 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
479 static tvbuff_t *last_tvb=NULL;
482 tvb = tvb_new(TVBUFF_SUBSET);
487 /* remember this tvb in case we throw an exception and
488 * lose the pointer to it.
492 tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
495 * The top-level data source of this tvbuff is the top-level
496 * data source of its parent.
498 tvb->ds_tvb = backing->ds_tvb;
500 /* ok no exception so we dont need to remember it any longer */
507 tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
509 tvb_comp_t *composite;
511 g_assert(!tvb->initialized);
512 composite = &tvb->tvbuffs.composite;
513 composite->tvbs = g_slist_append( composite->tvbs, member );
514 add_to_used_in_list(member, tvb);
518 tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
520 tvb_comp_t *composite;
522 g_assert(!tvb->initialized);
523 composite = &tvb->tvbuffs.composite;
524 composite->tvbs = g_slist_prepend( composite->tvbs, member );
525 add_to_used_in_list(member, tvb);
529 tvb_new_composite(void)
531 return tvb_new(TVBUFF_COMPOSITE);
535 tvb_composite_finalize(tvbuff_t* tvb)
539 tvbuff_t *member_tvb;
540 tvb_comp_t *composite;
543 g_assert(!tvb->initialized);
544 g_assert(tvb->length == 0);
546 composite = &tvb->tvbuffs.composite;
547 num_members = g_slist_length(composite->tvbs);
549 composite->start_offsets = g_new(guint, num_members);
550 composite->end_offsets = g_new(guint, num_members);
552 for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
553 g_assert((guint) i < num_members);
554 member_tvb = slist->data;
555 composite->start_offsets[i] = tvb->length;
556 tvb->length += member_tvb->length;
557 composite->end_offsets[i] = tvb->length - 1;
561 tvb->initialized = TRUE;
567 tvb_length(tvbuff_t* tvb)
569 g_assert(tvb->initialized);
575 tvb_length_remaining(tvbuff_t *tvb, gint offset)
577 guint abs_offset, abs_length;
579 g_assert(tvb->initialized);
581 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
590 tvb_ensure_length_remaining(tvbuff_t *tvb, gint offset)
592 guint abs_offset, abs_length;
595 g_assert(tvb->initialized);
597 if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, &exception)) {
600 if (abs_length == 0) {
602 * This routine ensures there's at least one byte available.
603 * There aren't any bytes available, so throw the appropriate
606 if (abs_offset >= tvb->reported_length)
607 THROW(ReportedBoundsError);
617 /* Validates that 'length' bytes are available starting from
618 * offset (pos/neg). Does not throw an exception. */
620 tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
622 guint abs_offset, abs_length;
624 g_assert(tvb->initialized);
626 if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
629 if (abs_offset + abs_length <= tvb->length) {
637 /* Validates that 'length' bytes are available starting from
638 * offset (pos/neg). Throws an exception if they aren't. */
640 tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
642 guint abs_offset, abs_length;
644 g_assert(tvb->initialized);
647 * -1 doesn't mean "until end of buffer", as that's pointless
648 * for this routine. We must treat it as a Really Large Positive
649 * Number, so that we throw an exception; we throw
650 * ReportedBoundsError, as if it were past even the end of a
651 * reassembled packet, and past the end of even the data we
654 * We do the same with other negative lengths.
657 THROW(ReportedBoundsError);
659 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
663 tvb_offset_exists(tvbuff_t *tvb, gint offset)
665 guint abs_offset, abs_length;
667 g_assert(tvb->initialized);
668 if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
671 if (abs_offset < tvb->length) {
680 tvb_reported_length(tvbuff_t* tvb)
682 g_assert(tvb->initialized);
684 return tvb->reported_length;
688 tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
690 guint abs_offset, abs_length;
692 g_assert(tvb->initialized);
694 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
695 if (tvb->reported_length >= abs_offset)
696 return tvb->reported_length - abs_offset;
705 /* Set the reported length of a tvbuff to a given value; used for protocols
706 whose headers contain an explicit length and where the calling
707 dissector's payload may include padding as well as the packet for
710 Also adjusts the data length. */
712 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
714 g_assert(tvb->initialized);
716 if (reported_length > tvb->reported_length)
717 THROW(ReportedBoundsError);
719 tvb->reported_length = reported_length;
720 if (reported_length < tvb->length)
721 tvb->length = reported_length;
726 first_real_data_ptr(tvbuff_t *tvb)
731 case TVBUFF_REAL_DATA:
732 return tvb->real_data;
734 member = tvb->tvbuffs.subset.tvb;
735 return first_real_data_ptr(member);
736 case TVBUFF_COMPOSITE:
737 member = tvb->tvbuffs.composite.tvbs->data;
738 return first_real_data_ptr(member);
741 g_assert_not_reached();
746 offset_from_real_beginning(tvbuff_t *tvb, int counter)
751 case TVBUFF_REAL_DATA:
754 member = tvb->tvbuffs.subset.tvb;
755 return offset_from_real_beginning(member, counter + tvb->tvbuffs.subset.offset);
756 case TVBUFF_COMPOSITE:
757 member = tvb->tvbuffs.composite.tvbs->data;
758 return offset_from_real_beginning(member, counter);
761 g_assert_not_reached();
766 composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
769 guint i, num_members;
770 tvb_comp_t *composite;
771 tvbuff_t *member_tvb = NULL;
772 guint member_offset, member_length;
775 g_assert(tvb->type == TVBUFF_COMPOSITE);
777 /* Maybe the range specified by offset/length
778 * is contiguous inside one of the member tvbuffs */
779 composite = &tvb->tvbuffs.composite;
780 num_members = g_slist_length(composite->tvbs);
782 for (i = 0; i < num_members; i++) {
783 if (abs_offset <= composite->end_offsets[i]) {
784 slist = g_slist_nth(composite->tvbs, i);
785 member_tvb = slist->data;
789 g_assert(member_tvb);
791 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
792 abs_length, &member_offset, &member_length, NULL)) {
795 * The range is, in fact, contiguous within member_tvb.
797 g_assert(!tvb->real_data);
798 return ensure_contiguous_no_exception(member_tvb, member_offset, member_length, NULL);
801 tvb->real_data = tvb_memdup(tvb, 0, -1);
802 return tvb->real_data + abs_offset;
805 g_assert_not_reached();
810 ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
813 guint abs_offset, abs_length;
815 if (!check_offset_length_no_exception(tvb, offset, length,
816 &abs_offset, &abs_length, exception)) {
821 * We know that all the data is present in the tvbuff, so
822 * no exceptions should be thrown.
824 if (tvb->real_data) {
825 return tvb->real_data + abs_offset;
829 case TVBUFF_REAL_DATA:
830 g_assert_not_reached();
832 return ensure_contiguous_no_exception(tvb->tvbuffs.subset.tvb,
833 abs_offset - tvb->tvbuffs.subset.offset,
835 case TVBUFF_COMPOSITE:
836 return composite_ensure_contiguous_no_exception(tvb, abs_offset, abs_length);
840 g_assert_not_reached();
845 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
850 p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
852 g_assert(exception > 0);
859 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
864 for (b = haystack, i = 0; (guint) i < haystacklen; i++, b++) {
874 guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
878 guint8 item, *needlep, needle;
880 for (b = haystack, i = 0; (guint) i < haystacklen; i++, b++) {
883 while ((needle = *needlep) != '\0') {
895 /************** ACCESSORS **************/
898 composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
900 guint i, num_members;
901 tvb_comp_t *composite;
902 tvbuff_t *member_tvb = NULL;
903 guint member_offset, member_length;
907 g_assert(tvb->type == TVBUFF_COMPOSITE);
909 /* Maybe the range specified by offset/length
910 * is contiguous inside one of the member tvbuffs */
911 composite = &tvb->tvbuffs.composite;
912 num_members = g_slist_length(composite->tvbs);
914 for (i = 0; i < num_members; i++) {
915 if (abs_offset <= composite->end_offsets[i]) {
916 slist = g_slist_nth(composite->tvbs, i);
917 member_tvb = slist->data;
921 g_assert(member_tvb);
923 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
924 abs_length, &member_offset, &member_length, NULL)) {
926 g_assert(!tvb->real_data);
927 return tvb_memcpy(member_tvb, target, member_offset, member_length);
930 /* The requested data is non-contiguous inside
931 * the member tvb. We have to memcpy() the part that's in the member tvb,
932 * then iterate across the other member tvb's, copying their portions
933 * until we have copied all data.
935 retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
936 &member_offset, &member_length, NULL);
939 tvb_memcpy(member_tvb, target, member_offset, member_length);
940 abs_offset += member_length;
941 abs_length -= member_length;
944 if (abs_length > 0) {
945 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
951 g_assert_not_reached();
956 tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
958 guint abs_offset, abs_length;
960 g_assert(length >= -1);
961 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
963 if (tvb->real_data) {
964 return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
968 case TVBUFF_REAL_DATA:
969 g_assert_not_reached();
972 return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
973 abs_offset - tvb->tvbuffs.subset.offset,
976 case TVBUFF_COMPOSITE:
977 return composite_memcpy(tvb, target, offset, length);
980 g_assert_not_reached();
986 * XXX - this doesn't treat a length of -1 as an error.
987 * If it did, this could replace some code that calls
988 * "tvb_ensure_bytes_exist()" and then allocates a buffer and copies
991 * "composite_ensure_contiguous_no_exception()" depends on -1 not being
992 * an error; does anything else depend on this routine treating -1 as
993 * meaning "to the end of the buffer"?
996 tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
998 guint abs_offset, abs_length;
1001 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
1003 duped = g_malloc(abs_length);
1004 return tvb_memcpy(tvb, duped, abs_offset, abs_length);
1010 tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
1012 return ensure_contiguous(tvb, offset, length);
1016 tvb_get_guint8(tvbuff_t *tvb, gint offset)
1020 ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
1025 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
1029 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
1034 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
1038 ptr = ensure_contiguous(tvb, offset, 3);
1039 return pntoh24(ptr);
1043 tvb_get_ntohl(tvbuff_t *tvb, gint offset)
1047 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1052 * Stuff for IEEE float handling on platforms that don't have IEEE
1053 * format as the native floating-point format.
1055 * For now, we treat only the VAX as such a platform.
1057 * XXX - other non-IEEE boxes that can run UNIX include some Crays,
1058 * and possibly other machines.
1060 * It appears that the official Linux port to System/390 and
1061 * zArchitecture uses IEEE format floating point (not a
1064 * I don't know whether there are any other machines that
1065 * could run Ethereal and that don't use IEEE format.
1066 * As far as I know, all of the main commercial microprocessor
1067 * families on which OSes that support Ethereal can run
1068 * use IEEE format (x86, 68k, SPARC, MIPS, PA-RISC, Alpha,
1069 * IA-64, and so on).
1079 #define IEEE_SP_NUMBER_WIDTH 32 /* bits in number */
1080 #define IEEE_SP_EXP_WIDTH 8 /* bits in exponent */
1081 #define IEEE_SP_MANTISSA_WIDTH 23 /* IEEE_SP_NUMBER_WIDTH - 1 - IEEE_SP_EXP_WIDTH */
1083 #define IEEE_SP_SIGN_MASK 0x80000000
1084 #define IEEE_SP_EXPONENT_MASK 0x7F800000
1085 #define IEEE_SP_MANTISSA_MASK 0x007FFFFF
1086 #define IEEE_SP_INFINITY IEEE_SP_EXPONENT_MASK
1088 #define IEEE_SP_IMPLIED_BIT (1 << IEEE_SP_MANTISSA_WIDTH)
1089 #define IEEE_SP_INFINITE ((1 << IEEE_SP_EXP_WIDTH) - 1)
1090 #define IEEE_SP_BIAS ((1 << (IEEE_SP_EXP_WIDTH - 1)) - 1)
1093 ieee_float_is_zero(guint32 w)
1095 return ((w & ~IEEE_SP_SIGN_MASK) == 0);
1099 get_ieee_float(guint32 w)
1105 sign = w & IEEE_SP_SIGN_MASK;
1106 exponent = w & IEEE_SP_EXPONENT_MASK;
1107 mantissa = w & IEEE_SP_MANTISSA_MASK;
1109 if (ieee_float_is_zero(w)) {
1110 /* number is zero, unnormalized, or not-a-number */
1115 * XXX - how to handle this?
1117 if (IEEE_SP_INFINITY == exponent) {
1119 * number is positive or negative infinity, or a special value
1121 return (sign? MINUS_INFINITY: PLUS_INFINITY);
1125 exponent = ((exponent >> IEEE_SP_MANTISSA_WIDTH) - IEEE_SP_BIAS) -
1126 IEEE_SP_MANTISSA_WIDTH;
1127 mantissa |= IEEE_SP_IMPLIED_BIT;
1130 return -mantissa * pow(2, exponent);
1132 return mantissa * pow(2, exponent);
1137 * We assume that if you don't have IEEE floating-point, you have a
1138 * compiler that understands 64-bit integral quantities.
1140 #define IEEE_DP_NUMBER_WIDTH 64 /* bits in number */
1141 #define IEEE_DP_EXP_WIDTH 11 /* bits in exponent */
1142 #define IEEE_DP_MANTISSA_WIDTH 52 /* IEEE_DP_NUMBER_WIDTH - 1 - IEEE_DP_EXP_WIDTH */
1144 #define IEEE_DP_SIGN_MASK 0x8000000000000000LL
1145 #define IEEE_DP_EXPONENT_MASK 0x7FF0000000000000LL
1146 #define IEEE_DP_MANTISSA_MASK 0x000FFFFFFFFFFFFFLL
1147 #define IEEE_DP_INFINITY IEEE_DP_EXPONENT_MASK
1149 #define IEEE_DP_IMPLIED_BIT (1LL << IEEE_DP_MANTISSA_WIDTH)
1150 #define IEEE_DP_INFINITE ((1 << IEEE_DP_EXP_WIDTH) - 1)
1151 #define IEEE_DP_BIAS ((1 << (IEEE_DP_EXP_WIDTH - 1)) - 1)
1154 ieee_double_is_zero(guint64 w)
1156 return ((w & ~IEEE_SP_SIGN_MASK) == 0);
1160 get_ieee_double(guint64 w)
1166 sign = w & IEEE_DP_SIGN_MASK;
1167 exponent = w & IEEE_DP_EXPONENT_MASK;
1168 mantissa = w & IEEE_DP_MANTISSA_MASK;
1170 if (ieee_double_is_zero(w)) {
1171 /* number is zero, unnormalized, or not-a-number */
1176 * XXX - how to handle this?
1178 if (IEEE_DP_INFINITY == exponent) {
1180 * number is positive or negative infinity, or a special value
1182 return (sign? MINUS_INFINITY: PLUS_INFINITY);
1186 exponent = ((exponent >> IEEE_DP_MANTISSA_WIDTH) - IEEE_DP_BIAS) -
1187 IEEE_DP_MANTISSA_WIDTH;
1188 mantissa |= IEEE_DP_IMPLIED_BIT;
1191 return -mantissa * pow(2, exponent);
1193 return mantissa * pow(2, exponent);
1198 * Fetches an IEEE single-precision floating-point number, in
1199 * big-endian form, and returns a "float".
1201 * XXX - should this be "double", in case there are IEEE single-
1202 * precision numbers that won't fit in some platform's native
1206 tvb_get_ntohieee_float(tvbuff_t *tvb, int offset)
1209 return get_ieee_float(tvb_get_ntohl(tvb, offset));
1216 ieee_fp_union.w = tvb_get_ntohl(tvb, offset);
1217 return ieee_fp_union.f;
1222 * Fetches an IEEE double-precision floating-point number, in
1223 * big-endian form, and returns a "double".
1226 tvb_get_ntohieee_double(tvbuff_t *tvb, int offset)
1240 #ifdef WORDS_BIGENDIAN
1241 ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset);
1242 ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset+4);
1244 ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset+4);
1245 ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset);
1248 return get_ieee_double(ieee_fp_union.dw);
1250 return ieee_fp_union.d;
1255 tvb_get_letohs(tvbuff_t *tvb, gint offset)
1259 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
1260 return pletohs(ptr);
1264 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
1268 ptr = ensure_contiguous(tvb, offset, 3);
1269 return pletoh24(ptr);
1273 tvb_get_letohl(tvbuff_t *tvb, gint offset)
1277 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1278 return pletohl(ptr);
1282 * Fetches an IEEE single-precision floating-point number, in
1283 * little-endian form, and returns a "float".
1285 * XXX - should this be "double", in case there are IEEE single-
1286 * precision numbers that won't fit in some platform's native
1290 tvb_get_letohieee_float(tvbuff_t *tvb, int offset)
1293 return get_ieee_float(tvb_get_letohl(tvb, offset));
1300 ieee_fp_union.w = tvb_get_letohl(tvb, offset);
1301 return ieee_fp_union.f;
1306 * Fetches an IEEE double-precision floating-point number, in
1307 * little-endian form, and returns a "double".
1310 tvb_get_letohieee_double(tvbuff_t *tvb, int offset)
1324 #ifdef WORDS_BIGENDIAN
1325 ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset+4);
1326 ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset);
1328 ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset);
1329 ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset+4);
1332 return get_ieee_double(ieee_fp_union.dw);
1334 return ieee_fp_union.d;
1338 /* Find first occurence of needle in tvbuff, starting at offset. Searches
1339 * at most maxlength number of bytes; if maxlength is -1, searches to
1341 * Returns the offset of the found needle, or -1 if not found.
1342 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1343 * in that case, -1 will be returned if the boundary is reached before
1344 * finding needle. */
1346 tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
1348 const guint8 *result;
1349 guint abs_offset, junk_length;
1353 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1355 /* Only search to end of tvbuff, w/o throwing exception. */
1356 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1357 if (maxlength == -1) {
1358 /* No maximum length specified; search to end of tvbuff. */
1361 else if (tvbufflen < (guint) maxlength) {
1362 /* Maximum length goes past end of tvbuff; search to end
1367 /* Maximum length doesn't go past end of tvbuff; search
1372 /* If we have real data, perform our search now. */
1373 if (tvb->real_data) {
1374 result = guint8_find(tvb->real_data + abs_offset, limit, needle);
1375 if (result == NULL) {
1379 return result - tvb->real_data;
1384 case TVBUFF_REAL_DATA:
1385 g_assert_not_reached();
1388 return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
1389 abs_offset - tvb->tvbuffs.subset.offset,
1392 case TVBUFF_COMPOSITE:
1393 g_assert_not_reached();
1394 /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
1397 g_assert_not_reached();
1401 /* Find first occurence of any of the needles in tvbuff, starting at offset.
1402 * Searches at most maxlength number of bytes; if maxlength is -1, searches
1404 * Returns the offset of the found needle, or -1 if not found.
1405 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1406 * in that case, -1 will be returned if the boundary is reached before
1407 * finding needle. */
1409 tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 *needles)
1411 const guint8 *result;
1412 guint abs_offset, junk_length;
1416 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1418 /* Only search to end of tvbuff, w/o throwing exception. */
1419 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1420 if (maxlength == -1) {
1421 /* No maximum length specified; search to end of tvbuff. */
1424 else if (tvbufflen < (guint) maxlength) {
1425 /* Maximum length goes past end of tvbuff; search to end
1430 /* Maximum length doesn't go past end of tvbuff; search
1435 /* If we have real data, perform our search now. */
1436 if (tvb->real_data) {
1437 result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles);
1438 if (result == NULL) {
1442 return result - tvb->real_data;
1447 case TVBUFF_REAL_DATA:
1448 g_assert_not_reached();
1451 return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
1452 abs_offset - tvb->tvbuffs.subset.offset,
1455 case TVBUFF_COMPOSITE:
1456 g_assert_not_reached();
1457 /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
1460 g_assert_not_reached();
1464 /* Find size of stringz (NUL-terminated string) by looking for terminating
1465 * NUL. The size of the string includes the terminating NUL.
1467 * If the NUL isn't found, it throws the appropriate exception.
1470 tvb_strsize(tvbuff_t *tvb, gint offset)
1472 guint abs_offset, junk_length;
1475 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1476 nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
1477 if (nul_offset == -1) {
1479 * OK, we hit the end of the tvbuff, so we should throw
1482 * Did we hit the end of the captured data, or the end
1483 * of the actual data? If there's less captured data
1484 * than actual data, we presumably hit the end of the
1485 * captured data, otherwise we hit the end of the actual
1488 if (tvb_length(tvb) < tvb_reported_length(tvb)) {
1491 THROW(ReportedBoundsError);
1494 return (nul_offset - abs_offset) + 1;
1497 /* Find length of string by looking for end of string ('\0'), up to
1498 * 'maxlength' characters'; if 'maxlength' is -1, searches to end
1500 * Returns -1 if 'maxlength' reached before finding EOS. */
1502 tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
1505 guint abs_offset, junk_length;
1507 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1509 result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
1511 if (result_offset == -1) {
1515 return result_offset - abs_offset;
1520 * Implement strneql etc
1524 * Call strncmp after checking if enough chars left, returning 0 if
1525 * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1528 tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, gint size)
1532 ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
1535 int cmp = strncmp((const char *)ptr, str, size);
1538 * Return 0 if equal, -1 otherwise.
1540 return (cmp == 0 ? 0 : -1);
1543 * Not enough characters in the tvbuff to match the
1551 * Call strncasecmp after checking if enough chars left, returning 0 if
1552 * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1555 tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, gint size)
1559 ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
1562 int cmp = strncasecmp((const char *)ptr, str, size);
1565 * Return 0 if equal, -1 otherwise.
1567 return (cmp == 0 ? 0 : -1);
1570 * Not enough characters in the tvbuff to match the
1578 * Call memcmp after checking if enough chars left, returning 0 if
1579 * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1582 tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1586 ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
1589 int cmp = memcmp(ptr, str, size);
1592 * Return 0 if equal, -1 otherwise.
1594 return (cmp == 0 ? 0 : -1);
1597 * Not enough characters in the tvbuff to match the
1604 /* Convert a string from Unicode to ASCII. At the moment we fake it by
1605 * assuming all characters are ASCII )-: The caller must free the
1606 * result returned. The len parameter is the number of guint16's to
1607 * convert from Unicode. */
1609 tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
1615 /* Make sure we have enough data before allocating the buffer,
1616 so we don't blow up if the length is huge. */
1617 tvb_ensure_bytes_exist(tvb, offset, 2*len);
1619 /* We know we won't throw an exception, so we don't have to worry
1620 about leaking this buffer. */
1621 buffer = g_malloc(len + 1);
1623 for (i = 0; i < len; i++) {
1624 character = little_endian ? tvb_get_letohs(tvb, offset)
1625 : tvb_get_ntohs(tvb, offset);
1626 buffer[i] = character & 0xff;
1636 * Format the data in the tvb from offset for length ...
1640 tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
1645 if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
1647 len = tvb_length_remaining(tvb, offset);
1648 ptr = ensure_contiguous(tvb, offset, len);
1652 return format_text(ptr, len);
1657 * Given a tvbuff, an offset, and a length, allocate a buffer big enough
1658 * to hold a non-null-terminated string of that length at that offset,
1659 * plus a trailing '\0', copy the string into it, and return a pointer
1662 * Throws an exception if the tvbuff ends before the string does.
1665 tvb_get_string(tvbuff_t *tvb, gint offset, gint length)
1670 ptr = ensure_contiguous(tvb, offset, length);
1671 strbuf = g_malloc(length + 1);
1673 memcpy(strbuf, ptr, length);
1674 strbuf[length] = '\0';
1679 * Given a tvbuff and an offset, with the offset assumed to refer to
1680 * a null-terminated string, find the length of that string (and throw
1681 * an exception if the tvbuff ends before we find the null), allocate
1682 * a buffer big enough to hold the string, copy the string into it,
1683 * and return a pointer to the string. Also return the length of the
1684 * string (including the terminating null) through a pointer.
1687 tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
1692 size = tvb_strsize(tvb, offset);
1693 strptr = g_malloc(size);
1694 tvb_memcpy(tvb, strptr, offset, size);
1699 /* Looks for a stringz (NUL-terminated string) in tvbuff and copies
1700 * no more than bufsize number of bytes, including terminating NUL, to buffer.
1701 * Returns length of string (not including terminating NUL), or -1 if the string was
1702 * truncated in the buffer due to not having reached the terminating NUL.
1703 * In this way, it acts like snprintf().
1705 * bufsize MUST be greater than 0.
1707 * When processing a packet where the remaining number of bytes is less
1708 * than bufsize, an exception is not thrown if the end of the packet
1709 * is reached before the NUL is found. If no NUL is found before reaching
1710 * the end of the short packet, -1 is still returned, and the string
1711 * is truncated with a NUL, albeit not at buffer[bufsize - 1], but
1712 * at the correct spot, terminating the string.
1714 * *bytes_copied will contain the number of bytes actually copied,
1715 * including the terminating-NUL.
1718 _tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer,
1722 guint abs_offset, junk_length;
1724 gboolean decreased_max = FALSE;
1726 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1728 /* There must at least be room for the terminating NUL. */
1729 g_assert(bufsize != 0);
1731 /* If there's no room for anything else, just return the NUL. */
1738 /* Only read to end of tvbuff, w/o throwing exception. */
1739 len = tvb_length_remaining(tvb, abs_offset);
1741 /* check_offset_length() won't throw an exception if we're
1742 * looking at the byte immediately after the end of the tvbuff. */
1744 THROW(ReportedBoundsError);
1747 /* This should not happen because check_offset_length() would
1748 * have already thrown an exception if 'offset' were out-of-bounds.
1750 g_assert(len != -1);
1753 * If we've been passed a negative number, bufsize will
1756 g_assert(bufsize <= G_MAXINT);
1758 if ((guint)len < bufsize) {
1760 decreased_max = TRUE;
1766 stringlen = tvb_strnlen(tvb, abs_offset, limit - 1);
1767 /* If NUL wasn't found, copy the data and return -1 */
1768 if (stringlen == -1) {
1769 tvb_memcpy(tvb, buffer, abs_offset, limit);
1770 if (decreased_max) {
1772 /* Add 1 for the extra NUL that we set at buffer[limit],
1773 * pretending that it was copied as part of the string. */
1774 *bytes_copied = limit + 1;
1777 *bytes_copied = limit;
1782 /* Copy the string to buffer */
1783 tvb_memcpy(tvb, buffer, abs_offset, stringlen + 1);
1784 *bytes_copied = stringlen + 1;
1788 /* Looks for a stringz (NUL-terminated string) in tvbuff and copies
1789 * no more than bufsize number of bytes, including terminating NUL, to buffer.
1790 * Returns length of string (not including terminating NUL), or -1 if the string was
1791 * truncated in the buffer due to not having reached the terminating NUL.
1792 * In this way, it acts like snprintf().
1794 * When processing a packet where the remaining number of bytes is less
1795 * than bufsize, an exception is not thrown if the end of the packet
1796 * is reached before the NUL is found. If no NUL is found before reaching
1797 * the end of the short packet, -1 is still returned, and the string
1798 * is truncated with a NUL, albeit not at buffer[bufsize - 1], but
1799 * at the correct spot, terminating the string.
1802 tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
1806 return _tvb_get_nstringz(tvb, offset, bufsize, buffer, &bytes_copied);
1809 /* Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to
1810 * have a terminating NUL. If the string was truncated when copied into buffer,
1811 * a NUL is placed at the end of buffer to terminate it.
1814 tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
1816 gint len, bytes_copied;
1818 len = _tvb_get_nstringz(tvb, offset, bufsize, buffer, &bytes_copied);
1821 buffer[bufsize - 1] = 0;
1822 return bytes_copied - 1;
1830 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1831 * at that offset (which may be -1 for "all the way to the end of the
1832 * tvbuff"), find the end of the (putative) line that starts at the
1833 * specified offset in the tvbuff, going no further than the specified
1836 * Return the length of the line (not counting the line terminator at
1837 * the end), or, if we don't find a line terminator:
1839 * if "deseg" is true, return -1;
1841 * if "deseg" is false, return the amount of data remaining in
1844 * Set "*next_offset" to the offset of the character past the line
1845 * terminator, or past the end of the buffer if we don't find a line
1846 * terminator. (It's not set if we return -1.)
1849 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
1857 len = tvb_length_remaining(tvb, offset);
1859 * XXX - what if "len" is still -1, meaning "offset is past the
1860 * end of the tvbuff"?
1862 eob_offset = offset + len;
1865 * Look either for a CR or an LF.
1867 eol_offset = tvb_pbrk_guint8(tvb, offset, len, (guint8 *)"\r\n");
1868 if (eol_offset == -1) {
1870 * No CR or LF - line is presumably continued in next packet.
1874 * Tell our caller we saw no EOL, so they can
1875 * try to desegment and get the entire line
1881 * Pretend the line runs to the end of the tvbuff.
1883 linelen = eob_offset - offset;
1884 *next_offset = eob_offset;
1888 * Find the number of bytes between the starting offset
1891 linelen = eol_offset - offset;
1896 if (tvb_get_guint8(tvb, eol_offset) == '\r') {
1898 * Yes - is it followed by an LF?
1900 if (eol_offset + 1 >= eob_offset) {
1902 * Dunno - the next byte isn't in this
1907 * We'll return -1, although that
1908 * runs the risk that if the line
1909 * really *is* terminated with a CR,
1910 * we won't properly dissect this
1913 * It's probably more likely that
1914 * the line ends with CR-LF than
1915 * that it ends with CR by itself.
1921 * Well, we can at least look at the next
1924 if (tvb_get_guint8(tvb, eol_offset + 1) == '\n') {
1926 * It's an LF; skip over the CR.
1934 * Return the offset of the character after the last
1935 * character in the line, skipping over the last character
1936 * in the line terminator.
1938 *next_offset = eol_offset + 1;
1944 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1945 * at that offset (which may be -1 for "all the way to the end of the
1946 * tvbuff"), find the end of the (putative) line that starts at the
1947 * specified offset in the tvbuff, going no further than the specified
1950 * However, treat quoted strings inside the buffer specially - don't
1951 * treat newlines in quoted strings as line terminators.
1953 * Return the length of the line (not counting the line terminator at
1954 * the end), or the amount of data remaining in the buffer if we don't
1955 * find a line terminator.
1957 * Set "*next_offset" to the offset of the character past the line
1958 * terminator, or past the end of the buffer if we don't find a line
1962 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
1965 gint cur_offset, char_offset;
1972 len = tvb_length_remaining(tvb, offset);
1974 * XXX - what if "len" is still -1, meaning "offset is past the
1975 * end of the tvbuff"?
1977 eob_offset = offset + len;
1979 cur_offset = offset;
1983 * Is this part of the string quoted?
1987 * Yes - look only for the terminating quote.
1989 char_offset = tvb_find_guint8(tvb, cur_offset, len,
1993 * Look either for a CR, an LF, or a '"'.
1995 char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
1996 (guint8 *)"\r\n\"");
1998 if (char_offset == -1) {
2000 * Not found - line is presumably continued in
2002 * We pretend the line runs to the end of the tvbuff.
2004 linelen = eob_offset - offset;
2005 *next_offset = eob_offset;
2011 * We're processing a quoted string.
2012 * We only looked for ", so we know it's a ";
2013 * as we're processing a quoted string, it's a
2021 c = tvb_get_guint8(tvb, char_offset);
2024 * Un-quoted "; it begins a quoted
2030 * It's a CR or LF; we've found a line
2033 * Find the number of bytes between the
2034 * starting offset and the CR or LF.
2036 linelen = char_offset - offset;
2043 * Yes; is it followed by an LF?
2045 if (char_offset + 1 < eob_offset &&
2046 tvb_get_guint8(tvb, char_offset + 1)
2049 * Yes; skip over the CR.
2056 * Return the offset of the character after
2057 * the last character in the line, skipping
2058 * over the last character in the line
2059 * terminator, and quit.
2061 *next_offset = char_offset + 1;
2067 * Step past the character we found.
2069 cur_offset = char_offset + 1;
2070 if (cur_offset >= eob_offset) {
2072 * The character we found was the last character
2073 * in the tvbuff - line is presumably continued in
2075 * We pretend the line runs to the end of the tvbuff.
2077 linelen = eob_offset - offset;
2078 *next_offset = eob_offset;
2086 * Format a bunch of data from a tvbuff as bytes, returning a pointer
2087 * to the string with the formatted data.
2090 tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
2092 return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
2095 /* Find a needle tvbuff within a haystack tvbuff. */
2097 tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset)
2099 guint haystack_abs_offset, haystack_abs_length;
2100 const guint8 *haystack_data;
2101 const guint8 *needle_data;
2102 const guint needle_len = needle_tvb->length;
2103 const guint8 *location;
2105 if (haystack_tvb->length < 1 || needle_tvb->length < 1) {
2109 /* Get pointers to the tvbuffs' data. */
2110 haystack_data = tvb_get_ptr(haystack_tvb, 0, -1);
2111 needle_data = tvb_get_ptr(needle_tvb, 0, -1);
2113 check_offset_length(haystack_tvb, haystack_offset, -1,
2114 &haystack_abs_offset, &haystack_abs_length);
2116 location = epan_memmem(haystack_data + haystack_abs_offset, haystack_abs_length,
2117 needle_data, needle_len);
2120 return location - haystack_data;