d24643e243cf8c3cb1cb54b26be8217959fcfdbe
[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.27 2002/01/04 06:45:14 gram Exp $
13  *
14  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
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         tvb->ds_name            = NULL;
147
148         switch(type) {
149                 case TVBUFF_REAL_DATA:
150                         /* Nothing */
151                         break;
152
153                 case TVBUFF_SUBSET:
154                         backing = &tvb->tvbuffs.subset;
155                         backing->tvb    = NULL;
156                         backing->offset = 0;
157                         backing->length = 0;
158                         break;
159
160                 case TVBUFF_COMPOSITE:
161                         composite = &tvb->tvbuffs.composite;
162                         composite->tvbs                 = NULL;
163                         composite->start_offsets        = NULL;
164                         composite->end_offsets          = NULL;
165                         break;
166         }
167 }
168
169
170 tvbuff_t*
171 tvb_new(tvbuff_type type)
172 {
173         tvbuff_t        *tvb;
174
175         tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
176         g_assert(tvb);
177
178         tvb_init(tvb, type);
179
180         return tvb;
181 }
182
183 /* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
184 static void
185 tvb_free_void(void *tvb)
186 {
187         tvb_free((tvbuff_t*)tvb);
188 }
189
190
191
192 void
193 tvb_free(tvbuff_t* tvb)
194 {
195         tvbuff_t        *member_tvb;
196         tvb_comp_t      *composite;
197         GSList          *slist;
198
199         tvb->usage_count--;
200
201         if (tvb->usage_count == 0) {
202                 switch (tvb->type) {
203                 case TVBUFF_REAL_DATA:
204                         if (tvb->free_cb) {
205                                 tvb->free_cb(tvb->real_data);
206                         }
207                         if (tvb->ds_name)
208                                 g_free(tvb->ds_name);
209                         break;
210
211                 case TVBUFF_SUBSET:
212                         /* This will be NULL if tvb_new_subset() fails because
213                          * reported_length < -1 */
214                         if (tvb->tvbuffs.subset.tvb) {
215                                 tvb_decrement_usage_count(tvb->tvbuffs.subset.tvb, 1);
216                         }
217
218                         /*
219                          * TVBUFF_SUBSET tvbuffs share a "ds_name" with
220                          * the parent tvbuff, so this tvbuff's "ds_name"
221                          * shouldn't be freed.
222                          */
223                         break;
224
225                 case TVBUFF_COMPOSITE:
226                         composite = &tvb->tvbuffs.composite;
227                         for (slist = composite->tvbs; slist != NULL ; slist = slist->next) {
228                                 member_tvb = slist->data;
229                                 tvb_decrement_usage_count(member_tvb, 1);
230                         }
231
232                         g_slist_free(composite->tvbs);
233
234                         if (composite->start_offsets)
235                                 g_free(composite->start_offsets);
236                         if (composite->end_offsets)
237                                 g_free(composite->end_offsets);
238                         if (tvb->real_data)
239                                 g_free(tvb->real_data);
240                         if (tvb->ds_name)
241                                 g_free(tvb->ds_name);
242
243                         break;
244                 }
245
246                 if (tvb->used_in) {
247                         g_slist_free(tvb->used_in);
248                 }
249
250                 g_chunk_free(tvb, tvbuff_mem_chunk);
251         }
252 }
253
254 guint
255 tvb_increment_usage_count(tvbuff_t* tvb, guint count)
256 {
257         tvb->usage_count += count;
258
259         return tvb->usage_count;
260 }
261
262 guint
263 tvb_decrement_usage_count(tvbuff_t* tvb, guint count)
264 {
265         if (tvb->usage_count <= count) {
266                 tvb->usage_count = 1;
267                 tvb_free(tvb);
268                 return 0;
269         }
270         else {
271                 tvb->usage_count -= count;
272                 return tvb->usage_count;
273         }
274
275 }
276
277 void
278 tvb_free_chain(tvbuff_t* tvb)
279 {
280         GSList          *slist;
281
282         /* Recursively call tvb_free_chain() */
283         for (slist = tvb->used_in; slist != NULL ; slist = slist->next) {
284                 tvb_free_chain( (tvbuff_t*)slist->data );
285         }
286
287         /* Stop the recursion */
288         tvb_free(tvb);
289 }
290
291
292
293 void
294 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
295 {
296         g_assert(tvb->type == TVBUFF_REAL_DATA);
297         tvb->free_cb = func;
298 }
299
300 static void
301 add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
302 {
303         tvb->used_in = g_slist_prepend(tvb->used_in, used_in);
304         tvb_increment_usage_count(tvb, 1);
305 }
306
307 void
308 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
309 {
310         g_assert(parent->initialized);
311         g_assert(child->initialized);
312         g_assert(child->type == TVBUFF_REAL_DATA);
313         add_to_used_in_list(parent, child);
314 }
315
316 void
317 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
318 {
319         g_assert(tvb->type == TVBUFF_REAL_DATA);
320         g_assert(!tvb->initialized);
321
322         if (reported_length < -1) {
323                 THROW(ReportedBoundsError);
324         }
325
326         tvb->real_data          = (gpointer) data;
327         tvb->length             = length;
328         tvb->reported_length    = reported_length;
329         tvb->initialized        = TRUE;
330 }
331
332 tvbuff_t*
333 tvb_new_real_data(const guint8* data, guint length, gint reported_length, const gchar* ds_name)
334 {
335         tvbuff_t        *tvb;
336
337         tvb = tvb_new(TVBUFF_REAL_DATA);
338
339         CLEANUP_PUSH(tvb_free_void, tvb);
340
341         tvb_set_real_data(tvb, data, length, reported_length);
342
343         /* set the data source name */
344         tvb->ds_name = g_strdup( ds_name);
345
346         CLEANUP_POP;
347
348         return tvb;
349 }
350
351 /* Computes the absolute offset and length based on a possibly-negative offset
352  * and a length that is possible -1 (which means "to the end of the data").
353  * Returns TRUE/FALSE indicating whether the offset is in bounds or
354  * not. The integer ptrs are modified with the new offset and length.
355  * No exception is thrown.
356  *
357  * XXX - we return TRUE, not FALSE, if the offset is positive and right
358  * after the end of the tvbuff (i.e., equal to the length).  We do this
359  * so that a dissector constructing a subset tvbuff for the next protocol
360  * will get a zero-length tvbuff, not an exception, if there's no data
361  * left for the next protocol - we want the next protocol to be the one
362  * that gets an exception, so the error is reported as an error in that
363  * protocol rather than the containing protocol.  */
364 static gboolean
365 compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
366                 guint *offset_ptr, guint *length_ptr, int *exception)
367 {
368         g_assert(offset_ptr);
369         g_assert(length_ptr);
370
371         /* Compute the offset */
372         if (offset >= 0) {
373                 /* Positive offset - relative to the beginning of the packet. */
374                 if ((guint) offset > tvb->reported_length) {
375                         if (exception) {
376                                 *exception = ReportedBoundsError;
377                         }
378                         return FALSE;
379                 }
380                 else if ((guint) offset > tvb->length) {
381                         if (exception) {
382                                 *exception = BoundsError;
383                         }
384                         return FALSE;
385                 }
386                 else {
387                         *offset_ptr = offset;
388                 }
389         }
390         else {
391                 /* Negative offset - relative to the end of the packet. */
392                 if ((guint) -offset > tvb->reported_length) {
393                         if (exception) {
394                                 *exception = ReportedBoundsError;
395                         }
396                         return FALSE;
397                 }
398                 else if ((guint) -offset > tvb->length) {
399                         if (exception) {
400                                 *exception = BoundsError;
401                         }
402                         return FALSE;
403                 }
404                 else {
405                         *offset_ptr = tvb->length + offset;
406                 }
407         }
408
409         /* Compute the length */
410         if (length < -1) {
411                 return FALSE;
412         }
413         else if (length == -1) {
414                 *length_ptr = tvb->length - *offset_ptr;
415         }
416         else {
417                 *length_ptr = length;
418         }
419
420         return TRUE;
421 }
422
423
424 static gboolean
425 check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
426                 guint *offset_ptr, guint *length_ptr, int *exception)
427 {
428         g_assert(tvb->initialized);
429
430         if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
431                 return FALSE;
432         }
433
434         if (*offset_ptr + *length_ptr <= tvb->length) {
435                 return TRUE;
436         }
437         else if (*offset_ptr + *length_ptr <= tvb->reported_length) {
438                 if (exception) {
439                         *exception = BoundsError;
440                 }
441                 return FALSE;
442         }
443         else {
444                 if (exception) {
445                         *exception = ReportedBoundsError;
446                 }
447                 return FALSE;
448         }
449
450         g_assert_not_reached();
451 }
452
453 /* Checks (+/-) offset and length and throws BoundsError if
454  * either is out of bounds. Sets integer ptrs to the new offset
455  * and length. */
456 static void
457 check_offset_length(tvbuff_t *tvb, gint offset, gint length,
458                 guint *offset_ptr, guint *length_ptr)
459 {
460         int exception = 0;
461
462         if (length < -1) {
463                 THROW(BoundsError);
464         }
465
466         if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
467                 g_assert(exception > 0);
468                 THROW(exception);
469         }
470         return;
471 }
472
473
474 void
475 tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
476                 gint backing_offset, gint backing_length, gint reported_length)
477 {
478         g_assert(tvb->type == TVBUFF_SUBSET);
479         g_assert(!tvb->initialized);
480
481         if (reported_length < -1) {
482                 THROW(ReportedBoundsError);
483         }
484
485         check_offset_length(backing, backing_offset, backing_length,
486                         &tvb->tvbuffs.subset.offset,
487                         &tvb->tvbuffs.subset.length);
488
489         tvb->tvbuffs.subset.tvb         = backing;
490         tvb->length                     = tvb->tvbuffs.subset.length;
491
492         if (reported_length == -1) {
493                 tvb->reported_length    = backing->reported_length - tvb->tvbuffs.subset.offset;
494         }
495         else {
496                 tvb->reported_length    = reported_length;
497         }
498         tvb->initialized                = TRUE;
499         add_to_used_in_list(backing, tvb);
500
501         /* Optimization. If the backing buffer has a pointer to contiguous, real data,
502          * then we can point directly to our starting offset in that buffer */
503         if (backing->real_data != NULL) {
504                 tvb->real_data = backing->real_data + tvb->tvbuffs.subset.offset;
505         }
506 }
507
508
509 tvbuff_t*
510 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
511 {
512         tvbuff_t        *tvb;
513
514         tvb = tvb_new(TVBUFF_SUBSET);
515
516         CLEANUP_PUSH(tvb_free_void, tvb);
517
518         tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
519
520         tvb->ds_name = backing->ds_name;
521         CLEANUP_POP;
522
523         return tvb;
524 }
525
526 void
527 tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
528 {
529         tvb_comp_t      *composite;
530
531         g_assert(!tvb->initialized);
532         composite = &tvb->tvbuffs.composite;
533         composite->tvbs = g_slist_append( composite->tvbs, member );
534         add_to_used_in_list(member, tvb);
535 }
536
537 void
538 tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
539 {
540         tvb_comp_t      *composite;
541
542         g_assert(!tvb->initialized);
543         composite = &tvb->tvbuffs.composite;
544         composite->tvbs = g_slist_prepend( composite->tvbs, member );
545         add_to_used_in_list(member, tvb);
546 }
547
548 tvbuff_t*
549 tvb_new_composite(void)
550 {
551         return tvb_new(TVBUFF_COMPOSITE);
552 }
553
554 void
555 tvb_composite_finalize(tvbuff_t* tvb)
556 {
557         GSList          *slist;
558         guint           num_members;
559         tvbuff_t        *member_tvb;
560         tvb_comp_t      *composite;
561         int             i = 0;
562
563         g_assert(!tvb->initialized);
564         g_assert(tvb->length == 0);
565
566         composite = &tvb->tvbuffs.composite;
567         num_members = g_slist_length(composite->tvbs);
568
569         composite->start_offsets = g_new(guint, num_members);
570         composite->end_offsets = g_new(guint, num_members);
571
572         for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
573                 g_assert((guint) i < num_members);
574                 member_tvb = slist->data;
575                 composite->start_offsets[i] = tvb->length;
576                 tvb->length += member_tvb->length;
577                 composite->end_offsets[i] = tvb->length - 1;
578                 i++;
579         }
580
581         tvb->initialized = TRUE;
582 }
583
584
585
586 guint
587 tvb_length(tvbuff_t* tvb)
588 {
589         g_assert(tvb->initialized);
590
591         return tvb->length;
592 }
593
594 gint
595 tvb_length_remaining(tvbuff_t *tvb, gint offset)
596 {
597         guint   abs_offset, abs_length;
598
599         g_assert(tvb->initialized);
600
601         if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
602                 return abs_length;
603         }
604         else {
605                 return -1;
606         }
607 }
608
609
610
611 /* Validates that 'length' bytes are available starting from
612  * offset (pos/neg). Does not throw BoundsError exception. */
613 gboolean
614 tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
615 {
616         guint           abs_offset, abs_length;
617
618         g_assert(tvb->initialized);
619
620         if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
621                 return FALSE;
622
623         if (abs_offset + abs_length <= tvb->length) {
624                 return TRUE;
625         }
626         else {
627                 return FALSE;
628         }
629 }
630
631 gboolean
632 tvb_offset_exists(tvbuff_t *tvb, gint offset)
633 {
634         guint           abs_offset, abs_length;
635
636         g_assert(tvb->initialized);
637         if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
638                 return FALSE;
639
640         if (abs_offset < tvb->length) {
641                 return TRUE;
642         }
643         else {
644                 return FALSE;
645         }
646 }
647
648 guint
649 tvb_reported_length(tvbuff_t* tvb)
650 {
651         g_assert(tvb->initialized);
652
653         return tvb->reported_length;
654 }
655
656 gint
657 tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
658 {
659         guint   abs_offset, abs_length;
660
661         g_assert(tvb->initialized);
662
663         if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
664                 if (tvb->reported_length >= abs_offset)
665                         return tvb->reported_length - abs_offset;
666                 else
667                         return -1;
668         }
669         else {
670                 return -1;
671         }
672 }
673
674 /* Set the reported length of a tvbuff to a given value; used for protocols
675    whose headers contain an explicit length and where the calling
676    dissector's payload may include padding as well as the packet for
677    this protocol.
678
679    Also adjusts the data length. */
680 void
681 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
682 {
683         g_assert(tvb->initialized);
684
685         if (reported_length > tvb->reported_length)
686                 THROW(ReportedBoundsError);
687
688         tvb->reported_length = reported_length;
689         if (reported_length < tvb->length)
690                 tvb->length = reported_length;
691 }
692
693
694 static guint8*
695 first_real_data_ptr(tvbuff_t *tvb)
696 {
697         tvbuff_t        *member;
698
699         switch(tvb->type) {
700                 case TVBUFF_REAL_DATA:
701                         return tvb->real_data;
702                 case TVBUFF_SUBSET:
703                         member = tvb->tvbuffs.subset.tvb;
704                         return first_real_data_ptr(member);
705                 case TVBUFF_COMPOSITE:
706                         member = tvb->tvbuffs.composite.tvbs->data;
707                         return first_real_data_ptr(member);
708         }
709
710         g_assert_not_reached();
711         return NULL;
712 }
713
714 static int
715 offset_from_real_beginning(tvbuff_t *tvb, int counter)
716 {
717         tvbuff_t        *member;
718
719         switch(tvb->type) {
720                 case TVBUFF_REAL_DATA:
721                         return counter;
722                 case TVBUFF_SUBSET:
723                         member = tvb->tvbuffs.subset.tvb;
724                         return offset_from_real_beginning(member, counter + tvb->tvbuffs.subset.offset);
725                 case TVBUFF_COMPOSITE:
726                         member = tvb->tvbuffs.composite.tvbs->data;
727                         return offset_from_real_beginning(member, counter);
728         }
729
730         g_assert_not_reached();
731         return 0;
732 }
733
734 gint
735 tvb_raw_offset(tvbuff_t *tvb)
736 {
737         if (tvb->raw_offset == -1) {
738                 tvb->raw_offset = offset_from_real_beginning(tvb, 0);
739         }
740         return tvb->raw_offset;
741 }
742
743 static guint8*
744 composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
745 {
746         guint           i, num_members;
747         tvb_comp_t      *composite;
748         tvbuff_t        *member_tvb = NULL;
749         guint           member_offset, member_length;
750         GSList          *slist;
751
752         g_assert(tvb->type == TVBUFF_COMPOSITE);
753
754         /* Maybe the range specified by offset/length
755          * is contiguous inside one of the member tvbuffs */
756         composite = &tvb->tvbuffs.composite;
757         num_members = g_slist_length(composite->tvbs);
758
759         for (i = 0; i < num_members; i++) {
760                 if (abs_offset <= composite->end_offsets[i]) {
761                         slist = g_slist_nth(composite->tvbs, i);
762                         member_tvb = slist->data;
763                         break;
764                 }
765         }
766         g_assert(member_tvb);
767
768         if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
769                                 abs_length, &member_offset, &member_length, NULL)) {
770
771                 g_assert(!tvb->real_data);
772                 return ensure_contiguous(member_tvb, member_offset, member_length);
773         }
774         else {
775                 tvb->real_data = tvb_memdup(tvb, 0, -1);
776                 return tvb->real_data + abs_offset;
777         }
778
779         g_assert_not_reached();
780         return NULL;
781 }
782
783 static guint8*
784 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
785 {
786         guint   abs_offset, abs_length;
787
788         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
789
790         if (tvb->real_data) {
791                 return tvb->real_data + abs_offset;
792         }
793         else {
794                 switch(tvb->type) {
795                         case TVBUFF_REAL_DATA:
796                                 g_assert_not_reached();
797                         case TVBUFF_SUBSET:
798                                 return ensure_contiguous(tvb->tvbuffs.subset.tvb,
799                                                 abs_offset - tvb->tvbuffs.subset.offset,
800                                                 abs_length);
801                         case TVBUFF_COMPOSITE:
802                                 return composite_ensure_contiguous(tvb, abs_offset, abs_length);
803                 }
804         }
805
806         g_assert_not_reached();
807         return NULL;
808 }
809
810 static const guint8*
811 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
812 {
813         const guint8    *b;
814         int             i;
815
816         for (b = haystack, i = 0; (guint) i < haystacklen; i++, b++) {
817                 if (*b == needle) {
818                         return b;
819                 }
820         }
821
822         return NULL;
823 }
824
825 static const guint8*
826 guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
827 {
828         const guint8    *b;
829         int             i;
830         guint8          item, *needlep, needle;
831
832         for (b = haystack, i = 0; (guint) i < haystacklen; i++, b++) {
833                 item = *b;
834                 needlep = needles;
835                 while ((needle = *needlep) != '\0') {
836                         if (item == needle)
837                                 return b;
838                         needlep++;
839                 }
840         }
841
842         return NULL;
843 }
844
845
846
847 /************** ACCESSORS **************/
848
849 static guint8*
850 composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
851 {
852         guint           i, num_members;
853         tvb_comp_t      *composite;
854         tvbuff_t        *member_tvb = NULL;
855         guint           member_offset, member_length;
856         gboolean        retval;
857         GSList          *slist;
858
859         g_assert(tvb->type == TVBUFF_COMPOSITE);
860
861         /* Maybe the range specified by offset/length
862          * is contiguous inside one of the member tvbuffs */
863         composite = &tvb->tvbuffs.composite;
864         num_members = g_slist_length(composite->tvbs);
865
866         for (i = 0; i < num_members; i++) {
867                 if (abs_offset <= composite->end_offsets[i]) {
868                         slist = g_slist_nth(composite->tvbs, i);
869                         member_tvb = slist->data;
870                         break;
871                 }
872         }
873         g_assert(member_tvb);
874
875         if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
876                                 abs_length, &member_offset, &member_length, NULL)) {
877
878                 g_assert(!tvb->real_data);
879                 return tvb_memcpy(member_tvb, target, member_offset, member_length);
880         }
881         else {
882                 /* The requested data is non-contiguous inside
883                  * the member tvb. We have to memcpy() the part that's in the member tvb,
884                  * then iterate across the other member tvb's, copying their portions
885                  * until we have copied all data.
886                  */
887                 retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
888                                 &member_offset, &member_length, NULL);
889                 g_assert(retval);
890
891                 tvb_memcpy(member_tvb, target, member_offset, member_length);
892                 abs_offset      += member_length;
893                 abs_length      -= member_length;
894
895                 /* Recurse */
896                 if (abs_length > 0) {
897                         composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
898                 }
899
900                 return target;
901         }
902
903         g_assert_not_reached();
904         return NULL;
905 }
906
907 guint8*
908 tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
909 {
910         guint   abs_offset, abs_length;
911
912         g_assert(length >= -1);
913         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
914
915         if (tvb->real_data) {
916                 return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
917         }
918
919         switch(tvb->type) {
920                 case TVBUFF_REAL_DATA:
921                         g_assert_not_reached();
922
923                 case TVBUFF_SUBSET:
924                         return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
925                                         abs_offset - tvb->tvbuffs.subset.offset,
926                                         abs_length);
927
928                 case TVBUFF_COMPOSITE:
929                         return composite_memcpy(tvb, target, offset, length);
930         }
931
932         g_assert_not_reached();
933         return NULL;
934 }
935
936
937 guint8*
938 tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
939 {
940         guint   abs_offset, abs_length;
941         guint8  *duped;
942
943         check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
944
945         duped = g_malloc(abs_length);
946         return tvb_memcpy(tvb, duped, abs_offset, abs_length);
947 }
948
949
950         
951 const guint8*
952 tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
953 {
954         return ensure_contiguous(tvb, offset, length);
955 }
956
957 guint8
958 tvb_get_guint8(tvbuff_t *tvb, gint offset)
959 {
960         guint8* ptr;
961
962         ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
963         return *ptr;
964 }
965
966 guint16
967 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
968 {
969         guint8* ptr;
970
971         ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
972         return pntohs(ptr);
973 }
974
975 guint32
976 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
977 {
978         guint8* ptr;
979
980         ptr = ensure_contiguous(tvb, offset, 3);
981         return pntoh24(ptr);
982 }
983
984 guint32
985 tvb_get_ntohl(tvbuff_t *tvb, gint offset)
986 {
987         guint8* ptr;
988
989         ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
990         return pntohl(ptr);
991 }
992
993 guint16
994 tvb_get_letohs(tvbuff_t *tvb, gint offset)
995 {
996         guint8* ptr;
997
998         ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
999         return pletohs(ptr);
1000 }
1001
1002 guint32
1003 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
1004 {
1005         guint8* ptr;
1006
1007         ptr = ensure_contiguous(tvb, offset, 3);
1008         return pletoh24(ptr);
1009 }
1010
1011 guint32
1012 tvb_get_letohl(tvbuff_t *tvb, gint offset)
1013 {
1014         guint8* ptr;
1015
1016         ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
1017         return pletohl(ptr);
1018 }
1019
1020 /* Find first occurence of needle in tvbuff, starting at offset. Searches
1021  * at most maxlength number of bytes; if maxlength is -1, searches to
1022  * end of tvbuff.
1023  * Returns the offset of the found needle, or -1 if not found.
1024  * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1025  * in that case, -1 will be returned if the boundary is reached before
1026  * finding needle. */
1027 gint
1028 tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
1029 {
1030         const guint8    *result;
1031         guint           abs_offset, junk_length;
1032         guint           tvbufflen;
1033         guint           limit;
1034
1035         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1036
1037         /* Only search to end of tvbuff, w/o throwing exception. */
1038         tvbufflen = tvb_length_remaining(tvb, abs_offset);
1039         if (maxlength == -1) {
1040                 /* No maximum length specified; search to end of tvbuff. */
1041                 limit = tvbufflen;
1042         }
1043         else if (tvbufflen < (guint) maxlength) {
1044                 /* Maximum length goes past end of tvbuff; search to end
1045                    of tvbuff. */
1046                 limit = tvbufflen;
1047         }
1048         else {
1049                 /* Maximum length doesn't go past end of tvbuff; search
1050                    to that value. */
1051                 limit = maxlength;
1052         }
1053
1054         /* If we have real data, perform our search now. */
1055         if (tvb->real_data) {
1056                 result = guint8_find(tvb->real_data + abs_offset, limit, needle);
1057                 if (result == NULL) {
1058                         return -1;
1059                 }
1060                 else {
1061                         return result - tvb->real_data;
1062                 }
1063         }
1064
1065         switch(tvb->type) {
1066                 case TVBUFF_REAL_DATA:
1067                         g_assert_not_reached();
1068
1069                 case TVBUFF_SUBSET:
1070                         return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
1071                                         abs_offset - tvb->tvbuffs.subset.offset,
1072                                         limit, needle);
1073
1074                 case TVBUFF_COMPOSITE:
1075                         g_assert_not_reached();
1076                         /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
1077         }
1078
1079         g_assert_not_reached();
1080         return -1;
1081 }
1082
1083 /* Find first occurence of any of the needles in tvbuff, starting at offset.
1084  * Searches at most maxlength number of bytes; if maxlength is -1, searches
1085  * to end of tvbuff.
1086  * Returns the offset of the found needle, or -1 if not found.
1087  * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
1088  * in that case, -1 will be returned if the boundary is reached before
1089  * finding needle. */
1090 gint
1091 tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 *needles)
1092 {
1093         const guint8    *result;
1094         guint           abs_offset, junk_length;
1095         guint           tvbufflen;
1096         guint           limit;
1097
1098         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1099
1100         /* Only search to end of tvbuff, w/o throwing exception. */
1101         tvbufflen = tvb_length_remaining(tvb, abs_offset);
1102         if (maxlength == -1) {
1103                 /* No maximum length specified; search to end of tvbuff. */
1104                 limit = tvbufflen;
1105         }
1106         else if (tvbufflen < (guint) maxlength) {
1107                 /* Maximum length goes past end of tvbuff; search to end
1108                    of tvbuff. */
1109                 limit = tvbufflen;
1110         }
1111         else {
1112                 /* Maximum length doesn't go past end of tvbuff; search
1113                    to that value. */
1114                 limit = maxlength;
1115         }
1116
1117         /* If we have real data, perform our search now. */
1118         if (tvb->real_data) {
1119                 result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles);
1120                 if (result == NULL) {
1121                         return -1;
1122                 }
1123                 else {
1124                         return result - tvb->real_data;
1125                 }
1126         }
1127
1128         switch(tvb->type) {
1129                 case TVBUFF_REAL_DATA:
1130                         g_assert_not_reached();
1131
1132                 case TVBUFF_SUBSET:
1133                         return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
1134                                         abs_offset - tvb->tvbuffs.subset.offset,
1135                                         limit, needles);
1136
1137                 case TVBUFF_COMPOSITE:
1138                         g_assert_not_reached();
1139                         /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
1140         }
1141
1142         g_assert_not_reached();
1143         return -1;
1144 }
1145
1146 /* Find size of stringz (NUL-terminated string) by looking for terminating
1147  * NUL.  The size of the string includes the terminating NUL.
1148  *
1149  * If the NUL isn't found, it throws the appropriate exception.
1150  */
1151 guint
1152 tvb_strsize(tvbuff_t *tvb, gint offset)
1153 {
1154         guint   abs_offset, junk_length;
1155         gint    nul_offset;
1156
1157         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1158         nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
1159         if (nul_offset == -1) {
1160                 /*
1161                  * OK, we hit the end of the tvbuff, so we should throw
1162                  * an exception.
1163                  *
1164                  * Did we hit the end of the captured data, or the end
1165                  * of the actual data?  If there's less captured data
1166                  * than actual data, we presumably hit the end of the
1167                  * captured data, otherwise we hit the end of the actual
1168                  * data.
1169                  */
1170                 if (tvb_length(tvb) < tvb_reported_length(tvb)) {
1171                         THROW(BoundsError);
1172                 } else {
1173                         THROW(ReportedBoundsError);
1174                 }
1175         }
1176         return (nul_offset - abs_offset) + 1;
1177 }
1178
1179 /* Find length of string by looking for end of string ('\0'), up to
1180  * 'maxlength' characters'; if 'maxlength' is -1, searches to end
1181  * of tvbuff.
1182  * Returns -1 if 'maxlength' reached before finding EOS. */
1183 gint
1184 tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
1185 {
1186         gint    result_offset;
1187         guint   abs_offset, junk_length;
1188
1189         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1190
1191         result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
1192
1193         if (result_offset == -1) {
1194                 return -1;
1195         }
1196         else {
1197                 return result_offset - abs_offset;
1198         }
1199 }
1200
1201 /*
1202  * Implement strneql etc
1203  */
1204
1205 /*
1206  * Call strncmp after checking if enough chars left, returning 0 if
1207  * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1208  */
1209 gint
1210 tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1211 {
1212         guint8 *ptr;
1213
1214         ptr = ensure_contiguous(tvb, offset, size);
1215
1216         if (ptr) {
1217                 int cmp = strncmp(ptr, str, size);
1218
1219                 /*
1220                  * Return 0 if equal, -1 otherwise.
1221                  */
1222                 return (cmp == 0 ? 0 : -1);
1223         } else {
1224                 /*
1225                  * Not enough characters in the tvbuff to match the
1226                  * string.
1227                  */
1228                 return -1;
1229         }
1230 }
1231
1232 /*
1233  * Call strncasecmp after checking if enough chars left, returning 0 if
1234  * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1235  */
1236 gint
1237 tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1238 {
1239         guint8 *ptr;
1240
1241         ptr = ensure_contiguous(tvb, offset, size);
1242
1243         if (ptr) {
1244                 int cmp = strncasecmp(ptr, str, size);
1245
1246                 /*
1247                  * Return 0 if equal, -1 otherwise.
1248                  */
1249                 return (cmp == 0 ? 0 : -1);
1250         } else {
1251                 /*
1252                  * Not enough characters in the tvbuff to match the
1253                  * string.
1254                  */
1255                 return -1;
1256         }
1257 }
1258
1259 /*
1260  * Call memcmp after checking if enough chars left, returning 0 if
1261  * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
1262  */
1263 gint
1264 tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
1265 {
1266         guint8 *ptr;
1267
1268         ptr = ensure_contiguous(tvb, offset, size);
1269
1270         if (ptr) {
1271                 int cmp = memcmp(ptr, str, size);
1272
1273                 /*
1274                  * Return 0 if equal, -1 otherwise.
1275                  */
1276                 return (cmp == 0 ? 0 : -1);
1277         } else {
1278                 /*
1279                  * Not enough characters in the tvbuff to match the
1280                  * string.
1281                  */
1282                 return -1;
1283         }
1284 }
1285
1286 /*
1287  * Format the data in the tvb from offset for length ...
1288  */
1289
1290 guint8 *
1291 tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
1292 {
1293   guint8 *ptr;
1294   gint len = size;
1295
1296   if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
1297
1298     len = tvb_length_remaining(tvb, offset);
1299     ptr = ensure_contiguous(tvb, offset, len);
1300
1301   }
1302
1303   return format_text(ptr, len);
1304  
1305 }
1306
1307 /* Looks for a stringz (NUL-terminated string) in tvbuff and copies
1308  * no more than maxlength number of bytes, including terminating NUL, to buffer.
1309  * Returns length of string (not including terminating NUL), or -1 if the string was
1310  * truncated in the buffer due to not having reached the terminating NUL.
1311  * In this way, it acts like snprintf().
1312  */
1313 gint
1314 tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1315 {
1316         gint    stringlen;
1317         guint   abs_offset, junk_length;
1318         gint    limit, len;
1319
1320         check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
1321
1322         if (maxlength == 0) {
1323                 buffer[0] = 0;
1324                 return 0;
1325         }
1326
1327         /* Only copy to end of tvbuff, w/o throwing exception. */
1328         len = tvb_length_remaining(tvb, abs_offset);
1329
1330     /* This should not happen because check_offset_length() would
1331      * have already thrown an exception if 'offset' were out-of-bounds.
1332      */
1333     g_assert(len != -1);
1334
1335     if ((guint)len < maxlength) {
1336                 limit = maxlength - (tvb_length(tvb) - abs_offset);
1337         }
1338         else {
1339                 limit = maxlength;
1340         }
1341
1342         stringlen = tvb_strnlen(tvb, abs_offset, limit);
1343
1344         /* If NUL wasn't found, copy the data and return -1 */
1345         if (stringlen == -1) {
1346                 tvb_memcpy(tvb, buffer, abs_offset, limit);
1347                 return -1;
1348         }
1349
1350         /* Copy the string to buffer */
1351         tvb_memcpy(tvb, buffer, abs_offset, stringlen + 1);
1352         return stringlen;
1353 }
1354
1355 /* Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to
1356  * have a terminating NUL. If the string was truncated when copied into buffer,
1357  * a NUL is placed at the end of buffer to terminate it.
1358  */
1359 gint
1360 tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint maxlength, guint8* buffer)
1361 {
1362         gint    len;
1363
1364         len = tvb_get_nstringz(tvb, offset, maxlength, buffer);
1365
1366         if (len == -1) {
1367                 buffer[maxlength] = 0;
1368                 return maxlength - 1;
1369         }
1370         else {
1371                 return len;
1372         }
1373 }
1374
1375 /*
1376  * Given a tvbuff, an offset into the tvbuff, and a length that starts
1377  * at that offset (which may be -1 for "all the way to the end of the
1378  * tvbuff"), find the end of the (putative) line that starts at the
1379  * specified offset in the tvbuff, going no further than the specified
1380  * length.
1381  *
1382  * Return the length of the line (not counting the line terminator at
1383  * the end), or the amount of data remaining in the buffer if we don't
1384  * find a line terminator.
1385  *
1386  * Set "*next_offset" to the offset of the character past the line
1387  * terminator, or past the end of the buffer if we don't find a line
1388  * terminator.
1389  */
1390 gint
1391 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset)
1392 {
1393         gint eob_offset;
1394         gint eol_offset;
1395         int linelen;
1396
1397         if (len == -1)
1398                 len = tvb_length_remaining(tvb, offset);
1399         /*
1400          * XXX - what if "len" is still -1, meaning "offset is past the
1401          * end of the tvbuff"?
1402          */
1403         eob_offset = offset + len;
1404
1405         /*
1406          * Look either for a CR or an LF.
1407          */
1408         eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n");
1409         if (eol_offset == -1) {
1410                 /*
1411                  * No CR or LF - line is presumably continued in next packet.
1412                  * We pretend the line runs to the end of the tvbuff.
1413                  */
1414                 linelen = eob_offset - offset;
1415                 *next_offset = eob_offset;
1416         } else {
1417                 /*
1418                  * Find the number of bytes between the starting offset
1419                  * and the CR or LF.
1420                  */
1421                 linelen = eol_offset - offset;
1422
1423                 /*
1424                  * Is it a CR?
1425                  */
1426                 if (tvb_get_guint8(tvb, eol_offset) == '\r') {
1427                         /*
1428                          * Yes - is it followed by an LF?
1429                          */
1430                         if (eol_offset + 1 < eob_offset &&
1431                             tvb_get_guint8(tvb, eol_offset + 1) == '\n') {
1432                                 /*
1433                                  * Yes; skip over the CR.
1434                                  */
1435                                 eol_offset++;
1436                         }
1437                 }
1438
1439                 /*
1440                  * Return the offset of the character after the last
1441                  * character in the line, skipping over the last character
1442                  * in the line terminator.
1443                  */
1444                 *next_offset = eol_offset + 1;
1445         }
1446         return linelen;
1447 }
1448
1449 /*
1450  * Given a tvbuff, an offset into the tvbuff, and a length that starts
1451  * at that offset (which may be -1 for "all the way to the end of the
1452  * tvbuff"), find the end of the (putative) line that starts at the
1453  * specified offset in the tvbuff, going no further than the specified
1454  * length.
1455  *
1456  * However, treat quoted strings inside the buffer specially - don't
1457  * treat newlines in quoted strings as line terminators.
1458  *
1459  * Return the length of the line (not counting the line terminator at
1460  * the end), or the amount of data remaining in the buffer if we don't
1461  * find a line terminator.
1462  *
1463  * Set "*next_offset" to the offset of the character past the line
1464  * terminator, or past the end of the buffer if we don't find a line
1465  * terminator.
1466  */
1467 gint
1468 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
1469     gint *next_offset)
1470 {
1471         gint cur_offset, char_offset;
1472         gboolean is_quoted;
1473         u_char c;
1474         gint eob_offset;
1475         int linelen;
1476
1477         if (len == -1)
1478                 len = tvb_length_remaining(tvb, offset);
1479         /*
1480          * XXX - what if "len" is still -1, meaning "offset is past the
1481          * end of the tvbuff"?
1482          */
1483         eob_offset = offset + len;
1484
1485         cur_offset = offset;
1486         is_quoted = FALSE;
1487         for (;;) {
1488                 /*
1489                  * Is this part of the string quoted?
1490                  */
1491                 if (is_quoted) {
1492                         /*
1493                          * Yes - look only for the terminating quote.
1494                          */
1495                         char_offset = tvb_find_guint8(tvb, cur_offset, len,
1496                             '"');
1497                 } else {
1498                         /*
1499                          * Look either for a CR, an LF, or a '"'.
1500                          */
1501                         char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
1502                             "\r\n\"");
1503                 }
1504                 if (char_offset == -1) {
1505                         /*
1506                          * Not found - line is presumably continued in
1507                          * next packet.
1508                          * We pretend the line runs to the end of the tvbuff.
1509                          */
1510                         linelen = eob_offset - offset;
1511                         *next_offset = eob_offset;
1512                         break;
1513                 }
1514                         
1515                 if (is_quoted) {
1516                         /*
1517                          * We're processing a quoted string.
1518                          * We only looked for ", so we know it's a ";
1519                          * as we're processing a quoted string, it's a
1520                          * closing quote.
1521                          */
1522                         is_quoted = FALSE;
1523                 } else {
1524                         /*
1525                          * OK, what is it?
1526                          */
1527                         c = tvb_get_guint8(tvb, char_offset);
1528                         if (c == '"') {
1529                                 /*
1530                                  * Un-quoted "; it begins a quoted
1531                                  * string.
1532                                  */
1533                                 is_quoted = TRUE;
1534                         } else {
1535                                 /*
1536                                  * It's a CR or LF; we've found a line
1537                                  * terminator.
1538                                  *
1539                                  * Find the number of bytes between the
1540                                  * starting offset and the CR or LF.
1541                                  */
1542                                 linelen = char_offset - offset;
1543
1544                                 /*
1545                                  * Is it a CR?
1546                                  */
1547                                 if (c == '\r') {
1548                                         /*
1549                                          * Yes; is it followed by an LF?
1550                                          */
1551                                         if (char_offset + 1 < eob_offset &&
1552                                             tvb_get_guint8(tvb, char_offset + 1)
1553                                               == '\n') {
1554                                                 /*
1555                                                  * Yes; skip over the CR.
1556                                                  */
1557                                                 char_offset++;
1558                                         }
1559                                 }
1560
1561                                 /*
1562                                  * Return the offset of the character after
1563                                  * the last character in the line, skipping
1564                                  * over the last character in the line
1565                                  * terminator, and quit.
1566                                  */
1567                                 *next_offset = char_offset + 1;
1568                                 break;
1569                         }
1570                 }
1571
1572                 /*
1573                  * Step past the character we found.
1574                  */
1575                 cur_offset = char_offset + 1;
1576                 if (cur_offset >= eob_offset) {
1577                         /*
1578                          * The character we found was the last character
1579                          * in the tvbuff - line is presumably continued in
1580                          * next packet.
1581                          * We pretend the line runs to the end of the tvbuff.
1582                          */
1583                         linelen = eob_offset - offset;
1584                         *next_offset = eob_offset;
1585                         break;
1586                 }
1587         }
1588         return linelen;
1589 }
1590
1591 /*
1592  * Format a bunch of data from a tvbuff as bytes, returning a pointer
1593  * to the string with the formatted data.
1594  */
1595 gchar *
1596 tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
1597 {
1598         return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
1599 }
1600
1601 gchar*
1602 tvb_get_name(tvbuff_t* tvb)
1603 {
1604         return tvb->ds_name;
1605 }