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.17 2001/05/27 21:34:05 guy Exp $
14 * Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
16 * Ethereal - Network traffic analyzer
17 * By Gerald Combs <gerald@ethereal.com>
18 * Copyright 1998 Gerald Combs
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version 2
23 * of the License, or (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46 /* The backing tvbuff_t */
49 /* The offset/length of 'tvb' to which I'm privy */
58 /* Used for quick testing to see if this
59 * is the tvbuff that a COMPOSITE is
71 gchar* ds_name; /* data source name */
73 /* The tvbuffs in which this tvbuff is a member
74 * (that is, a backing tvbuff for a TVBUFF_SUBSET
75 * or a member for a TVB_COMPOSITE) */
78 /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track
79 * of the other tvbuff's they use */
85 /* We're either a TVBUFF_REAL_DATA or a
86 * TVBUFF_SUBSET that has a backing buffer that
87 * has real_data != NULL, or a TVBUFF_COMPOSITE
88 * which has flattened its data due to a call
93 /* Length of virtual buffer (and/or real_data). */
96 /* Reported length. */
97 guint reported_length;
99 /* Offset from beginning of first TVBUFF_REAL. */
102 /* Func to call when actually freed */
103 tvbuff_free_cb_t free_cb;
107 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length);
109 /* We dole out tvbuff's from this memchunk. */
110 GMemChunk *tvbuff_mem_chunk = NULL;
115 if (!tvbuff_mem_chunk)
116 tvbuff_mem_chunk = g_mem_chunk_create(tvbuff_t, 20, G_ALLOC_AND_FREE);
122 if (tvbuff_mem_chunk)
123 g_mem_chunk_destroy(tvbuff_mem_chunk);
125 tvbuff_mem_chunk = NULL;
132 tvb_init(tvbuff_t *tvb, tvbuff_type type)
134 tvb_backing_t *backing;
135 tvb_comp_t *composite;
138 tvb->initialized = FALSE;
139 tvb->usage_count = 1;
141 tvb->reported_length = 0;
143 tvb->real_data = NULL;
144 tvb->raw_offset = -1;
148 case TVBUFF_REAL_DATA:
153 backing = &tvb->tvbuffs.subset;
159 case TVBUFF_COMPOSITE:
160 composite = &tvb->tvbuffs.composite;
161 composite->tvbs = NULL;
162 composite->start_offsets = NULL;
163 composite->end_offsets = NULL;
170 tvb_new(tvbuff_type type)
174 tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
182 /* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
184 tvb_free_void(void *tvb)
186 tvb_free((tvbuff_t*)tvb);
192 tvb_free(tvbuff_t* tvb)
194 tvbuff_t *member_tvb;
195 tvb_comp_t *composite;
200 if (tvb->usage_count == 0) {
202 case TVBUFF_REAL_DATA:
204 tvb->free_cb(tvb->real_data);
209 /* This will be NULL if tvb_new_subset() fails because
210 * reported_length < -1 */
211 if (tvb->tvbuffs.subset.tvb) {
212 tvb_decrement_usage_count(tvb->tvbuffs.subset.tvb, 1);
216 case TVBUFF_COMPOSITE:
217 composite = &tvb->tvbuffs.composite;
218 for (slist = composite->tvbs; slist != NULL ; slist = slist->next) {
219 member_tvb = slist->data;
220 tvb_decrement_usage_count(member_tvb, 1);
223 g_slist_free(composite->tvbs);
225 if (composite->start_offsets)
226 g_free(composite->start_offsets);
227 if (composite->end_offsets)
228 g_free(composite->end_offsets);
230 g_free(tvb->real_data);
236 g_slist_free(tvb->used_in);
239 g_chunk_free(tvb, tvbuff_mem_chunk);
244 tvb_increment_usage_count(tvbuff_t* tvb, guint count)
246 tvb->usage_count += count;
248 return tvb->usage_count;
252 tvb_decrement_usage_count(tvbuff_t* tvb, guint count)
254 if (tvb->usage_count <= count) {
255 tvb->usage_count = 1;
260 tvb->usage_count -= count;
261 return tvb->usage_count;
267 tvb_free_chain(tvbuff_t* tvb)
271 /* Recursively call tvb_free_chain() */
272 for (slist = tvb->used_in; slist != NULL ; slist = slist->next) {
273 tvb_free_chain( (tvbuff_t*)slist->data );
276 /* Stop the recursion */
283 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
285 g_assert(tvb->type == TVBUFF_REAL_DATA);
290 add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
292 tvb->used_in = g_slist_prepend(tvb->used_in, used_in);
293 tvb_increment_usage_count(tvb, 1);
297 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
299 g_assert(parent->initialized);
300 g_assert(child->initialized);
301 g_assert(child->type == TVBUFF_REAL_DATA);
302 add_to_used_in_list(parent, child);
306 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
308 g_assert(tvb->type == TVBUFF_REAL_DATA);
309 g_assert(!tvb->initialized);
311 if (reported_length < -1) {
312 THROW(ReportedBoundsError);
315 tvb->real_data = (gpointer) data;
316 tvb->length = length;
317 tvb->reported_length = reported_length;
318 tvb->initialized = TRUE;
322 tvb_new_real_data(const guint8* data, guint length, gint reported_length, const gchar* ds_name)
326 tvb = tvb_new(TVBUFF_REAL_DATA);
328 CLEANUP_PUSH(tvb_free_void, tvb);
330 tvb_set_real_data(tvb, data, length, reported_length);
332 /* set the data source name */
333 tvb->ds_name = g_strdup( ds_name);
340 /* Computes the absolute offset and length based on a possibly-negative offset
341 * and a length that is possible -1 (which means "to the end of the data").
342 * Returns TRUE/FALSE indicating whether the offset is in bounds or
343 * not. The integer ptrs are modified with the new offset and length.
344 * No exception is thrown.
346 * XXX - we return TRUE, not FALSE, if the offset is positive and right
347 * after the end of the tvbuff (i.e., equal to the length). We do this
348 * so that a dissector constructing a subset tvbuff for the next protocol
349 * will get a zero-length tvbuff, not an exception, if there's no data
350 * left for the next protocol - we want the next protocol to be the one
351 * that gets an exception, so the error is reported as an error in that
352 * protocol rather than the containing protocol. */
354 compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
355 guint *offset_ptr, guint *length_ptr, int *exception)
357 g_assert(offset_ptr);
358 g_assert(length_ptr);
360 /* Compute the offset */
362 /* Positive offset - relative to the beginning of the packet. */
363 if (offset > tvb->reported_length) {
365 *exception = ReportedBoundsError;
369 else if (offset > tvb->length) {
371 *exception = BoundsError;
376 *offset_ptr = offset;
380 /* Negative offset - relative to the end of the packet. */
381 if (-offset > tvb->reported_length) {
383 *exception = ReportedBoundsError;
387 else if (-offset > tvb->length) {
389 *exception = BoundsError;
394 *offset_ptr = tvb->length + offset;
398 /* Compute the length */
399 g_assert(length >= -1);
401 *length_ptr = tvb->length - *offset_ptr;
404 *length_ptr = length;
412 check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
413 guint *offset_ptr, guint *length_ptr, int *exception)
415 g_assert(tvb->initialized);
417 if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
421 if (*offset_ptr + *length_ptr <= tvb->length) {
424 else if (*offset_ptr + *length_ptr <= tvb->reported_length) {
426 *exception = BoundsError;
432 *exception = ReportedBoundsError;
437 g_assert_not_reached();
440 /* Checks (+/-) offset and length and throws BoundsError if
441 * either is out of bounds. Sets integer ptrs to the new offset
444 check_offset_length(tvbuff_t *tvb, gint offset, gint length,
445 guint *offset_ptr, guint *length_ptr)
449 if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
450 g_assert(exception > 0);
458 tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
459 gint backing_offset, gint backing_length, gint reported_length)
461 g_assert(tvb->type == TVBUFF_SUBSET);
462 g_assert(!tvb->initialized);
464 if (reported_length < -1) {
465 THROW(ReportedBoundsError);
468 check_offset_length(backing, backing_offset, backing_length,
469 &tvb->tvbuffs.subset.offset,
470 &tvb->tvbuffs.subset.length);
472 tvb->tvbuffs.subset.tvb = backing;
473 tvb->length = tvb->tvbuffs.subset.length;
475 if (reported_length == -1) {
476 tvb->reported_length = backing->reported_length - tvb->tvbuffs.subset.offset;
479 tvb->reported_length = reported_length;
481 tvb->initialized = TRUE;
482 add_to_used_in_list(backing, tvb);
484 /* Optimization. If the backing buffer has a pointer to contiguous, real data,
485 * then we can point directly to our starting offset in that buffer */
486 if (backing->real_data != NULL) {
487 tvb->real_data = backing->real_data + tvb->tvbuffs.subset.offset;
493 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
497 tvb = tvb_new(TVBUFF_SUBSET);
499 CLEANUP_PUSH(tvb_free_void, tvb);
501 tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
503 tvb->ds_name = backing->ds_name;
510 tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
512 tvb_comp_t *composite;
514 g_assert(!tvb->initialized);
515 composite = &tvb->tvbuffs.composite;
516 composite->tvbs = g_slist_append( composite->tvbs, member );
517 add_to_used_in_list(member, tvb);
521 tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
523 tvb_comp_t *composite;
525 g_assert(!tvb->initialized);
526 composite = &tvb->tvbuffs.composite;
527 composite->tvbs = g_slist_prepend( composite->tvbs, member );
528 add_to_used_in_list(member, tvb);
532 tvb_new_composite(void)
534 return tvb_new(TVBUFF_COMPOSITE);
538 tvb_composite_finalize(tvbuff_t* tvb)
542 tvbuff_t *member_tvb;
543 tvb_comp_t *composite;
546 g_assert(!tvb->initialized);
547 g_assert(tvb->length == 0);
549 composite = &tvb->tvbuffs.composite;
550 num_members = g_slist_length(composite->tvbs);
552 composite->start_offsets = g_new(guint, num_members);
553 composite->end_offsets = g_new(guint, num_members);
555 for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
556 g_assert(i < num_members);
557 member_tvb = slist->data;
558 composite->start_offsets[i] = tvb->length;
559 tvb->length += member_tvb->length;
560 composite->end_offsets[i] = tvb->length - 1;
564 tvb->initialized = TRUE;
570 tvb_length(tvbuff_t* tvb)
572 g_assert(tvb->initialized);
578 tvb_length_remaining(tvbuff_t *tvb, gint offset)
580 guint abs_offset, abs_length;
582 g_assert(tvb->initialized);
584 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
594 /* Validates that 'length' bytes are available starting from
595 * offset (pos/neg). Does not throw BoundsError exception. */
597 tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
599 guint abs_offset, abs_length;
601 g_assert(tvb->initialized);
603 if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
606 if (abs_offset + abs_length <= tvb->length) {
615 tvb_offset_exists(tvbuff_t *tvb, gint offset)
617 guint abs_offset, abs_length;
619 g_assert(tvb->initialized);
620 if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
623 if (abs_offset < tvb->length) {
632 tvb_reported_length(tvbuff_t* tvb)
634 g_assert(tvb->initialized);
636 return tvb->reported_length;
640 tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
642 guint abs_offset, abs_length;
644 g_assert(tvb->initialized);
646 if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
647 if (tvb->reported_length >= abs_offset)
648 return tvb->reported_length - abs_offset;
657 /* Set the reported length of a tvbuff to a given value; used for protocols
658 whose headers contain an explicit length and where the calling
659 dissector's payload may include padding as well as the packet for
662 Also adjusts the data length. */
664 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
666 g_assert(tvb->initialized);
668 if (reported_length > tvb->reported_length)
669 THROW(ReportedBoundsError);
671 tvb->reported_length = reported_length;
672 if (reported_length < tvb->length)
673 tvb->length = reported_length;
678 first_real_data_ptr(tvbuff_t *tvb)
683 case TVBUFF_REAL_DATA:
684 return tvb->real_data;
686 member = tvb->tvbuffs.subset.tvb;
687 return first_real_data_ptr(member);
688 case TVBUFF_COMPOSITE:
689 member = tvb->tvbuffs.composite.tvbs->data;
690 return first_real_data_ptr(member);
693 g_assert_not_reached();
698 offset_from_real_beginning(tvbuff_t *tvb, int counter)
703 case TVBUFF_REAL_DATA:
706 member = tvb->tvbuffs.subset.tvb;
707 return offset_from_real_beginning(member, counter + tvb->tvbuffs.subset.offset);
708 case TVBUFF_COMPOSITE:
709 member = tvb->tvbuffs.composite.tvbs->data;
710 return offset_from_real_beginning(member, counter);
713 g_assert_not_reached();
718 tvb_raw_offset(tvbuff_t *tvb)
720 if (tvb->raw_offset == -1) {
721 tvb->raw_offset = offset_from_real_beginning(tvb, 0);
723 return tvb->raw_offset;
727 tvb_compat(tvbuff_t *tvb, const guint8 **pd, int *offset)
729 g_assert(tvb->initialized);
730 *pd = first_real_data_ptr(tvb);
731 *offset = tvb_raw_offset(tvb);
736 composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
738 guint i, num_members;
739 tvb_comp_t *composite;
740 tvbuff_t *member_tvb = NULL;
741 guint member_offset, member_length;
744 g_assert(tvb->type == TVBUFF_COMPOSITE);
746 /* Maybe the range specified by offset/length
747 * is contiguous inside one of the member tvbuffs */
748 composite = &tvb->tvbuffs.composite;
749 num_members = g_slist_length(composite->tvbs);
751 for (i = 0; i < num_members; i++) {
752 if (abs_offset <= composite->end_offsets[i]) {
753 slist = g_slist_nth(composite->tvbs, i);
754 member_tvb = slist->data;
758 g_assert(member_tvb);
760 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
761 abs_length, &member_offset, &member_length, NULL)) {
763 g_assert(!tvb->real_data);
764 return ensure_contiguous(member_tvb, member_offset, member_length);
767 tvb->real_data = tvb_memdup(tvb, 0, -1);
768 return tvb->real_data + abs_offset;
771 g_assert_not_reached();
776 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
778 guint abs_offset, abs_length;
780 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
782 if (tvb->real_data) {
783 return tvb->real_data + abs_offset;
787 case TVBUFF_REAL_DATA:
788 g_assert_not_reached();
790 return ensure_contiguous(tvb->tvbuffs.subset.tvb,
791 abs_offset - tvb->tvbuffs.subset.offset,
793 case TVBUFF_COMPOSITE:
794 return composite_ensure_contiguous(tvb, abs_offset, abs_length);
798 g_assert_not_reached();
803 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
808 for (b = haystack, i = 0; i < haystacklen; i++, b++) {
818 guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
822 guint8 item, *needlep, needle;
824 for (b = haystack, i = 0; i < haystacklen; i++, b++) {
827 while ((needle = *needlep) != '\0') {
839 /************** ACCESSORS **************/
842 composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
844 guint i, num_members;
845 tvb_comp_t *composite;
846 tvbuff_t *member_tvb = NULL;
847 guint member_offset, member_length;
851 g_assert(tvb->type == TVBUFF_COMPOSITE);
853 /* Maybe the range specified by offset/length
854 * is contiguous inside one of the member tvbuffs */
855 composite = &tvb->tvbuffs.composite;
856 num_members = g_slist_length(composite->tvbs);
858 for (i = 0; i < num_members; i++) {
859 if (abs_offset <= composite->end_offsets[i]) {
860 slist = g_slist_nth(composite->tvbs, i);
861 member_tvb = slist->data;
865 g_assert(member_tvb);
867 if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
868 abs_length, &member_offset, &member_length, NULL)) {
870 g_assert(!tvb->real_data);
871 return tvb_memcpy(member_tvb, target, member_offset, member_length);
874 /* The requested data is non-contiguous inside
875 * the member tvb. We have to memcpy() the part that's in the member tvb,
876 * then iterate across the other member tvb's, copying their portions
877 * until we have copied all data.
879 retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
880 &member_offset, &member_length, NULL);
883 tvb_memcpy(member_tvb, target, member_offset, member_length);
884 abs_offset += member_length;
885 abs_length -= member_length;
888 if (abs_length > 0) {
889 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
895 g_assert_not_reached();
900 tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
902 guint abs_offset, abs_length;
904 g_assert(length >= -1);
905 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
907 if (tvb->real_data) {
908 return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
912 case TVBUFF_REAL_DATA:
913 g_assert_not_reached();
916 return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
917 abs_offset - tvb->tvbuffs.subset.offset,
920 case TVBUFF_COMPOSITE:
921 return composite_memcpy(tvb, target, offset, length);
924 g_assert_not_reached();
930 tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
932 guint abs_offset, abs_length;
935 check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
937 duped = g_malloc(abs_length);
938 return tvb_memcpy(tvb, duped, abs_offset, abs_length);
944 tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
946 return ensure_contiguous(tvb, offset, length);
950 tvb_get_guint8(tvbuff_t *tvb, gint offset)
954 ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
959 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
963 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
968 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
972 ptr = ensure_contiguous(tvb, offset, 3);
977 tvb_get_ntohl(tvbuff_t *tvb, gint offset)
981 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
987 tvb_get_ntohll(tvbuff_t *tvb, gint offset)
991 ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
997 tvb_get_letohs(tvbuff_t *tvb, gint offset)
1001 ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
1002 return pletohs(ptr);
1006 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
1010 ptr = ensure_contiguous(tvb, offset, 3);
1011 return pletoh24(ptr);
1015 tvb_get_letohl(tvbuff_t *tvb, gint offset)
1019 ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1020 return pletohl(ptr);
1023 #ifdef G_HAVE_GINT64
1025 tvb_get_letohll(tvbuff_t *tvb, gint offset)
1029 ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
1030 return pletohll(ptr);
1035 /* Find first occurence of needle in tvbuff, starting at offset. Searches
1036 * at most maxlength number of bytes; if maxlength is -1, searches to
1038 * Returns the offset of the found needle, or -1 if not found.
1039 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1040 * in that case, -1 will be returned if the boundary is reached before
1041 * finding needle. */
1043 tvb_find_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 needle)
1045 const guint8 *result;
1046 guint abs_offset, junk_length;
1050 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1052 /* Only search to end of tvbuff, w/o throwing exception. */
1053 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1054 if (maxlength == -1) {
1055 /* No maximum length specified; search to end of tvbuff. */
1058 else if (tvbufflen < maxlength) {
1059 /* Maximum length goes past end of tvbuff; search to end
1064 /* Maximum length doesn't go past end of tvbuff; search
1069 /* If we have real data, perform our search now. */
1070 if (tvb->real_data) {
1071 result = guint8_find(tvb->real_data + abs_offset, limit, needle);
1072 if (result == NULL) {
1076 return result - tvb->real_data;
1081 case TVBUFF_REAL_DATA:
1082 g_assert_not_reached();
1085 return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
1086 abs_offset - tvb->tvbuffs.subset.offset,
1089 case TVBUFF_COMPOSITE:
1090 g_assert_not_reached();
1091 /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
1094 g_assert_not_reached();
1098 /* Find first occurence of any of the needles in tvbuff, starting at offset.
1099 * Searches at most maxlength number of bytes; if maxlength is -1, searches
1101 * Returns the offset of the found needle, or -1 if not found.
1102 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1103 * in that case, -1 will be returned if the boundary is reached before
1104 * finding needle. */
1106 tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 *needles)
1108 const guint8 *result;
1109 guint abs_offset, junk_length;
1113 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1115 /* Only search to end of tvbuff, w/o throwing exception. */
1116 tvbufflen = tvb_length_remaining(tvb, abs_offset);
1117 if (maxlength == -1) {
1118 /* No maximum length specified; search to end of tvbuff. */
1121 else if (tvbufflen < maxlength) {
1122 /* Maximum length goes past end of tvbuff; search to end
1127 /* Maximum length doesn't go past end of tvbuff; search
1132 /* If we have real data, perform our search now. */
1133 if (tvb->real_data) {
1134 result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles);
1135 if (result == NULL) {
1139 return result - tvb->real_data;
1144 case TVBUFF_REAL_DATA:
1145 g_assert_not_reached();
1148 return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
1149 abs_offset - tvb->tvbuffs.subset.offset,
1152 case TVBUFF_COMPOSITE:
1153 g_assert_not_reached();
1154 /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
1157 g_assert_not_reached();
1161 /* Find size of stringz (NUL-terminated string) by looking for terminating
1162 * NUL. The size of the string includes the terminating NUL.
1164 * If the NUL isn't found, it throws the appropriate exception.
1167 tvb_strsize(tvbuff_t *tvb, gint offset)
1169 guint abs_offset, junk_length;
1172 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1173 nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
1174 if (nul_offset == -1) {
1176 * OK, we hit the end of the tvbuff, so we should throw
1179 * Did we hit the end of the captured data, or the end
1180 * of the actual data? If there's less captured data
1181 * than actual data, we presumably hit the end of the
1182 * captured data, otherwise we hit the end of the actual
1185 if (tvb_length(tvb) < tvb_reported_length(tvb)) {
1188 THROW(ReportedBoundsError);
1191 return (nul_offset - abs_offset) + 1;
1194 /* Find length of string by looking for end of string ('\0'), up to
1195 * 'maxlength' characters'; if 'maxlength' is -1, searches to end
1197 * Returns -1 if 'maxlength' reached before finding EOS. */
1199 tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
1202 guint abs_offset, junk_length;
1204 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1206 result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
1208 if (result_offset == -1) {
1212 return result_offset - abs_offset;
1217 * Implement strneql etc
1220 /* Call strncmp after checking if enough chars left, otherwise return -1 */
1222 tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1226 ptr = ensure_contiguous(tvb, offset, size);
1229 int cmp = strncmp(ptr, str, size);
1232 * Return 0 if equal, -1 otherwise.
1234 return (cmp == 0 ? 0 : -1);
1237 * Not enough characters in the tvbuff to match the
1244 /* Call strncasecmp after checking if enough chars left, otherwise return -1 */
1246 tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1250 ptr = ensure_contiguous(tvb, offset, size);
1253 int cmp = strncasecmp(ptr, str, size);
1256 * Return 0 if equal, -1 otherwise.
1258 return (cmp == 0 ? 0 : -1);
1261 * Not enough characters in the tvbuff to match the
1269 * Format the data in the tvb from offset for length ...
1273 tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
1278 if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
1280 len = tvb_length_remaining(tvb, offset);
1281 ptr = ensure_contiguous(tvb, offset, len);
1285 return format_text(ptr, len);
1289 /* Looks for a stringz (NUL-terminated string) in tvbuff and copies
1290 * no more than maxlength number of bytes, including terminating NUL, to buffer.
1291 * Returns length of string (not including terminating NUL), or -1 if the string was
1292 * truncated in the buffer due to not having reached the terminating NUL.
1293 * In this way, it acts like snprintf().
1296 tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1299 guint abs_offset, junk_length;
1302 check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1304 if (maxlength == 0) {
1309 /* Only copy to end of tvbuff, w/o throwing exception. */
1310 if (tvb_length_remaining(tvb, abs_offset) < maxlength) {
1311 limit = maxlength - (tvb_length(tvb) - abs_offset);
1317 stringlen = tvb_strnlen(tvb, abs_offset, limit);
1319 /* If NUL wasn't found, copy the data and return -1 */
1320 if (stringlen == -1) {
1321 tvb_memcpy(tvb, buffer, abs_offset, limit);
1325 /* Copy the string to buffer */
1326 tvb_memcpy(tvb, buffer, abs_offset, stringlen + 1);
1330 /* Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to
1331 * have a terminating NUL. If the string was truncated when copied into buffer,
1332 * a NUL is placed at the end of buffer to terminate it.
1335 tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1339 len = tvb_get_nstringz(tvb, offset, maxlength, buffer);
1342 buffer[maxlength] = 0;
1343 return maxlength - 1;
1351 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1352 * at that offset (which may be -1 for "all the way to the end of the
1353 * tvbuff"), find the end of the (putative) line that starts at the
1354 * specified offset in the tvbuff, going no further than the specified
1357 * Return the length of the line (not counting the line terminator at
1358 * the end), or the amount of data remaining in the buffer if we don't
1359 * find a line terminator.
1361 * Set "*next_offset" to the offset of the character past the line
1362 * terminator, or past the end of the buffer if we don't find a line
1366 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset)
1373 len = tvb_length_remaining(tvb, offset);
1375 * XXX - what if "len" is still -1, meaning "offset is past the
1376 * end of the tvbuff"?
1378 eob_offset = offset + len;
1381 * Look either for a CR or an LF.
1383 eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n");
1384 if (eol_offset == -1) {
1386 * No CR or LF - line is presumably continued in next packet.
1387 * We pretend the line runs to the end of the tvbuff.
1389 linelen = eob_offset - offset;
1390 *next_offset = eob_offset;
1393 * Find the number of bytes between the starting offset
1396 linelen = eol_offset - offset;
1401 if (tvb_get_guint8(tvb, eol_offset) == '\r') {
1403 * Yes - is it followed by an LF?
1405 if (eol_offset + 1 < eob_offset &&
1406 tvb_get_guint8(tvb, eol_offset + 1) == '\n') {
1408 * Yes; skip over the CR.
1415 * Return the offset of the character after the last
1416 * character in the line, skipping over the last character
1417 * in the line terminator.
1419 *next_offset = eol_offset + 1;
1425 * Given a tvbuff, an offset into the tvbuff, and a length that starts
1426 * at that offset (which may be -1 for "all the way to the end of the
1427 * tvbuff"), find the end of the (putative) line that starts at the
1428 * specified offset in the tvbuff, going no further than the specified
1431 * However, treat quoted strings inside the buffer specially - don't
1432 * treat newlines in quoted strings as line terminators.
1434 * Return the length of the line (not counting the line terminator at
1435 * the end), or the amount of data remaining in the buffer if we don't
1436 * find a line terminator.
1438 * Set "*next_offset" to the offset of the character past the line
1439 * terminator, or past the end of the buffer if we don't find a line
1443 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
1446 gint cur_offset, char_offset;
1453 len = tvb_length_remaining(tvb, offset);
1455 * XXX - what if "len" is still -1, meaning "offset is past the
1456 * end of the tvbuff"?
1458 eob_offset = offset + len;
1460 cur_offset = offset;
1464 * Is this part of the string quoted?
1468 * Yes - look only for the terminating quote.
1470 char_offset = tvb_find_guint8(tvb, cur_offset, len,
1474 * Look either for a CR, an LF, or a '"'.
1476 char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
1479 if (char_offset == -1) {
1481 * Not found - line is presumably continued in
1483 * We pretend the line runs to the end of the tvbuff.
1485 linelen = eob_offset - offset;
1486 *next_offset = eob_offset;
1492 * We're processing a quoted string.
1493 * We only looked for ", so we know it's a ";
1494 * as we're processing a quoted string, it's a
1502 c = tvb_get_guint8(tvb, char_offset);
1505 * Un-quoted "; it begins a quoted
1511 * It's a CR or LF; we've found a line
1514 * Find the number of bytes between the
1515 * starting offset and the CR or LF.
1517 linelen = char_offset - offset;
1524 * Yes; is it followed by an LF?
1526 if (char_offset + 1 < eob_offset &&
1527 tvb_get_guint8(tvb, char_offset + 1)
1530 * Yes; skip over the CR.
1537 * Return the offset of the character after
1538 * the last character in the line, skipping
1539 * over the last character in the line
1540 * terminator, and quit.
1542 *next_offset = char_offset + 1;
1548 * Step past the character we found.
1550 cur_offset = char_offset + 1;
1551 if (cur_offset >= eob_offset) {
1553 * The character we found was the last character
1554 * in the tvbuff - line is presumably continued in
1556 * We pretend the line runs to the end of the tvbuff.
1558 linelen = eob_offset - offset;
1559 *next_offset = eob_offset;
1567 * Format a bunch of data from a tvbuff as bytes, returning a pointer
1568 * to the string with the formatted data.
1571 tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
1573 return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
1577 tvb_get_name(tvbuff_t* tvb)
1579 return tvb->ds_name;