Fix a comment, and update Gerald's e-mail address.
[obnox/wireshark/wip.git] / epan / tvbuff.c
1 /* tvbuff.c
2  *
3  * Testy, Virtual(-izable) Buffer of guint8*'s
4  * 
5  * "Testy" -- the buffer gets mad when an attempt to access data
6  *              beyond the bounds of the buffer. An exception is thrown.
7  *
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
10  *              other tvbuffs.
11  *
12  * $Id: tvbuff.c,v 1.17 2001/05/27 21:34:05 guy Exp $
13  *
14  * Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
15  *
16  * Ethereal - Network traffic analyzer
17  * By Gerald Combs <gerald@ethereal.com>
18  * Copyright 1998 Gerald Combs
19  * 
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.
24  * 
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.
29  * 
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.
33  */
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <string.h>
40
41 #include "pint.h"
42 #include "tvbuff.h"
43 #include "strutil.h"
44
45 typedef struct {
46         /* The backing tvbuff_t */
47         tvbuff_t        *tvb;
48
49         /* The offset/length of 'tvb' to which I'm privy */
50         guint           offset;
51         guint           length;
52
53 } tvb_backing_t;
54
55 typedef struct {
56         GSList          *tvbs;
57
58         /* Used for quick testing to see if this
59          * is the tvbuff that a COMPOSITE is
60          * interested in. */
61         guint           *start_offsets;
62         guint           *end_offsets;
63
64 } tvb_comp_t;
65
66 struct tvbuff {
67         /* Record-keeping */
68         tvbuff_type             type;
69         gboolean                initialized;
70         guint                   usage_count;
71         gchar*                  ds_name;          /* data source name */
72
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) */
76         GSList                  *used_in;
77
78         /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track
79          * of the other tvbuff's they use */
80         union {
81                 tvb_backing_t   subset;
82                 tvb_comp_t      composite;
83         } tvbuffs;
84
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
89          * to tvb_get_ptr().
90          */
91         guint8                  *real_data;
92
93         /* Length of virtual buffer (and/or real_data). */
94         guint                   length;
95
96         /* Reported length. */
97         guint                   reported_length;
98
99         /* Offset from beginning of first TVBUFF_REAL. */
100         gint                    raw_offset;
101
102         /* Func to call when actually freed */
103         tvbuff_free_cb_t        free_cb;
104 };
105
106 static guint8*
107 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length);
108
109 /* We dole out tvbuff's from this memchunk. */
110 GMemChunk *tvbuff_mem_chunk = NULL;
111
112 void
113 tvbuff_init(void)
114 {
115         if (!tvbuff_mem_chunk)
116                 tvbuff_mem_chunk = g_mem_chunk_create(tvbuff_t, 20, G_ALLOC_AND_FREE);
117 }
118
119 void
120 tvbuff_cleanup(void)
121 {
122         if (tvbuff_mem_chunk)
123                 g_mem_chunk_destroy(tvbuff_mem_chunk);
124
125         tvbuff_mem_chunk = NULL;
126 }
127
128
129
130
131 static void
132 tvb_init(tvbuff_t *tvb, tvbuff_type type)
133 {
134         tvb_backing_t   *backing;
135         tvb_comp_t      *composite;
136
137         tvb->type               = type;
138         tvb->initialized        = FALSE;
139         tvb->usage_count        = 1;
140         tvb->length             = 0;
141         tvb->reported_length    = 0;
142         tvb->free_cb            = NULL;
143         tvb->real_data          = NULL;
144         tvb->raw_offset         = -1;
145         tvb->used_in            = NULL;
146
147         switch(type) {
148                 case TVBUFF_REAL_DATA:
149                         /* Nothing */
150                         break;
151
152                 case TVBUFF_SUBSET:
153                         backing = &tvb->tvbuffs.subset;
154                         backing->tvb    = NULL;
155                         backing->offset = 0;
156                         backing->length = 0;
157                         break;
158
159                 case TVBUFF_COMPOSITE:
160                         composite = &tvb->tvbuffs.composite;
161                         composite->tvbs                 = NULL;
162                         composite->start_offsets        = NULL;
163                         composite->end_offsets          = NULL;
164                         break;
165         }
166 }
167
168
169 tvbuff_t*
170 tvb_new(tvbuff_type type)
171 {
172         tvbuff_t        *tvb;
173
174         tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
175         g_assert(tvb);
176
177         tvb_init(tvb, type);
178
179         return tvb;
180 }
181
182 /* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
183 static void
184 tvb_free_void(void *tvb)
185 {
186         tvb_free((tvbuff_t*)tvb);
187 }
188
189
190
191 void
192 tvb_free(tvbuff_t* tvb)
193 {
194         tvbuff_t        *member_tvb;
195         tvb_comp_t      *composite;
196         GSList          *slist;
197
198         tvb->usage_count--;
199
200         if (tvb->usage_count == 0) {
201                 switch (tvb->type) {
202                 case TVBUFF_REAL_DATA:
203                         if (tvb->free_cb) {
204                                 tvb->free_cb(tvb->real_data);
205                         }
206                         break;
207
208                 case TVBUFF_SUBSET:
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);
213                         }
214                         break;
215
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);
221                         }
222
223                         g_slist_free(composite->tvbs);
224
225                         if (composite->start_offsets)
226                                 g_free(composite->start_offsets);
227                         if (composite->end_offsets)
228                                 g_free(composite->end_offsets);
229                         if (tvb->real_data)
230                                 g_free(tvb->real_data);
231
232                         break;
233                 }
234
235                 if (tvb->used_in) {
236                         g_slist_free(tvb->used_in);
237                 }
238
239                 g_chunk_free(tvb, tvbuff_mem_chunk);
240         }
241 }
242
243 guint
244 tvb_increment_usage_count(tvbuff_t* tvb, guint count)
245 {
246         tvb->usage_count += count;
247
248         return tvb->usage_count;
249 }
250
251 guint
252 tvb_decrement_usage_count(tvbuff_t* tvb, guint count)
253 {
254         if (tvb->usage_count <= count) {
255                 tvb->usage_count = 1;
256                 tvb_free(tvb);
257                 return 0;
258         }
259         else {
260                 tvb->usage_count -= count;
261                 return tvb->usage_count;
262         }
263
264 }
265
266 void
267 tvb_free_chain(tvbuff_t* tvb)
268 {
269         GSList          *slist;
270
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 );
274         }
275
276         /* Stop the recursion */
277         tvb_free(tvb);
278 }
279
280
281
282 void
283 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
284 {
285         g_assert(tvb->type == TVBUFF_REAL_DATA);
286         tvb->free_cb = func;
287 }
288
289 static void
290 add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
291 {
292         tvb->used_in = g_slist_prepend(tvb->used_in, used_in);
293         tvb_increment_usage_count(tvb, 1);
294 }
295
296 void
297 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
298 {
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);
303 }
304
305 void
306 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
307 {
308         g_assert(tvb->type == TVBUFF_REAL_DATA);
309         g_assert(!tvb->initialized);
310
311         if (reported_length < -1) {
312                 THROW(ReportedBoundsError);
313         }
314
315         tvb->real_data          = (gpointer) data;
316         tvb->length             = length;
317         tvb->reported_length    = reported_length;
318         tvb->initialized        = TRUE;
319 }
320
321 tvbuff_t*
322 tvb_new_real_data(const guint8* data, guint length, gint reported_length, const gchar* ds_name)
323 {
324         tvbuff_t        *tvb;
325
326         tvb = tvb_new(TVBUFF_REAL_DATA);
327
328         CLEANUP_PUSH(tvb_free_void, tvb);
329
330         tvb_set_real_data(tvb, data, length, reported_length);
331
332         /* set the data source name */
333         tvb->ds_name = g_strdup( ds_name);
334
335         CLEANUP_POP;
336
337         return tvb;
338 }
339
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.
345  *
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.  */
353 static gboolean
354 compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
355                 guint *offset_ptr, guint *length_ptr, int *exception)
356 {
357         g_assert(offset_ptr);
358         g_assert(length_ptr);
359
360         /* Compute the offset */
361         if (offset >= 0) {
362                 /* Positive offset - relative to the beginning of the packet. */
363                 if (offset > tvb->reported_length) {
364                         if (exception) {
365                                 *exception = ReportedBoundsError;
366                         }
367                         return FALSE;
368                 }
369                 else if (offset > tvb->length) {
370                         if (exception) {
371                                 *exception = BoundsError;
372                         }
373                         return FALSE;
374                 }
375                 else {
376                         *offset_ptr = offset;
377                 }
378         }
379         else {
380                 /* Negative offset - relative to the end of the packet. */
381                 if (-offset > tvb->reported_length) {
382                         if (exception) {
383                                 *exception = ReportedBoundsError;
384                         }
385                         return FALSE;
386                 }
387                 else if (-offset > tvb->length) {
388                         if (exception) {
389                                 *exception = BoundsError;
390                         }
391                         return FALSE;
392                 }
393                 else {
394                         *offset_ptr = tvb->length + offset;
395                 }
396         }
397
398         /* Compute the length */
399         g_assert(length >= -1);
400         if (length == -1) {
401                 *length_ptr = tvb->length - *offset_ptr;
402         }
403         else {
404                 *length_ptr = length;
405         }
406
407         return TRUE;
408 }
409
410
411 static gboolean
412 check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
413                 guint *offset_ptr, guint *length_ptr, int *exception)
414 {
415         g_assert(tvb->initialized);
416
417         if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
418                 return FALSE;
419         }
420
421         if (*offset_ptr + *length_ptr <= tvb->length) {
422                 return TRUE;
423         }
424         else if (*offset_ptr + *length_ptr <= tvb->reported_length) {
425                 if (exception) {
426                         *exception = BoundsError;
427                 }
428                 return FALSE;
429         }
430         else {
431                 if (exception) {
432                         *exception = ReportedBoundsError;
433                 }
434                 return FALSE;
435         }
436
437         g_assert_not_reached();
438 }
439
440 /* Checks (+/-) offset and length and throws BoundsError if
441  * either is out of bounds. Sets integer ptrs to the new offset
442  * and length. */
443 static void
444 check_offset_length(tvbuff_t *tvb, gint offset, gint length,
445                 guint *offset_ptr, guint *length_ptr)
446 {
447         int exception = 0;
448
449         if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
450                 g_assert(exception > 0);
451                 THROW(exception);
452         }
453         return;
454 }
455
456
457 void
458 tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
459                 gint backing_offset, gint backing_length, gint reported_length)
460 {
461         g_assert(tvb->type == TVBUFF_SUBSET);
462         g_assert(!tvb->initialized);
463
464         if (reported_length < -1) {
465                 THROW(ReportedBoundsError);
466         }
467
468         check_offset_length(backing, backing_offset, backing_length,
469                         &tvb->tvbuffs.subset.offset,
470                         &tvb->tvbuffs.subset.length);
471
472         tvb->tvbuffs.subset.tvb         = backing;
473         tvb->length                     = tvb->tvbuffs.subset.length;
474
475         if (reported_length == -1) {
476                 tvb->reported_length    = backing->reported_length - tvb->tvbuffs.subset.offset;
477         }
478         else {
479                 tvb->reported_length    = reported_length;
480         }
481         tvb->initialized                = TRUE;
482         add_to_used_in_list(backing, tvb);
483
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;
488         }
489 }
490
491
492 tvbuff_t*
493 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
494 {
495         tvbuff_t        *tvb;
496
497         tvb = tvb_new(TVBUFF_SUBSET);
498
499         CLEANUP_PUSH(tvb_free_void, tvb);
500
501         tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
502
503         tvb->ds_name = backing->ds_name;
504         CLEANUP_POP;
505
506         return tvb;
507 }
508
509 void
510 tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
511 {
512         tvb_comp_t      *composite;
513
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);
518 }
519
520 void
521 tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
522 {
523         tvb_comp_t      *composite;
524
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);
529 }
530
531 tvbuff_t*
532 tvb_new_composite(void)
533 {
534         return tvb_new(TVBUFF_COMPOSITE);
535 }
536
537 void
538 tvb_composite_finalize(tvbuff_t* tvb)
539 {
540         GSList          *slist;
541         guint           num_members;
542         tvbuff_t        *member_tvb;
543         tvb_comp_t      *composite;
544         int             i = 0;
545
546         g_assert(!tvb->initialized);
547         g_assert(tvb->length == 0);
548
549         composite = &tvb->tvbuffs.composite;
550         num_members = g_slist_length(composite->tvbs);
551
552         composite->start_offsets = g_new(guint, num_members);
553         composite->end_offsets = g_new(guint, num_members);
554
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;
561                 i++;
562         }
563
564         tvb->initialized = TRUE;
565 }
566
567
568
569 guint
570 tvb_length(tvbuff_t* tvb)
571 {
572         g_assert(tvb->initialized);
573
574         return tvb->length;
575 }
576
577 gint
578 tvb_length_remaining(tvbuff_t *tvb, gint offset)
579 {
580         guint   abs_offset, abs_length;
581
582         g_assert(tvb->initialized);
583
584         if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
585                 return abs_length;
586         }
587         else {
588                 return -1;
589         }
590 }
591
592
593
594 /* Validates that 'length' bytes are available starting from
595  * offset (pos/neg). Does not throw BoundsError exception. */
596 gboolean
597 tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
598 {
599         guint           abs_offset, abs_length;
600
601         g_assert(tvb->initialized);
602
603         if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
604                 return FALSE;
605
606         if (abs_offset + abs_length <= tvb->length) {
607                 return TRUE;
608         }
609         else {
610                 return FALSE;
611         }
612 }
613
614 gboolean
615 tvb_offset_exists(tvbuff_t *tvb, gint offset)
616 {
617         guint           abs_offset, abs_length;
618
619         g_assert(tvb->initialized);
620         if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
621                 return FALSE;
622
623         if (abs_offset < tvb->length) {
624                 return TRUE;
625         }
626         else {
627                 return FALSE;
628         }
629 }
630
631 guint
632 tvb_reported_length(tvbuff_t* tvb)
633 {
634         g_assert(tvb->initialized);
635
636         return tvb->reported_length;
637 }
638
639 gint
640 tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
641 {
642         guint   abs_offset, abs_length;
643
644         g_assert(tvb->initialized);
645
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;
649                 else
650                         return -1;
651         }
652         else {
653                 return -1;
654         }
655 }
656
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
660    this protocol.
661
662    Also adjusts the data length. */
663 void
664 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
665 {
666         g_assert(tvb->initialized);
667
668         if (reported_length > tvb->reported_length)
669                 THROW(ReportedBoundsError);
670
671         tvb->reported_length = reported_length;
672         if (reported_length < tvb->length)
673                 tvb->length = reported_length;
674 }
675
676
677 static guint8*
678 first_real_data_ptr(tvbuff_t *tvb)
679 {
680         tvbuff_t        *member;
681
682         switch(tvb->type) {
683                 case TVBUFF_REAL_DATA:
684                         return tvb->real_data;
685                 case TVBUFF_SUBSET:
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);
691         }
692
693         g_assert_not_reached();
694         return NULL;
695 }
696
697 static int
698 offset_from_real_beginning(tvbuff_t *tvb, int counter)
699 {
700         tvbuff_t        *member;
701
702         switch(tvb->type) {
703                 case TVBUFF_REAL_DATA:
704                         return counter;
705                 case TVBUFF_SUBSET:
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);
711         }
712
713         g_assert_not_reached();
714         return 0;
715 }
716
717 gint
718 tvb_raw_offset(tvbuff_t *tvb)
719 {
720         if (tvb->raw_offset == -1) {
721                 tvb->raw_offset = offset_from_real_beginning(tvb, 0);
722         }
723         return tvb->raw_offset;
724 }
725
726 void
727 tvb_compat(tvbuff_t *tvb, const guint8 **pd, int *offset)
728 {
729         g_assert(tvb->initialized);
730         *pd = first_real_data_ptr(tvb);
731         *offset = tvb_raw_offset(tvb);
732 }
733
734
735 static guint8*
736 composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
737 {
738         guint           i, num_members;
739         tvb_comp_t      *composite;
740         tvbuff_t        *member_tvb = NULL;
741         guint           member_offset, member_length;
742         GSList          *slist;
743
744         g_assert(tvb->type == TVBUFF_COMPOSITE);
745
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);
750
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;
755                         break;
756                 }
757         }
758         g_assert(member_tvb);
759
760         if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
761                                 abs_length, &member_offset, &member_length, NULL)) {
762
763                 g_assert(!tvb->real_data);
764                 return ensure_contiguous(member_tvb, member_offset, member_length);
765         }
766         else {
767                 tvb->real_data = tvb_memdup(tvb, 0, -1);
768                 return tvb->real_data + abs_offset;
769         }
770
771         g_assert_not_reached();
772         return NULL;
773 }
774
775 static guint8*
776 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
777 {
778         guint   abs_offset, abs_length;
779
780         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
781
782         if (tvb->real_data) {
783                 return tvb->real_data + abs_offset;
784         }
785         else {
786                 switch(tvb->type) {
787                         case TVBUFF_REAL_DATA:
788                                 g_assert_not_reached();
789                         case TVBUFF_SUBSET:
790                                 return ensure_contiguous(tvb->tvbuffs.subset.tvb,
791                                                 abs_offset - tvb->tvbuffs.subset.offset,
792                                                 abs_length);
793                         case TVBUFF_COMPOSITE:
794                                 return composite_ensure_contiguous(tvb, abs_offset, abs_length);
795                 }
796         }
797
798         g_assert_not_reached();
799         return NULL;
800 }
801
802 static const guint8*
803 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
804 {
805         const guint8    *b;
806         int             i;
807
808         for (b = haystack, i = 0; i < haystacklen; i++, b++) {
809                 if (*b == needle) {
810                         return b;
811                 }
812         }
813
814         return NULL;
815 }
816
817 static const guint8*
818 guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
819 {
820         const guint8    *b;
821         int             i;
822         guint8          item, *needlep, needle;
823
824         for (b = haystack, i = 0; i < haystacklen; i++, b++) {
825                 item = *b;
826                 needlep = needles;
827                 while ((needle = *needlep) != '\0') {
828                         if (item == needle)
829                                 return b;
830                         needlep++;
831                 }
832         }
833
834         return NULL;
835 }
836
837
838
839 /************** ACCESSORS **************/
840
841 static guint8*
842 composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
843 {
844         guint           i, num_members;
845         tvb_comp_t      *composite;
846         tvbuff_t        *member_tvb = NULL;
847         guint           member_offset, member_length;
848         gboolean        retval;
849         GSList          *slist;
850
851         g_assert(tvb->type == TVBUFF_COMPOSITE);
852
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);
857
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;
862                         break;
863                 }
864         }
865         g_assert(member_tvb);
866
867         if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
868                                 abs_length, &member_offset, &member_length, NULL)) {
869
870                 g_assert(!tvb->real_data);
871                 return tvb_memcpy(member_tvb, target, member_offset, member_length);
872         }
873         else {
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.
878                  */
879                 retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
880                                 &member_offset, &member_length, NULL);
881                 g_assert(retval);
882
883                 tvb_memcpy(member_tvb, target, member_offset, member_length);
884                 abs_offset      += member_length;
885                 abs_length      -= member_length;
886
887                 /* Recurse */
888                 if (abs_length > 0) {
889                         composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
890                 }
891
892                 return target;
893         }
894
895         g_assert_not_reached();
896         return NULL;
897 }
898
899 guint8*
900 tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
901 {
902         guint   abs_offset, abs_length;
903
904         g_assert(length >= -1);
905         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
906
907         if (tvb->real_data) {
908                 return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
909         }
910
911         switch(tvb->type) {
912                 case TVBUFF_REAL_DATA:
913                         g_assert_not_reached();
914
915                 case TVBUFF_SUBSET:
916                         return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
917                                         abs_offset - tvb->tvbuffs.subset.offset,
918                                         abs_length);
919
920                 case TVBUFF_COMPOSITE:
921                         return composite_memcpy(tvb, target, offset, length);
922         }
923
924         g_assert_not_reached();
925         return NULL;
926 }
927
928
929 guint8*
930 tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
931 {
932         guint   abs_offset, abs_length;
933         guint8  *duped;
934
935         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
936
937         duped = g_malloc(abs_length);
938         return tvb_memcpy(tvb, duped, abs_offset, abs_length);
939 }
940
941
942         
943 const guint8*
944 tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
945 {
946         return ensure_contiguous(tvb, offset, length);
947 }
948
949 guint8
950 tvb_get_guint8(tvbuff_t *tvb, gint offset)
951 {
952         guint8* ptr;
953
954         ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
955         return *ptr;
956 }
957
958 guint16
959 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
960 {
961         guint8* ptr;
962
963         ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
964         return pntohs(ptr);
965 }
966
967 guint32
968 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
969 {
970         guint8* ptr;
971
972         ptr = ensure_contiguous(tvb, offset, 3);
973         return pntoh24(ptr);
974 }
975
976 guint32
977 tvb_get_ntohl(tvbuff_t *tvb, gint offset)
978 {
979         guint8* ptr;
980
981         ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
982         return pntohl(ptr);
983 }
984
985 #ifdef G_HAVE_GINT64
986 guint64
987 tvb_get_ntohll(tvbuff_t *tvb, gint offset)
988 {
989         guint8* ptr;
990
991         ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
992         return pntohll(ptr);
993 }
994 #endif
995
996 guint16
997 tvb_get_letohs(tvbuff_t *tvb, gint offset)
998 {
999         guint8* ptr;
1000
1001         ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
1002         return pletohs(ptr);
1003 }
1004
1005 guint32
1006 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
1007 {
1008         guint8* ptr;
1009
1010         ptr = ensure_contiguous(tvb, offset, 3);
1011         return pletoh24(ptr);
1012 }
1013
1014 guint32
1015 tvb_get_letohl(tvbuff_t *tvb, gint offset)
1016 {
1017         guint8* ptr;
1018
1019         ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1020         return pletohl(ptr);
1021 }
1022
1023 #ifdef G_HAVE_GINT64
1024 guint64
1025 tvb_get_letohll(tvbuff_t *tvb, gint offset)
1026 {
1027         guint8* ptr;
1028
1029         ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
1030         return pletohll(ptr);
1031 }
1032 #endif
1033
1034
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
1037  * end of tvbuff.
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. */
1042 gint
1043 tvb_find_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 needle)
1044 {
1045         const guint8    *result;
1046         guint           abs_offset, junk_length;
1047         guint           tvbufflen;
1048         guint           limit;
1049
1050         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1051
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. */
1056                 limit = tvbufflen;
1057         }
1058         else if (tvbufflen < maxlength) {
1059                 /* Maximum length goes past end of tvbuff; search to end
1060                    of tvbuff. */
1061                 limit = tvbufflen;
1062         }
1063         else {
1064                 /* Maximum length doesn't go past end of tvbuff; search
1065                    to that value. */
1066                 limit = maxlength;
1067         }
1068
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) {
1073                         return -1;
1074                 }
1075                 else {
1076                         return result - tvb->real_data;
1077                 }
1078         }
1079
1080         switch(tvb->type) {
1081                 case TVBUFF_REAL_DATA:
1082                         g_assert_not_reached();
1083
1084                 case TVBUFF_SUBSET:
1085                         return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
1086                                         abs_offset - tvb->tvbuffs.subset.offset,
1087                                         limit, needle);
1088
1089                 case TVBUFF_COMPOSITE:
1090                         g_assert_not_reached();
1091                         /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
1092         }
1093
1094         g_assert_not_reached();
1095         return -1;
1096 }
1097
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
1100  * to end of tvbuff.
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. */
1105 gint
1106 tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, guint maxlength, guint8 *needles)
1107 {
1108         const guint8    *result;
1109         guint           abs_offset, junk_length;
1110         guint           tvbufflen;
1111         guint           limit;
1112
1113         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1114
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. */
1119                 limit = tvbufflen;
1120         }
1121         else if (tvbufflen < maxlength) {
1122                 /* Maximum length goes past end of tvbuff; search to end
1123                    of tvbuff. */
1124                 limit = tvbufflen;
1125         }
1126         else {
1127                 /* Maximum length doesn't go past end of tvbuff; search
1128                    to that value. */
1129                 limit = maxlength;
1130         }
1131
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) {
1136                         return -1;
1137                 }
1138                 else {
1139                         return result - tvb->real_data;
1140                 }
1141         }
1142
1143         switch(tvb->type) {
1144                 case TVBUFF_REAL_DATA:
1145                         g_assert_not_reached();
1146
1147                 case TVBUFF_SUBSET:
1148                         return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
1149                                         abs_offset - tvb->tvbuffs.subset.offset,
1150                                         limit, needles);
1151
1152                 case TVBUFF_COMPOSITE:
1153                         g_assert_not_reached();
1154                         /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
1155         }
1156
1157         g_assert_not_reached();
1158         return -1;
1159 }
1160
1161 /* Find size of stringz (NUL-terminated string) by looking for terminating
1162  * NUL.  The size of the string includes the terminating NUL.
1163  *
1164  * If the NUL isn't found, it throws the appropriate exception.
1165  */
1166 guint
1167 tvb_strsize(tvbuff_t *tvb, gint offset)
1168 {
1169         guint   abs_offset, junk_length;
1170         gint    nul_offset;
1171
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) {
1175                 /*
1176                  * OK, we hit the end of the tvbuff, so we should throw
1177                  * an exception.
1178                  *
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
1183                  * data.
1184                  */
1185                 if (tvb_length(tvb) < tvb_reported_length(tvb)) {
1186                         THROW(BoundsError);
1187                 } else {
1188                         THROW(ReportedBoundsError);
1189                 }
1190         }
1191         return (nul_offset - abs_offset) + 1;
1192 }
1193
1194 /* Find length of string by looking for end of string ('\0'), up to
1195  * 'maxlength' characters'; if 'maxlength' is -1, searches to end
1196  * of tvbuff.
1197  * Returns -1 if 'maxlength' reached before finding EOS. */
1198 gint
1199 tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
1200 {
1201         gint    result_offset;
1202         guint   abs_offset, junk_length;
1203
1204         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1205
1206         result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
1207
1208         if (result_offset == -1) {
1209                 return -1;
1210         }
1211         else {
1212                 return result_offset - abs_offset;
1213         }
1214 }
1215
1216 /*
1217  * Implement strneql etc
1218  */
1219
1220 /* Call strncmp after checking if enough chars left, otherwise return -1 */
1221 gint
1222 tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1223 {
1224         guint8 *ptr;
1225
1226         ptr = ensure_contiguous(tvb, offset, size);
1227
1228         if (ptr) {
1229                 int cmp = strncmp(ptr, str, size);
1230
1231                 /*
1232                  * Return 0 if equal, -1 otherwise.
1233                  */
1234                 return (cmp == 0 ? 0 : -1);
1235         } else {
1236                 /*
1237                  * Not enough characters in the tvbuff to match the
1238                  * string.
1239                  */
1240                 return -1;
1241         }
1242 }
1243
1244 /* Call strncasecmp after checking if enough chars left, otherwise return -1 */
1245 gint
1246 tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1247 {
1248         guint8 *ptr;
1249
1250         ptr = ensure_contiguous(tvb, offset, size);
1251
1252         if (ptr) {
1253                 int cmp = strncasecmp(ptr, str, size);
1254
1255                 /*
1256                  * Return 0 if equal, -1 otherwise.
1257                  */
1258                 return (cmp == 0 ? 0 : -1);
1259         } else {
1260                 /*
1261                  * Not enough characters in the tvbuff to match the
1262                  * string.
1263                  */
1264                 return -1;
1265         }
1266 }
1267
1268 /*
1269  * Format the data in the tvb from offset for length ...
1270  */
1271
1272 guint8 *
1273 tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
1274 {
1275   guint8 *ptr;
1276   gint len = size;
1277
1278   if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
1279
1280     len = tvb_length_remaining(tvb, offset);
1281     ptr = ensure_contiguous(tvb, offset, len);
1282
1283   }
1284
1285   return format_text(ptr, len);
1286  
1287 }
1288
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().
1294  */
1295 gint
1296 tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1297 {
1298         gint    stringlen;
1299         guint   abs_offset, junk_length;
1300         gint    limit;
1301
1302         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1303
1304         if (maxlength == 0) {
1305                 buffer[0] = 0;
1306                 return 0;
1307         }
1308
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);
1312         }
1313         else {
1314                 limit = maxlength;
1315         }
1316
1317         stringlen = tvb_strnlen(tvb, abs_offset, limit);
1318
1319         /* If NUL wasn't found, copy the data and return -1 */
1320         if (stringlen == -1) {
1321                 tvb_memcpy(tvb, buffer, abs_offset, limit);
1322                 return -1;
1323         }
1324
1325         /* Copy the string to buffer */
1326         tvb_memcpy(tvb, buffer, abs_offset, stringlen + 1);
1327         return stringlen;
1328 }
1329
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.
1333  */
1334 gint
1335 tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1336 {
1337         gint    len;
1338
1339         len = tvb_get_nstringz(tvb, offset, maxlength, buffer);
1340
1341         if (len == -1) {
1342                 buffer[maxlength] = 0;
1343                 return maxlength - 1;
1344         }
1345         else {
1346                 return len;
1347         }
1348 }
1349
1350 /*
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
1355  * length.
1356  *
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.
1360  *
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
1363  * terminator.
1364  */
1365 gint
1366 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset)
1367 {
1368         gint eob_offset;
1369         gint eol_offset;
1370         int linelen;
1371
1372         if (len == -1)
1373                 len = tvb_length_remaining(tvb, offset);
1374         /*
1375          * XXX - what if "len" is still -1, meaning "offset is past the
1376          * end of the tvbuff"?
1377          */
1378         eob_offset = offset + len;
1379
1380         /*
1381          * Look either for a CR or an LF.
1382          */
1383         eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n");
1384         if (eol_offset == -1) {
1385                 /*
1386                  * No CR or LF - line is presumably continued in next packet.
1387                  * We pretend the line runs to the end of the tvbuff.
1388                  */
1389                 linelen = eob_offset - offset;
1390                 *next_offset = eob_offset;
1391         } else {
1392                 /*
1393                  * Find the number of bytes between the starting offset
1394                  * and the CR or LF.
1395                  */
1396                 linelen = eol_offset - offset;
1397
1398                 /*
1399                  * Is it a CR?
1400                  */
1401                 if (tvb_get_guint8(tvb, eol_offset) == '\r') {
1402                         /*
1403                          * Yes - is it followed by an LF?
1404                          */
1405                         if (eol_offset + 1 < eob_offset &&
1406                             tvb_get_guint8(tvb, eol_offset + 1) == '\n') {
1407                                 /*
1408                                  * Yes; skip over the CR.
1409                                  */
1410                                 eol_offset++;
1411                         }
1412                 }
1413
1414                 /*
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.
1418                  */
1419                 *next_offset = eol_offset + 1;
1420         }
1421         return linelen;
1422 }
1423
1424 /*
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
1429  * length.
1430  *
1431  * However, treat quoted strings inside the buffer specially - don't
1432  * treat newlines in quoted strings as line terminators.
1433  *
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.
1437  *
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
1440  * terminator.
1441  */
1442 gint
1443 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
1444     gint *next_offset)
1445 {
1446         gint cur_offset, char_offset;
1447         gboolean is_quoted;
1448         u_char c;
1449         gint eob_offset;
1450         int linelen;
1451
1452         if (len == -1)
1453                 len = tvb_length_remaining(tvb, offset);
1454         /*
1455          * XXX - what if "len" is still -1, meaning "offset is past the
1456          * end of the tvbuff"?
1457          */
1458         eob_offset = offset + len;
1459
1460         cur_offset = offset;
1461         is_quoted = FALSE;
1462         for (;;) {
1463                 /*
1464                  * Is this part of the string quoted?
1465                  */
1466                 if (is_quoted) {
1467                         /*
1468                          * Yes - look only for the terminating quote.
1469                          */
1470                         char_offset = tvb_find_guint8(tvb, cur_offset, len,
1471                             '"');
1472                 } else {
1473                         /*
1474                          * Look either for a CR, an LF, or a '"'.
1475                          */
1476                         char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
1477                             "\r\n\"");
1478                 }
1479                 if (char_offset == -1) {
1480                         /*
1481                          * Not found - line is presumably continued in
1482                          * next packet.
1483                          * We pretend the line runs to the end of the tvbuff.
1484                          */
1485                         linelen = eob_offset - offset;
1486                         *next_offset = eob_offset;
1487                         break;
1488                 }
1489                         
1490                 if (is_quoted) {
1491                         /*
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
1495                          * closing quote.
1496                          */
1497                         is_quoted = FALSE;
1498                 } else {
1499                         /*
1500                          * OK, what is it?
1501                          */
1502                         c = tvb_get_guint8(tvb, char_offset);
1503                         if (c == '"') {
1504                                 /*
1505                                  * Un-quoted "; it begins a quoted
1506                                  * string.
1507                                  */
1508                                 is_quoted = TRUE;
1509                         } else {
1510                                 /*
1511                                  * It's a CR or LF; we've found a line
1512                                  * terminator.
1513                                  *
1514                                  * Find the number of bytes between the
1515                                  * starting offset and the CR or LF.
1516                                  */
1517                                 linelen = char_offset - offset;
1518
1519                                 /*
1520                                  * Is it a CR?
1521                                  */
1522                                 if (c == '\r') {
1523                                         /*
1524                                          * Yes; is it followed by an LF?
1525                                          */
1526                                         if (char_offset + 1 < eob_offset &&
1527                                             tvb_get_guint8(tvb, char_offset + 1)
1528                                               == '\n') {
1529                                                 /*
1530                                                  * Yes; skip over the CR.
1531                                                  */
1532                                                 char_offset++;
1533                                         }
1534                                 }
1535
1536                                 /*
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.
1541                                  */
1542                                 *next_offset = char_offset + 1;
1543                                 break;
1544                         }
1545                 }
1546
1547                 /*
1548                  * Step past the character we found.
1549                  */
1550                 cur_offset = char_offset + 1;
1551                 if (cur_offset >= eob_offset) {
1552                         /*
1553                          * The character we found was the last character
1554                          * in the tvbuff - line is presumably continued in
1555                          * next packet.
1556                          * We pretend the line runs to the end of the tvbuff.
1557                          */
1558                         linelen = eob_offset - offset;
1559                         *next_offset = eob_offset;
1560                         break;
1561                 }
1562         }
1563         return linelen;
1564 }
1565
1566 /*
1567  * Format a bunch of data from a tvbuff as bytes, returning a pointer
1568  * to the string with the formatted data.
1569  */
1570 gchar *
1571 tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
1572 {
1573         return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
1574 }
1575
1576 gchar*
1577 tvb_get_name(tvbuff_t* tvb)
1578 {
1579         return tvb->ds_name;
1580 }