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.16 2001/03/23 14:44:02 jfoster Exp $
14 * Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
16 * Ethereal - Network traffic analyzer
17 * By Gerald Combs <gerald@zing.org>
18 * Copyright 1998 Gerald Combs
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
47 /* The backing tvbuff_t */
50 /* The offset/length of 'tvb' to which I'm privy */
59 /* Used for quick testing to see if this
60 * is the tvbuff that a COMPOSITE is
72 gchar* ds_name; /* data source name */
74 /* The tvbuffs in which this tvbuff is a member
75 * (that is, a backing tvbuff for a TVBUFF_SUBSET
76 * or a member for a TVB_COMPOSITE) */
79 /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track
80 * of the other tvbuff's they use */
86 /* We're either a TVBUFF_REAL_DATA or a
87 * TVBUFF_SUBSET that has a backing buffer that
88 * has real_data != NULL, or a TVBUFF_COMPOSITE
89 * which has flattened its data due to a call
94 /* Length of virtual buffer (and/or real_data). */
97 /* Reported length. */
98 guint reported_length;
100 /* Offset from beginning of first TVBUFF_REAL. */
103 /* Func to call when actually freed */
104 tvbuff_free_cb_t free_cb;
108 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length);
110 /* We dole out tvbuff's from this memchunk. */
111 GMemChunk *tvbuff_mem_chunk = NULL;
116 if (!tvbuff_mem_chunk)
117 tvbuff_mem_chunk = g_mem_chunk_create(tvbuff_t, 20, G_ALLOC_AND_FREE);
123 if (tvbuff_mem_chunk)
124 g_mem_chunk_destroy(tvbuff_mem_chunk);
126 tvbuff_mem_chunk = NULL;
133 tvb_init(tvbuff_t *tvb, tvbuff_type type)
135 tvb_backing_t *backing;
136 tvb_comp_t *composite;
139 tvb->initialized = FALSE;
140 tvb->usage_count = 1;
142 tvb->reported_length = 0;
144 tvb->real_data = NULL;
145 tvb->raw_offset = -1;
149 case TVBUFF_REAL_DATA:
154 backing = &tvb->tvbuffs.subset;
160 case TVBUFF_COMPOSITE:
161 composite = &tvb->tvbuffs.composite;
162 composite->tvbs = NULL;
163 composite->start_offsets = NULL;
164 composite->end_offsets = NULL;
171 tvb_new(tvbuff_type type)
175 tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
183 /* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
185 tvb_free_void(void *tvb)
187 tvb_free((tvbuff_t*)tvb);
193 tvb_free(tvbuff_t* tvb)
195 tvbuff_t *member_tvb;
196 tvb_comp_t *composite;
201 if (tvb->usage_count == 0) {
203 case TVBUFF_REAL_DATA:
205 tvb->free_cb(tvb->real_data);
210 /* This will be NULL if tvb_new_subset() fails because
211 * reported_length < -1 */
212 if (tvb->tvbuffs.subset.tvb) {
213 tvb_decrement_usage_count(tvb->tvbuffs.subset.tvb, 1);
217 case TVBUFF_COMPOSITE:
218 composite = &tvb->tvbuffs.composite;
219 for (slist = composite->tvbs; slist != NULL ; slist = slist->next) {
220 member_tvb = slist->data;
221 tvb_decrement_usage_count(member_tvb, 1);
224 g_slist_free(composite->tvbs);
226 if (composite->start_offsets)
227 g_free(composite->start_offsets);
228 if (composite->end_offsets)
229 g_free(composite->end_offsets);
231 g_free(tvb->real_data);
237 g_slist_free(tvb->used_in);
240 g_chunk_free(tvb, tvbuff_mem_chunk);
245 tvb_increment_usage_count(tvbuff_t* tvb, guint count)
247 tvb->usage_count += count;
249 return tvb->usage_count;
253 tvb_decrement_usage_count(tvbuff_t* tvb, guint count)
255 if (tvb->usage_count <= count) {
256 tvb->usage_count = 1;
261 tvb->usage_count -= count;
262 return tvb->usage_count;
268 tvb_free_chain(tvbuff_t* tvb)
272 /* Recursively call tvb_free_chain() */
273 for (slist = tvb->used_in; slist != NULL ; slist = slist->next) {
274 tvb_free_chain( (tvbuff_t*)slist->data );
277 /* Stop the recursion */
284 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
286 g_assert(tvb->type == TVBUFF_REAL_DATA);
291 add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
293 tvb->used_in = g_slist_prepend(tvb->used_in, used_in);
294 tvb_increment_usage_count(tvb, 1);
298 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
300 g_assert(parent->initialized);
301 g_assert(child->initialized);
302 g_assert(child->type == TVBUFF_REAL_DATA);
303 add_to_used_in_list(parent, child);
307 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
309 g_assert(tvb->type == TVBUFF_REAL_DATA);
310 g_assert(!tvb->initialized);
312 if (reported_length < -1) {
313 THROW(ReportedBoundsError);
316 tvb->real_data = (gpointer) data;
317 tvb->length = length;
318 tvb->reported_length = reported_length;
319 tvb->initialized = TRUE;
323 tvb_new_real_data(const guint8* data, guint length, gint reported_length, const gchar* ds_name)
327 tvb = tvb_new(TVBUFF_REAL_DATA);
329 CLEANUP_PUSH(tvb_free_void, tvb);
331 tvb_set_real_data(tvb, data, length, reported_length);
333 /* set the data source name */
334 tvb->ds_name = g_strdup( ds_name);
341 /* Computes the absolute offset and length based on a possibly-negative offset
342 * and a length that is possible -1 (which means "to the end of the data").
343 * Returns TRUE/FALSE indicating whether the offset is in bounds or
344 * not. The integer ptrs are modified with the new offset and length.
345 * No exception is thrown.
347 * XXX - we return TRUE, not FALSE, if the offset is positive and right
348 * after the end of the tvbuff (i.e., equal to the length). We do this
349 * so that a dissector constructing a subset tvbuff for the next protocol
350 * will get a zero-length tvbuff, not an exception, if there's no data
351 * left for the next protocol - we want the next protocol to be the one
352 * that gets an exception, so the error is reported as an error in that
353 * protocol rather than the containing protocol. */
355 compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
356 guint *offset_ptr, guint *length_ptr, int *exception)
358 g_assert(offset_ptr);
359 g_assert(length_ptr);
361 /* Compute the offset */
363 /* Positive offset - relative to the beginning of the packet. */
364 if (offset > tvb->reported_length) {
366 *exception = ReportedBoundsError;
370 else if (offset > tvb->length) {
372 *exception = BoundsError;
377 *offset_ptr = offset;
381 /* Negative offset - relative to the end of the packet. */
382 if (-offset > tvb->reported_length) {
384 *exception = ReportedBoundsError;
388 else if (-offset > tvb->length) {
390 *exception = BoundsError;
395 *offset_ptr = tvb->length + offset;
399 /* Compute the length */
400 g_assert(length >= -1);
402 *length_ptr = tvb->length - *offset_ptr;
405 *length_ptr = length;
413 check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
414 guint *offset_ptr, guint *length_ptr, int *exception)
416 g_assert(tvb->initialized);
418 if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
422 if (*offset_ptr + *length_ptr <= tvb->length) {
425 else if (*offset_ptr + *length_ptr <= tvb->reported_length) {
427 *exception = BoundsError;
433 *exception = ReportedBoundsError;
438 g_assert_not_reached();
441 /* Checks (+/-) offset and length and throws BoundsError if
442 * either is out of bounds. Sets integer ptrs to the new offset
445 check_offset_length(tvbuff_t *tvb, gint offset, gint length,
446 guint *offset_ptr, guint *length_ptr)
450 if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
451 g_assert(exception > 0);
459 tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
460 gint backing_offset, gint backing_length, gint reported_length)
462 g_assert(tvb->type == TVBUFF_SUBSET);
463 g_assert(!tvb->initialized);
465 if (reported_length < -1) {
466 THROW(ReportedBoundsError);
469 check_offset_length(backing, backing_offset, backing_length,
470 &tvb->tvbuffs.subset.offset,
471 &tvb->tvbuffs.subset.length);
473 tvb->tvbuffs.subset.tvb = backing;
474 tvb->length = tvb->tvbuffs.subset.length;
476 if (reported_length == -1) {
477 tvb->reported_length = backing->reported_length - tvb->tvbuffs.subset.offset;
480 tvb->reported_length = reported_length;
482 tvb->initialized = TRUE;
483 add_to_used_in_list(backing, tvb);
485 /* Optimization. If the backing buffer has a pointer to contiguous, real data,
486 * then we can point directly to our starting offset in that buffer */
487 if (backing->real_data != NULL) {
488 tvb->real_data = backing->real_data + tvb->tvbuffs.subset.offset;
494 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
498 tvb = tvb_new(TVBUFF_SUBSET);
500 CLEANUP_PUSH(tvb_free_void, tvb);
502 tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
504 tvb->ds_name = backing->ds_name;
511 tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
513 tvb_comp_t *composite;
515 g_assert(!tvb->initialized);
516 composite = &tvb->tvbuffs.composite;
517 composite->tvbs = g_slist_append( composite->tvbs, member );
518 add_to_used_in_list(member, tvb);
522 tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
524 tvb_comp_t *composite;
526 g_assert(!tvb->initialized);
527 composite = &tvb->tvbuffs.composite;
528 composite->tvbs = g_slist_prepend( composite->tvbs, member );
529 add_to_used_in_list(member, tvb);
533 tvb_new_composite(void)
535 return tvb_new(TVBUFF_COMPOSITE);
539 tvb_composite_finalize(tvbuff_t* tvb)
543 tvbuff_t *member_tvb;
544 tvb_comp_t *composite;
547 g_assert(!tvb->initialized);
548 g_assert(tvb->length == 0);
550 composite = &tvb->tvbuffs.composite;
551 num_members = g_slist_length(composite->tvbs);
553 composite->start_offsets = g_new(guint, num_members);
554 composite->end_offsets = g_new(guint, num_members);
556 for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
557 g_assert(i < num_members);
558 member_tvb = slist->data;
559 composite->start_offsets[i] = tvb->length;
560 tvb->length += member_tvb->length;
561 composite->end_offsets[i] = tvb->length - 1;
565 tvb->initialized = TRUE;
571 tvb_length(tvbuff_t* tvb)
573 g_assert(tvb->initialized);
579 tvb_length_remaining(tvbuff_t *tvb, gint offset)
581 guint abs_offset, abs_length;
583 g_assert(tvb->initialized);
585 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
595 /* Validates that 'length' bytes are available starting from
596 * offset (pos/neg). Does not throw BoundsError exception. */
598 tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
600 guint abs_offset, abs_length;
602 g_assert(tvb->initialized);
604 if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
607 if (abs_offset + abs_length <= tvb->length) {
616 tvb_offset_exists(tvbuff_t *tvb, gint offset)
618 guint abs_offset, abs_length;
620 g_assert(tvb->initialized);
621 if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
624 if (abs_offset < tvb->length) {
633 tvb_reported_length(tvbuff_t* tvb)
635 g_assert(tvb->initialized);
637 return tvb->reported_length;
641 tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
643 guint abs_offset, abs_length;
645 g_assert(tvb->initialized);
647 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
648 if (tvb->reported_length >= abs_offset)
649 return tvb->reported_length - abs_offset;
658 /* Set the reported length of a tvbuff to a given value; used for protocols
659 whose headers contain an explicit length and where the calling
660 dissector's payload may include padding as well as the packet for
663 Also adjusts the data length. */
665 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
667 g_assert(tvb->initialized);
669 if (reported_length > tvb->reported_length)
670 THROW(ReportedBoundsError);
672 tvb->reported_length = reported_length;
673 if (reported_length < tvb->length)
674 tvb->length = reported_length;
679 first_real_data_ptr(tvbuff_t *tvb)
684 case TVBUFF_REAL_DATA:
685 return tvb->real_data;
687 member = tvb->tvbuffs.subset.tvb;
688 return first_real_data_ptr(member);
689 case TVBUFF_COMPOSITE:
690 member = tvb->tvbuffs.composite.tvbs->data;
691 return first_real_data_ptr(member);
694 g_assert_not_reached();
699 offset_from_real_beginning(tvbuff_t *tvb, int counter)
704 case TVBUFF_REAL_DATA:
707 member = tvb->tvbuffs.subset.tvb;
708 return offset_from_real_beginning(member, counter + tvb->tvbuffs.subset.offset);
709 case TVBUFF_COMPOSITE:
710 member = tvb->tvbuffs.composite.tvbs->data;
711 return offset_from_real_beginning(member, counter);
714 g_assert_not_reached();
719 tvb_raw_offset(tvbuff_t *tvb)
721 if (tvb->raw_offset == -1) {
722 tvb->raw_offset = offset_from_real_beginning(tvb, 0);
724 return tvb->raw_offset;
728 tvb_compat(tvbuff_t *tvb, const guint8 **pd, int *offset)
730 g_assert(tvb->initialized);
731 *pd = first_real_data_ptr(tvb);
732 *offset = tvb_raw_offset(tvb);
737 composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
739 guint i, num_members;
740 tvb_comp_t *composite;
741 tvbuff_t *member_tvb = NULL;
742 guint member_offset, member_length;
745 g_assert(tvb->type == TVBUFF_COMPOSITE);
747 /* Maybe the range specified by offset/length
748 * is contiguous inside one of the member tvbuffs */
749 composite = &tvb->tvbuffs.composite;
750 num_members = g_slist_length(composite->tvbs);
752 for (i = 0; i < num_members; i++) {
753 if (abs_offset <= composite->end_offsets[i]) {
754 slist = g_slist_nth(composite->tvbs, i);
755 member_tvb = slist->data;
759 g_assert(member_tvb);
761 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
762 abs_length, &member_offset, &member_length, NULL)) {
764 g_assert(!tvb->real_data);
765 return ensure_contiguous(member_tvb, member_offset, member_length);
768 tvb->real_data = tvb_memdup(tvb, 0, -1);
769 return tvb->real_data + abs_offset;
772 g_assert_not_reached();
777 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
779 guint abs_offset, abs_length;
781 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
783 if (tvb->real_data) {
784 return tvb->real_data + abs_offset;
788 case TVBUFF_REAL_DATA:
789 g_assert_not_reached();
791 return ensure_contiguous(tvb->tvbuffs.subset.tvb,
792 abs_offset - tvb->tvbuffs.subset.offset,
794 case TVBUFF_COMPOSITE:
795 return composite_ensure_contiguous(tvb, abs_offset, abs_length);
799 g_assert_not_reached();
804 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
809 for (b = haystack, i = 0; i < haystacklen; i++, b++) {
819 guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
823 guint8 item, *needlep, needle;
825 for (b = haystack, i = 0; i < haystacklen; i++, b++) {
828 while ((needle = *needlep) != '\0') {
840 /************** ACCESSORS **************/
843 composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
845 guint i, num_members;
846 tvb_comp_t *composite;
847 tvbuff_t *member_tvb = NULL;
848 guint member_offset, member_length;
852 g_assert(tvb->type == TVBUFF_COMPOSITE);
854 /* Maybe the range specified by offset/length
855 * is contiguous inside one of the member tvbuffs */
856 composite = &tvb->tvbuffs.composite;
857 num_members = g_slist_length(composite->tvbs);
859 for (i = 0; i < num_members; i++) {
860 if (abs_offset <= composite->end_offsets[i]) {
861 slist = g_slist_nth(composite->tvbs, i);
862 member_tvb = slist->data;
866 g_assert(member_tvb);
868 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
869 abs_length, &member_offset, &member_length, NULL)) {
871 g_assert(!tvb->real_data);
872 return tvb_memcpy(member_tvb, target, member_offset, member_length);
875 /* The requested data is non-contiguous inside
876 * the member tvb. We have to memcpy() the part that's in the member tvb,
877 * then iterate across the other member tvb's, copying their portions
878 * until we have copied all data.
880 retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
881 &member_offset, &member_length, NULL);
884 tvb_memcpy(member_tvb, target, member_offset, member_length);
885 abs_offset += member_length;
886 abs_length -= member_length;
889 if (abs_length > 0) {
890 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
896 g_assert_not_reached();
901 tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
903 guint abs_offset, abs_length;
905 g_assert(length >= -1);
906 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
908 if (tvb->real_data) {
909 return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
913 case TVBUFF_REAL_DATA:
914 g_assert_not_reached();
917 return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
918 abs_offset - tvb->tvbuffs.subset.offset,
921 case TVBUFF_COMPOSITE:
922 return composite_memcpy(tvb, target, offset, length);
925 g_assert_not_reached();
931 tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
933 guint abs_offset, abs_length;
936 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
938 duped = g_malloc(abs_length);
939 return tvb_memcpy(tvb, duped, abs_offset, abs_length);
945 tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
947 return ensure_contiguous(tvb, offset, length);
951 tvb_get_guint8(tvbuff_t *tvb, gint offset)
955 ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
960 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
964 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
969 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
973 ptr = ensure_contiguous(tvb, offset, 3);
978 tvb_get_ntohl(tvbuff_t *tvb, gint offset)
982 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
988 tvb_get_ntohll(tvbuff_t *tvb, gint offset)
992 ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
998 tvb_get_letohs(tvbuff_t *tvb, gint offset)
1002 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
1003 return pletohs(ptr);
1007 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
1011 ptr = ensure_contiguous(tvb, offset, 3);
1012 return pletoh24(ptr);
1016 tvb_get_letohl(tvbuff_t *tvb, gint offset)
1020 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1021 return pletohl(ptr);
1024 #ifdef G_HAVE_GINT64
1026 tvb_get_letohll(tvbuff_t *tvb, gint offset)
1030 ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
1031 return pletohll(ptr);
1036 /* Find first occurence of needle in tvbuff, starting at offset. Searches
1037 * at most maxlength number of bytes; if maxlength is -1, searches to
1039 * Returns the offset of the found needle, or -1 if not found.
1040 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1041 * in that case, -1 will be returned if the boundary is reached before
1042 * finding needle. */
1044 tvb_find_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 needle)
1046 const guint8 *result;
1047 guint abs_offset, junk_length;
1051 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1053 /* Only search to end of tvbuff, w/o throwing exception. */
1054 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1055 if (maxlength == -1) {
1056 /* No maximum length specified; search to end of tvbuff. */
1059 else if (tvbufflen < maxlength) {
1060 /* Maximum length goes past end of tvbuff; search to end
1065 /* Maximum length doesn't go past end of tvbuff; search
1070 /* If we have real data, perform our search now. */
1071 if (tvb->real_data) {
1072 result = guint8_find(tvb->real_data + abs_offset, limit, needle);
1073 if (result == NULL) {
1077 return result - tvb->real_data;
1082 case TVBUFF_REAL_DATA:
1083 g_assert_not_reached();
1086 return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
1087 abs_offset - tvb->tvbuffs.subset.offset,
1090 case TVBUFF_COMPOSITE:
1091 g_assert_not_reached();
1092 /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
1095 g_assert_not_reached();
1099 /* Find first occurence of any of the needles in tvbuff, starting at offset.
1100 * Searches at most maxlength number of bytes; if maxlength is -1, searches
1102 * Returns the offset of the found needle, or -1 if not found.
1103 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1104 * in that case, -1 will be returned if the boundary is reached before
1105 * finding needle. */
1107 tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 *needles)
1109 const guint8 *result;
1110 guint abs_offset, junk_length;
1114 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1116 /* Only search to end of tvbuff, w/o throwing exception. */
1117 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1118 if (maxlength == -1) {
1119 /* No maximum length specified; search to end of tvbuff. */
1122 else if (tvbufflen < maxlength) {
1123 /* Maximum length goes past end of tvbuff; search to end
1128 /* Maximum length doesn't go past end of tvbuff; search
1133 /* If we have real data, perform our search now. */
1134 if (tvb->real_data) {
1135 result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles);
1136 if (result == NULL) {
1140 return result - tvb->real_data;
1145 case TVBUFF_REAL_DATA:
1146 g_assert_not_reached();
1149 return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
1150 abs_offset - tvb->tvbuffs.subset.offset,
1153 case TVBUFF_COMPOSITE:
1154 g_assert_not_reached();
1155 /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
1158 g_assert_not_reached();
1162 /* Find size of stringz (NUL-terminated string) by looking for terminating
1163 * NUL. The size of the string includes the terminating NUL.
1165 * If the NUL isn't found, it throws the appropriate exception.
1168 tvb_strsize(tvbuff_t *tvb, gint offset)
1170 guint abs_offset, junk_length;
1173 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1174 nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
1175 if (nul_offset == -1) {
1177 * OK, we hit the end of the tvbuff, so we should throw
1180 * Did we hit the end of the captured data, or the end
1181 * of the actual data? If there's less captured data
1182 * than actual data, we presumably hit the end of the
1183 * captured data, otherwise we hit the end of the actual
1186 if (tvb_length(tvb) < tvb_reported_length(tvb)) {
1189 THROW(ReportedBoundsError);
1192 return (nul_offset - abs_offset) + 1;
1195 /* Find length of string by looking for end of string ('\0'), up to
1196 * 'maxlength' characters'; if 'maxlength' is -1, searches to end
1198 * Returns -1 if 'maxlength' reached before finding EOS. */
1200 tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
1203 guint abs_offset, junk_length;
1205 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1207 result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
1209 if (result_offset == -1) {
1213 return result_offset - abs_offset;
1218 * Implement strneql etc
1221 /* Call strncmp after checking if enough chars left, otherwise return -1 */
1223 tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1227 ptr = ensure_contiguous(tvb, offset, size);
1230 int cmp = strncmp(ptr, str, size);
1233 * Return 0 if equal, -1 otherwise.
1235 return (cmp == 0 ? 0 : -1);
1238 * Not enough characters in the tvbuff to match the
1245 /* Call strncasecmp after checking if enough chars left, otherwise return -1 */
1247 tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1251 ptr = ensure_contiguous(tvb, offset, size);
1254 int cmp = strncasecmp(ptr, str, size);
1257 * Return 0 if equal, -1 otherwise.
1259 return (cmp == 0 ? 0 : -1);
1262 * Not enough characters in the tvbuff to match the
1270 * Format the data in the tvb from offset for length ...
1274 tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
1279 if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
1281 len = tvb_length_remaining(tvb, offset);
1282 ptr = ensure_contiguous(tvb, offset, len);
1286 return format_text(ptr, len);
1290 /* Looks for a stringz (NUL-terminated string) in tvbuff and copies
1291 * no more than maxlength number of bytes, including terminating NUL, to buffer.
1292 * Returns length of string (not including terminating NUL), or -1 if the string was
1293 * truncated in the buffer due to not having reached the terminating NUL.
1294 * In this way, it acts like snprintf().
1297 tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1300 guint abs_offset, junk_length;
1303 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1305 if (maxlength == 0) {
1310 /* Only copy to end of tvbuff, w/o throwing exception. */
1311 if (tvb_length_remaining(tvb, abs_offset) < maxlength) {
1312 limit = maxlength - (tvb_length(tvb) - abs_offset);
1318 stringlen = tvb_strnlen(tvb, abs_offset, limit);
1320 /* If NUL wasn't found, copy the data and return -1 */
1321 if (stringlen == -1) {
1322 tvb_memcpy(tvb, buffer, abs_offset, limit);
1326 /* Copy the string to buffer */
1327 tvb_memcpy(tvb, buffer, abs_offset, stringlen + 1);
1331 /* Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to
1332 * have a terminating NUL. If the string was truncated when copied into buffer,
1333 * a NUL is placed at the end of buffer to terminate it.
1336 tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1340 len = tvb_get_nstringz(tvb, offset, maxlength, buffer);
1343 buffer[maxlength] = 0;
1344 return maxlength - 1;
1352 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1353 * at that offset (which may be -1 for "all the way to the end of the
1354 * tvbuff"), find the end of the (putative) line that starts at the
1355 * specified offset in the tvbuff, going no further than the specified
1358 * Return the length of the line (not counting the line terminator at
1359 * the end), or the amount of data remaining in the buffer if we don't
1360 * find a line terminator.
1362 * Set "*next_offset" to the offset of the character past the line
1363 * terminator, or past the end of the buffer if we don't find a line
1367 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset)
1374 len = tvb_length_remaining(tvb, offset);
1376 * XXX - what if "len" is still -1, meaning "offset is past the
1377 * end of the tvbuff"?
1379 eob_offset = offset + len;
1382 * Look either for a CR or an LF.
1384 eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n");
1385 if (eol_offset == -1) {
1387 * No CR or LF - line is presumably continued in next packet.
1388 * We pretend the line runs to the end of the tvbuff.
1390 linelen = eob_offset - offset;
1391 *next_offset = eob_offset;
1394 * Find the number of bytes between the starting offset
1397 linelen = eol_offset - offset;
1402 if (tvb_get_guint8(tvb, eol_offset) == '\r') {
1404 * Yes - is it followed by an LF?
1406 if (eol_offset + 1 < eob_offset &&
1407 tvb_get_guint8(tvb, eol_offset + 1) == '\n') {
1409 * Yes; skip over the CR.
1416 * Return the offset of the character after the last
1417 * character in the line, skipping over the last character
1418 * in the line terminator.
1420 *next_offset = eol_offset + 1;
1426 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1427 * at that offset (which may be -1 for "all the way to the end of the
1428 * tvbuff"), find the end of the (putative) line that starts at the
1429 * specified offset in the tvbuff, going no further than the specified
1432 * However, treat quoted strings inside the buffer specially - don't
1433 * treat newlines in quoted strings as line terminators.
1435 * Return the length of the line (not counting the line terminator at
1436 * the end), or the amount of data remaining in the buffer if we don't
1437 * find a line terminator.
1439 * Set "*next_offset" to the offset of the character past the line
1440 * terminator, or past the end of the buffer if we don't find a line
1444 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
1447 gint cur_offset, char_offset;
1454 len = tvb_length_remaining(tvb, offset);
1456 * XXX - what if "len" is still -1, meaning "offset is past the
1457 * end of the tvbuff"?
1459 eob_offset = offset + len;
1461 cur_offset = offset;
1465 * Is this part of the string quoted?
1469 * Yes - look only for the terminating quote.
1471 char_offset = tvb_find_guint8(tvb, cur_offset, len,
1475 * Look either for a CR, an LF, or a '"'.
1477 char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
1480 if (char_offset == -1) {
1482 * Not found - line is presumably continued in
1484 * We pretend the line runs to the end of the tvbuff.
1486 linelen = eob_offset - offset;
1487 *next_offset = eob_offset;
1493 * We're processing a quoted string.
1494 * We only looked for ", so we know it's a ";
1495 * as we're processing a quoted string, it's a
1503 c = tvb_get_guint8(tvb, char_offset);
1506 * Un-quoted "; it begins a quoted
1512 * It's a CR or LF; we've found a line
1515 * Find the number of bytes between the
1516 * starting offset and the CR or LF.
1518 linelen = char_offset - offset;
1525 * Yes; is it followed by an LF?
1527 if (char_offset + 1 < eob_offset &&
1528 tvb_get_guint8(tvb, char_offset + 1)
1531 * Yes; skip over the CR.
1538 * Return the offset of the character after
1539 * the last character in the line, skipping
1540 * over the last character in the line
1541 * terminator, and quit.
1543 *next_offset = char_offset + 1;
1549 * Step past the character we found.
1551 cur_offset = char_offset + 1;
1552 if (cur_offset >= eob_offset) {
1554 * The character we found was the last character
1555 * in the tvbuff - line is presumably continued in
1557 * We pretend the line runs to the end of the tvbuff.
1559 linelen = eob_offset - offset;
1560 *next_offset = eob_offset;
1568 * Format a bunch of data from a tvbuff as bytes, returning a pointer
1569 * to the string with the formatted data.
1572 tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
1574 return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
1578 tvb_get_name(tvbuff_t* tvb)
1580 return tvb->ds_name;