]> git.ipfire.org Git - people/ms/suricata.git/blame - src/util-streaming-buffer.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / util-streaming-buffer.c
CommitLineData
81b2984c
VJ
1/* Copyright (C) 2015-2016 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18#include "suricata-common.h"
19#include "util-streaming-buffer.h"
20#include "util-unittest.h"
21#include "util-print.h"
450500e6 22#include "util-validate.h"
81b2984c
VJ
23
24/**
25 * \file
26 *
27 * \author Victor Julien <victor@inliniac.net>
28 *
29 * \brief Streaming Buffer API
30 */
31
32/* memory handling wrappers. If config doesn't define it's own set of
33 * functions, use the defaults */
34#define MALLOC(cfg, s) \
35 (cfg)->Malloc ? (cfg)->Malloc((s)) : SCMalloc((s))
36#define CALLOC(cfg, n, s) \
37 (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : SCCalloc((n), (s))
38#define REALLOC(cfg, ptr, orig_s, s) \
39 (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : SCRealloc((ptr), (s))
40#define FREE(cfg, ptr, s) \
41 (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr))
42
d789dc7e
VJ
43static void SBBFree(StreamingBuffer *sb);
44
450500e6
VJ
45RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare);
46
47int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b)
48{
49 SCLogDebug("a %"PRIu64" len %u, b %"PRIu64" len %u",
50 a->offset, a->len, b->offset, b->len);
51
52 if (a->offset > b->offset)
53 SCReturnInt(1);
54 else if (a->offset < b->offset)
55 SCReturnInt(-1);
56 else {
57 if (a->len == 0 || b->len == 0 || a->len == b->len)
58 SCReturnInt(0);
59 else if (a->len > b->len)
60 SCReturnInt(1);
61 else
62 SCReturnInt(-1);
63 }
64}
65
66/* inclusive compare function that also considers the right edge,
67 * not just the offset. */
68static inline int InclusiveCompare(StreamingBufferBlock *lookup, StreamingBufferBlock *intree) {
69 const uint64_t lre = lookup->offset + lookup->len;
70 const uint64_t tre = intree->offset + intree->len;
ff920472 71 if (lre <= intree->offset) // entirely before
450500e6 72 return -1;
2c050187 73 else if (lre >= intree->offset && lookup->offset < tre && lre <= tre) // (some) overlap
450500e6
VJ
74 return 0;
75 else
76 return 1; // entirely after
77}
78
79StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm)
80{
81 SCLogDebug("looking up %"PRIu64, elm->offset);
82
83 struct StreamingBufferBlock *tmp = RB_ROOT(head);
84 struct StreamingBufferBlock *res = NULL;
85 while (tmp) {
86 SCLogDebug("compare with %"PRIu64"/%u", tmp->offset, tmp->len);
87 const int comp = InclusiveCompare(elm, tmp);
88 SCLogDebug("compare result: %d", comp);
89 if (comp < 0) {
90 res = tmp;
91 tmp = RB_LEFT(tmp, rb);
92 } else if (comp > 0) {
93 tmp = RB_RIGHT(tmp, rb);
94 } else {
95 return tmp;
96 }
97 }
98 return res;
99}
100
101
81b2984c
VJ
102static inline int InitBuffer(StreamingBuffer *sb)
103{
104 sb->buf = CALLOC(sb->cfg, 1, sb->cfg->buf_size);
105 if (sb->buf == NULL) {
106 return -1;
107 }
108 sb->buf_size = sb->cfg->buf_size;
109 return 0;
110}
111
112StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg)
113{
114 StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer));
115 if (sb != NULL) {
116 sb->buf_size = cfg->buf_size;
117 sb->cfg = cfg;
118
119 if (cfg->buf_size > 0) {
120 if (InitBuffer(sb) == 0) {
121 return sb;
122 }
123 FREE(cfg, sb, sizeof(StreamingBuffer));
124 /* implied buf_size == 0 */
125 } else {
126 return sb;
127 }
128 }
129 return NULL;
130}
131
132void StreamingBufferClear(StreamingBuffer *sb)
133{
134 if (sb != NULL) {
135 SCLogDebug("sb->buf_size %u max %u", sb->buf_size, sb->buf_size_max);
136
d789dc7e 137 SBBFree(sb);
81b2984c
VJ
138 if (sb->buf != NULL) {
139 FREE(sb->cfg, sb->buf, sb->buf_size);
140 sb->buf = NULL;
141 }
142 }
143}
144
145void StreamingBufferFree(StreamingBuffer *sb)
146{
147 if (sb != NULL) {
148 StreamingBufferClear(sb);
149 FREE(sb->cfg, sb, sizeof(StreamingBuffer));
150 }
151}
152
d789dc7e 153#ifdef DEBUG
450500e6 154static void SBBPrintList(StreamingBuffer *sb)
d789dc7e 155{
450500e6
VJ
156 StreamingBufferBlock *sbb = NULL;
157 RB_FOREACH(sbb, SBB, &sb->sbb_tree) {
d789dc7e 158 SCLogDebug("sbb: offset %"PRIu64", len %u", sbb->offset, sbb->len);
450500e6
VJ
159 StreamingBufferBlock *next = SBB_RB_NEXT(sbb);
160 if (next) {
161 if ((sbb->offset + sbb->len) != next->offset) {
d789dc7e 162 SCLogDebug("gap: offset %"PRIu64", len %"PRIu64, (sbb->offset + sbb->len),
450500e6 163 next->offset - (sbb->offset + sbb->len));
d789dc7e
VJ
164 }
165 }
d789dc7e
VJ
166 }
167}
168#endif
169
170/* setup with gap between 2 blocks
171 *
172 * [block][gap][block]
173 **/
174static void SBBInit(StreamingBuffer *sb,
175 uint32_t rel_offset, uint32_t data_len)
176{
450500e6
VJ
177 DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
178 DEBUG_VALIDATE_BUG_ON(sb->buf_offset > sb->stream_offset + rel_offset);
d789dc7e
VJ
179
180 /* need to set up 2: existing data block and new data block */
181 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
182 if (sbb == NULL) {
183 return;
184 }
185 sbb->offset = sb->stream_offset;
186 sbb->len = sb->buf_offset;
187
188 StreamingBufferBlock *sbb2 = CALLOC(sb->cfg, 1, sizeof(*sbb2));
189 if (sbb2 == NULL) {
190 FREE(sb->cfg, sbb, sizeof(*sbb));
191 return;
192 }
193 sbb2->offset = sb->stream_offset + rel_offset;
194 sbb2->len = data_len;
195
bbf1f78f 196 sb->head = sbb;
be1baa8c 197 sb->sbb_size = sbb->len + sbb2->len;
450500e6
VJ
198 SBB_RB_INSERT(&sb->sbb_tree, sbb);
199 SBB_RB_INSERT(&sb->sbb_tree, sbb2);
d789dc7e
VJ
200
201 SCLogDebug("sbb1 %"PRIu64", len %u, sbb2 %"PRIu64", len %u",
202 sbb->offset, sbb->len, sbb2->offset, sbb2->len);
203#ifdef DEBUG
204 SBBPrintList(sb);
205#endif
206 BUG_ON(sbb2->offset < sbb->len);
207}
208
209/* setup with leading gap
210 *
211 * [gap][block]
212 **/
213static void SBBInitLeadingGap(StreamingBuffer *sb,
214 uint64_t offset, uint32_t data_len)
215{
450500e6 216 DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
d789dc7e
VJ
217
218 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
219 if (sbb == NULL)
220 return;
221 sbb->offset = offset;
222 sbb->len = data_len;
223
bbf1f78f 224 sb->head = sbb;
be1baa8c 225 sb->sbb_size = sbb->len;
450500e6 226 SBB_RB_INSERT(&sb->sbb_tree, sbb);
d789dc7e
VJ
227
228 SCLogDebug("sbb %"PRIu64", len %u",
229 sbb->offset, sbb->len);
230#ifdef DEBUG
231 SBBPrintList(sb);
232#endif
233}
234
450500e6
VJ
235static inline void ConsolidateFwd(StreamingBuffer *sb,
236 struct SBB *tree, StreamingBufferBlock *sa)
d789dc7e 237{
450500e6
VJ
238 uint64_t sa_re = sa->offset + sa->len;
239 StreamingBufferBlock *tr, *s = sa;
240 RB_FOREACH_FROM(tr, SBB, s) {
241 if (sa == tr)
242 continue;
243
244 const uint64_t tr_re = tr->offset + tr->len;
245 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u re %"PRIu64,
246 tr, tr->offset, tr->len, tr_re);
247
248 if (sa_re < tr->offset)
249 break; // entirely before
250
251 /*
252 sa: [ ]
253 tr: [ ]
254 sa: [ ]
255 tr: [ ]
256 sa: [ ]
257 tr: [ ]
258 */
259 if (sa->offset >= tr->offset && sa_re <= tr_re) {
be1baa8c 260 sb->sbb_size -= sa->len;
450500e6
VJ
261 sa->len = tr->len;
262 sa->offset = tr->offset;
263 sa_re = sa->offset + sa->len;
264 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED2", tr, tr->offset, tr->len);
265 SBB_RB_REMOVE(tree, tr);
266 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
267 /*
268 sa: [ ]
269 tr: [ ]
270 sa: [ ]
271 tr: [ ]
272 sa: [ ]
273 tr: [ ]
274 */
275 } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
276 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED", tr, tr->offset, tr->len);
277 SBB_RB_REMOVE(tree, tr);
be1baa8c 278 sb->sbb_size -= tr->len;
450500e6
VJ
279 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
280 /*
281 sa: [ ]
282 tr: [ ]
283 sa: [ ]
284 tr: [ ]
285 */
286 } else if (sa->offset < tr->offset && // starts before
287 sa_re >= tr->offset && sa_re < tr_re) // ends inside
288 {
be1baa8c
VJ
289 // merge. sb->sbb_size includes both so we need to adjust that too.
290 uint32_t combined_len = sa->len + tr->len;
450500e6
VJ
291 sa->len = tr_re - sa->offset;
292 sa_re = sa->offset + sa->len;
293 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED MERGED", tr, tr->offset, tr->len);
294 SBB_RB_REMOVE(tree, tr);
be1baa8c 295 sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
450500e6
VJ
296 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
297 }
d789dc7e 298 }
d789dc7e
VJ
299}
300
450500e6
VJ
301static inline void ConsolidateBackward(StreamingBuffer *sb,
302 struct SBB *tree, StreamingBufferBlock *sa)
d789dc7e 303{
450500e6
VJ
304 uint64_t sa_re = sa->offset + sa->len;
305 StreamingBufferBlock *tr, *s = sa;
306 RB_FOREACH_REVERSE_FROM(tr, SBB, s) {
307 if (sa == tr)
308 continue;
309 const uint64_t tr_re = tr->offset + tr->len;
310 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u", tr, tr->offset, tr->len);
311
312 if (sa->offset > tr_re)
313 break; // entirely after
314
315 if (sa->offset >= tr->offset && sa_re <= tr_re) {
be1baa8c 316 sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting
450500e6
VJ
317 sa->len = tr->len;
318 sa->offset = tr->offset;
319 sa_re = sa->offset + sa->len;
320 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED2", tr, tr->offset, tr->len);
bbf1f78f
VJ
321 if (sb->head == tr)
322 sb->head = sa;
450500e6
VJ
323 SBB_RB_REMOVE(tree, tr);
324 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
325 /*
326 sa: [ ]
327 tr: [ ]
328 sa: [ ]
329 tr: [ ]
330 sa: [ ]
331 tr: [ ]
332 */
333 } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
334 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED", tr, tr->offset, tr->len);
bbf1f78f
VJ
335 if (sb->head == tr)
336 sb->head = sa;
450500e6 337 SBB_RB_REMOVE(tree, tr);
be1baa8c 338 sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting
450500e6
VJ
339 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
340 /*
341 sa: [ ]
342 tr: [ ]
343 sa: [ ]
344 tr: [ ]
345 */
346 } else if (sa->offset > tr->offset && sa_re > tr_re && sa->offset <= tr_re) {
be1baa8c
VJ
347 // merge. sb->sbb_size includes both so we need to adjust that too.
348 uint32_t combined_len = sa->len + tr->len;
450500e6
VJ
349 sa->len = sa_re - tr->offset;
350 sa->offset = tr->offset;
351 sa_re = sa->offset + sa->len;
352 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED MERGED", tr, tr->offset, tr->len);
bbf1f78f
VJ
353 if (sb->head == tr)
354 sb->head = sa;
450500e6 355 SBB_RB_REMOVE(tree, tr);
be1baa8c 356 sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
450500e6 357 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
d789dc7e
VJ
358 }
359 }
d789dc7e
VJ
360}
361
450500e6
VJ
362static int Insert(StreamingBuffer *sb, struct SBB *tree,
363 uint32_t rel_offset, uint32_t len)
d789dc7e 364{
450500e6 365 SCLogDebug("* inserting: %u/%u\n", rel_offset, len);
d789dc7e 366
450500e6
VJ
367 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
368 if (sbb == NULL)
369 return -1;
370 sbb->offset = sb->stream_offset + rel_offset;
371 sbb->len = len;
372 StreamingBufferBlock *res = SBB_RB_INSERT(tree, sbb);
373 if (res) {
374 // exact overlap
375 SCLogDebug("* insert failed: exact match in tree with %p %"PRIu64"/%u", res, res->offset, res->len);
376 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
377 return 0;
d789dc7e 378 }
be1baa8c 379 sb->sbb_size += len; // may adjust based on consolidation below
bbf1f78f
VJ
380 if (SBB_RB_PREV(sbb) == NULL) {
381 sb->head = sbb;
382 } else {
383 ConsolidateBackward(sb, tree, sbb);
384 }
450500e6 385 ConsolidateFwd(sb, tree, sbb);
d789dc7e
VJ
386#ifdef DEBUG
387 SBBPrintList(sb);
388#endif
450500e6
VJ
389 return 0;
390}
d789dc7e 391
450500e6
VJ
392static void SBBUpdate(StreamingBuffer *sb,
393 uint32_t rel_offset, uint32_t data_len)
394{
395 Insert(sb, &sb->sbb_tree, rel_offset, data_len);
d789dc7e
VJ
396}
397
398static void SBBFree(StreamingBuffer *sb)
399{
450500e6
VJ
400 StreamingBufferBlock *sbb = NULL, *safe = NULL;
401 RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
402 SBB_RB_REMOVE(&sb->sbb_tree, sbb);
be1baa8c 403 sb->sbb_size -= sbb->len;
d789dc7e 404 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
d789dc7e 405 }
bbf1f78f 406 sb->head = NULL;
d789dc7e
VJ
407}
408
409static void SBBPrune(StreamingBuffer *sb)
410{
450500e6
VJ
411 SCLogDebug("pruning %p to %"PRIu64, sb, sb->stream_offset);
412 StreamingBufferBlock *sbb = NULL, *safe = NULL;
413 RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
d789dc7e 414 /* completely beyond window, we're done */
bbf1f78f
VJ
415 if (sbb->offset > sb->stream_offset) {
416 sb->head = sbb;
d789dc7e 417 break;
bbf1f78f 418 }
d789dc7e
VJ
419
420 /* partly before, partly beyond. Adjust */
421 if (sbb->offset < sb->stream_offset &&
422 sbb->offset + sbb->len > sb->stream_offset) {
423 uint32_t shrink_by = sb->stream_offset - sbb->offset;
450500e6
VJ
424 DEBUG_VALIDATE_BUG_ON(shrink_by > sbb->len);
425 if (sbb->len >= shrink_by) {
426 sbb->len -= shrink_by;
427 sbb->offset += shrink_by;
be1baa8c 428 sb->sbb_size -= shrink_by;
450500e6
VJ
429 DEBUG_VALIDATE_BUG_ON(sbb->offset != sb->stream_offset);
430 }
bbf1f78f 431 sb->head = sbb;
d789dc7e
VJ
432 break;
433 }
434
450500e6 435 SBB_RB_REMOVE(&sb->sbb_tree, sbb);
bbf1f78f
VJ
436 /* either we set it again for the next sbb, or there isn't any */
437 sb->head = NULL;
be1baa8c 438 sb->sbb_size -= sbb->len;
450500e6 439 SCLogDebug("sb %p removed %p %"PRIu64", %u", sb, sbb, sbb->offset, sbb->len);
d789dc7e 440 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
d789dc7e
VJ
441 }
442}
443
81b2984c
VJ
444/**
445 * \internal
446 * \brief move buffer forward by 'slide'
447 */
448static void AutoSlide(StreamingBuffer *sb)
449{
450 uint32_t size = sb->cfg->buf_slide;
451 uint32_t slide = sb->buf_offset - size;
452 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
453 memmove(sb->buf, sb->buf+slide, size);
454 sb->stream_offset += slide;
455 sb->buf_offset = size;
d789dc7e 456 SBBPrune(sb);
81b2984c
VJ
457}
458
b856caad 459static int WARN_UNUSED
40af9aad 460GrowToSize(StreamingBuffer *sb, uint32_t size)
81b2984c
VJ
461{
462 /* try to grow in multiples of sb->cfg->buf_size */
463 uint32_t x = sb->cfg->buf_size ? size % sb->cfg->buf_size : 0;
464 uint32_t base = size - x;
465 uint32_t grow = base + sb->cfg->buf_size;
466
467 void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow);
40af9aad
VJ
468 if (ptr == NULL)
469 return -1;
470
471 /* for safe printing and general caution, lets memset the
472 * new data to 0 */
473 size_t diff = grow - sb->buf_size;
474 void *new_mem = ((char *)ptr) + sb->buf_size;
475 memset(new_mem, 0, diff);
476
477 sb->buf = ptr;
478 sb->buf_size = grow;
479 SCLogDebug("grown buffer to %u", grow);
81b2984c 480#ifdef DEBUG
40af9aad
VJ
481 if (sb->buf_size > sb->buf_size_max) {
482 sb->buf_size_max = sb->buf_size;
81b2984c 483 }
40af9aad
VJ
484#endif
485 return 0;
81b2984c
VJ
486}
487
40af9aad
VJ
488/** \internal
489 * \brief try to double the buffer size
490 * \retval 0 ok
491 * \retval -1 failed, buffer unchanged
492 */
b856caad 493static int WARN_UNUSED Grow(StreamingBuffer *sb)
81b2984c
VJ
494{
495 uint32_t grow = sb->buf_size * 2;
496 void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow);
40af9aad
VJ
497 if (ptr == NULL)
498 return -1;
499
500 /* for safe printing and general caution, lets memset the
501 * new data to 0 */
502 size_t diff = grow - sb->buf_size;
503 void *new_mem = ((char *)ptr) + sb->buf_size;
504 memset(new_mem, 0, diff);
505
506 sb->buf = ptr;
507 sb->buf_size = grow;
508 SCLogDebug("grown buffer to %u", grow);
81b2984c 509#ifdef DEBUG
40af9aad
VJ
510 if (sb->buf_size > sb->buf_size_max) {
511 sb->buf_size_max = sb->buf_size;
81b2984c 512 }
40af9aad
VJ
513#endif
514 return 0;
81b2984c
VJ
515}
516
517/**
518 * \brief slide to absolute offset
519 * \todo if sliding beyond window, we could perhaps reset?
520 */
521void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset)
522{
523 if (offset > sb->stream_offset &&
524 offset <= sb->stream_offset + sb->buf_offset)
525 {
526 uint32_t slide = offset - sb->stream_offset;
527 uint32_t size = sb->buf_offset - slide;
528 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
529 memmove(sb->buf, sb->buf+slide, size);
530 sb->stream_offset += slide;
531 sb->buf_offset = size;
d789dc7e 532 SBBPrune(sb);
81b2984c
VJ
533 }
534}
535
536void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide)
537{
538 uint32_t size = sb->buf_offset - slide;
539 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
540 memmove(sb->buf, sb->buf+slide, size);
541 sb->stream_offset += slide;
542 sb->buf_offset = size;
d789dc7e 543 SBBPrune(sb);
81b2984c
VJ
544}
545
546#define DATA_FITS(sb, len) \
547 ((sb)->buf_offset + (len) <= (sb)->buf_size)
548
549StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint8_t *data, uint32_t data_len)
550{
551 if (sb->buf == NULL) {
552 if (InitBuffer(sb) == -1)
553 return NULL;
554 }
555
40af9aad
VJ
556 if (!DATA_FITS(sb, data_len)) {
557 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
558 AutoSlide(sb);
559 if (sb->buf_size == 0) {
560 if (GrowToSize(sb, data_len) != 0)
561 return NULL;
562 } else {
563 while (!DATA_FITS(sb, data_len)) {
564 if (Grow(sb) != 0) {
565 return NULL;
81b2984c
VJ
566 }
567 }
568 }
40af9aad
VJ
569 }
570 if (!DATA_FITS(sb, data_len)) {
571 return NULL;
572 }
81b2984c 573
40af9aad
VJ
574 StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment));
575 if (seg != NULL) {
81b2984c
VJ
576 memcpy(sb->buf + sb->buf_offset, data, data_len);
577 seg->stream_offset = sb->stream_offset + sb->buf_offset;
578 seg->segment_len = data_len;
d789dc7e 579 uint32_t rel_offset = sb->buf_offset;
81b2984c 580 sb->buf_offset += data_len;
d789dc7e 581
450500e6 582 if (!RB_EMPTY(&sb->sbb_tree)) {
d789dc7e
VJ
583 SBBUpdate(sb, rel_offset, data_len);
584 }
81b2984c
VJ
585 return seg;
586 }
587 return NULL;
588}
589
40af9aad
VJ
590int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg,
591 const uint8_t *data, uint32_t data_len)
81b2984c
VJ
592{
593 BUG_ON(seg == NULL);
594
595 if (sb->buf == NULL) {
596 if (InitBuffer(sb) == -1)
40af9aad 597 return -1;
81b2984c
VJ
598 }
599
600 if (!DATA_FITS(sb, data_len)) {
601 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
602 AutoSlide(sb);
603 if (sb->buf_size == 0) {
40af9aad
VJ
604 if (GrowToSize(sb, data_len) != 0)
605 return -1;
81b2984c
VJ
606 } else {
607 while (!DATA_FITS(sb, data_len)) {
40af9aad
VJ
608 if (Grow(sb) != 0) {
609 return -1;
610 }
81b2984c
VJ
611 }
612 }
613 }
614 if (!DATA_FITS(sb, data_len)) {
40af9aad 615 return -1;
81b2984c
VJ
616 }
617
618 memcpy(sb->buf + sb->buf_offset, data, data_len);
619 seg->stream_offset = sb->stream_offset + sb->buf_offset;
620 seg->segment_len = data_len;
d789dc7e 621 uint32_t rel_offset = sb->buf_offset;
81b2984c 622 sb->buf_offset += data_len;
d789dc7e 623
450500e6 624 if (!RB_EMPTY(&sb->sbb_tree)) {
d789dc7e
VJ
625 SBBUpdate(sb, rel_offset, data_len);
626 }
40af9aad 627 return 0;
81b2984c
VJ
628}
629
630/**
631 * \brief add data w/o tracking a segment
632 */
40af9aad
VJ
633int StreamingBufferAppendNoTrack(StreamingBuffer *sb,
634 const uint8_t *data, uint32_t data_len)
81b2984c
VJ
635{
636 if (sb->buf == NULL) {
637 if (InitBuffer(sb) == -1)
40af9aad 638 return -1;
81b2984c
VJ
639 }
640
641 if (!DATA_FITS(sb, data_len)) {
642 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
643 AutoSlide(sb);
644 if (sb->buf_size == 0) {
40af9aad
VJ
645 if (GrowToSize(sb, data_len) != 0)
646 return -1;
81b2984c
VJ
647 } else {
648 while (!DATA_FITS(sb, data_len)) {
40af9aad
VJ
649 if (Grow(sb) != 0) {
650 return -1;
651 }
81b2984c
VJ
652 }
653 }
654 }
655 if (!DATA_FITS(sb, data_len)) {
40af9aad 656 return -1;
81b2984c
VJ
657 }
658
659 memcpy(sb->buf + sb->buf_offset, data, data_len);
d789dc7e 660 uint32_t rel_offset = sb->buf_offset;
81b2984c 661 sb->buf_offset += data_len;
d789dc7e 662
450500e6 663 if (!RB_EMPTY(&sb->sbb_tree)) {
d789dc7e
VJ
664 SBBUpdate(sb, rel_offset, data_len);
665 }
40af9aad 666 return 0;
81b2984c
VJ
667}
668
669#define DATA_FITS_AT_OFFSET(sb, len, offset) \
670 ((offset) + (len) <= (sb)->buf_size)
671
672/**
673 * \param offset offset relative to StreamingBuffer::stream_offset
0e70958e
EL
674 *
675 * \return 0 in case of success
676 * \return -1 on memory allocation errors
677 * \return negative value on other errors
81b2984c 678 */
40af9aad
VJ
679int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg,
680 const uint8_t *data, uint32_t data_len,
681 uint64_t offset)
81b2984c
VJ
682{
683 BUG_ON(seg == NULL);
684
685 if (offset < sb->stream_offset)
0e70958e 686 return -2;
81b2984c
VJ
687
688 if (sb->buf == NULL) {
689 if (InitBuffer(sb) == -1)
40af9aad 690 return -1;
81b2984c
VJ
691 }
692
693 uint32_t rel_offset = offset - sb->stream_offset;
694 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
695 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) {
696 AutoSlide(sb);
697 rel_offset = offset - sb->stream_offset;
698 }
699 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
40af9aad
VJ
700 if (GrowToSize(sb, (rel_offset + data_len)) != 0)
701 return -1;
81b2984c
VJ
702 }
703 }
3fa2e868 704 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
0e70958e 705 return -2;
3fa2e868 706 }
81b2984c
VJ
707
708 memcpy(sb->buf + rel_offset, data, data_len);
709 seg->stream_offset = offset;
710 seg->segment_len = data_len;
d789dc7e
VJ
711
712 SCLogDebug("rel_offset %u sb->stream_offset %"PRIu64", buf_offset %u",
713 rel_offset, sb->stream_offset, sb->buf_offset);
714
450500e6 715 if (RB_EMPTY(&sb->sbb_tree)) {
d789dc7e
VJ
716 SCLogDebug("empty sbb list");
717
718 if (sb->stream_offset == offset) {
719 SCLogDebug("empty sbb list: block exactly what was expected, fall through");
720 /* empty list, data is exactly what is expected (append),
721 * so do nothing */
722 } else if ((rel_offset + data_len) <= sb->buf_offset) {
723 SCLogDebug("empty sbb list: block is within existing region");
724 } else {
725 if (sb->buf_offset && rel_offset == sb->buf_offset) {
726 // nothing to do
727 } else if (rel_offset < sb->buf_offset) {
728 // nothing to do
729 } else if (sb->buf_offset) {
730 /* existing data, but there is a gap between us */
731 SBBInit(sb, rel_offset, data_len);
732 } else {
733 /* gap before data in empty list */
734 SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
735 SBBInitLeadingGap(sb, offset, data_len);
736 }
737 }
738 } else {
739 /* already have blocks, so append new block based on new data */
740 SBBUpdate(sb, rel_offset, data_len);
741 }
742
81b2984c
VJ
743 if (rel_offset + data_len > sb->buf_offset)
744 sb->buf_offset = rel_offset + data_len;
d789dc7e 745
40af9aad 746 return 0;
81b2984c
VJ
747}
748
749int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb,
750 const StreamingBufferSegment *seg)
751{
752 if (seg->stream_offset < sb->stream_offset) {
753 if (seg->stream_offset + seg->segment_len <= sb->stream_offset) {
754 return 1;
755 }
756 }
757 return 0;
758}
759
d789dc7e
VJ
760/** \brief get the data for one SBB */
761void StreamingBufferSBBGetData(const StreamingBuffer *sb,
762 const StreamingBufferBlock *sbb,
763 const uint8_t **data, uint32_t *data_len)
764{
765 if (sbb->offset >= sb->stream_offset) {
766 uint64_t offset = sbb->offset - sb->stream_offset;
767 *data = sb->buf + offset;
c306c02f
VJ
768 if (offset + sbb->len > sb->buf_offset)
769 *data_len = sb->buf_offset - offset;
d789dc7e
VJ
770 else
771 *data_len = sbb->len;
772 return;
773 } else {
774 uint64_t offset = sb->stream_offset - sbb->offset;
775 if (offset < sbb->len) {
776 *data = sb->buf;
777 *data_len = sbb->len - offset;
778 return;
779 }
780 }
781 *data = NULL;
782 *data_len = 0;
783 return;
784}
785
786/** \brief get the data for one SBB */
787void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb,
788 const StreamingBufferBlock *sbb,
789 const uint8_t **data, uint32_t *data_len,
790 uint64_t offset)
791{
792 if (offset >= sbb->offset && offset < (sbb->offset + sbb->len)) {
793 uint32_t sbblen = sbb->len - (offset - sbb->offset);
794
795 if (offset >= sb->stream_offset) {
796 uint64_t data_offset = offset - sb->stream_offset;
797 *data = sb->buf + data_offset;
798 if (data_offset + sbblen > sb->buf_size)
799 *data_len = sb->buf_size - data_offset;
800 else
801 *data_len = sbblen;
802 BUG_ON(*data_len > sbblen);
803 return;
804 } else {
805 uint64_t data_offset = sb->stream_offset - sbb->offset;
806 if (data_offset < sbblen) {
807 *data = sb->buf;
808 *data_len = sbblen - data_offset;
809 BUG_ON(*data_len > sbblen);
810 return;
811 }
812 }
813 }
814
815 *data = NULL;
816 *data_len = 0;
817 return;
818}
819
81b2984c
VJ
820void StreamingBufferSegmentGetData(const StreamingBuffer *sb,
821 const StreamingBufferSegment *seg,
822 const uint8_t **data, uint32_t *data_len)
823{
3fa2e868
VJ
824 if (likely(sb->buf)) {
825 if (seg->stream_offset >= sb->stream_offset) {
826 uint64_t offset = seg->stream_offset - sb->stream_offset;
827 *data = sb->buf + offset;
828 if (offset + seg->segment_len > sb->buf_size)
829 *data_len = sb->buf_size - offset;
830 else
831 *data_len = seg->segment_len;
81b2984c 832 return;
3fa2e868
VJ
833 } else {
834 uint64_t offset = sb->stream_offset - seg->stream_offset;
835 if (offset < seg->segment_len) {
836 *data = sb->buf;
837 *data_len = seg->segment_len - offset;
838 return;
839 }
81b2984c
VJ
840 }
841 }
842 *data = NULL;
843 *data_len = 0;
844 return;
845}
846
847/**
848 * \retval 1 data is the same
849 * \retval 0 data is different
850 */
851int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb,
852 const StreamingBufferSegment *seg,
853 const uint8_t *rawdata, uint32_t rawdata_len)
854{
855 const uint8_t *segdata = NULL;
856 uint32_t segdata_len = 0;
857 StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len);
858 if (segdata && segdata_len &&
859 segdata_len == rawdata_len &&
860 memcmp(segdata, rawdata, segdata_len) == 0)
861 {
862 return 1;
863 }
864 return 0;
865}
866
867int StreamingBufferGetData(const StreamingBuffer *sb,
868 const uint8_t **data, uint32_t *data_len,
869 uint64_t *stream_offset)
870{
871 if (sb != NULL && sb->buf != NULL) {
872 *data = sb->buf;
873 *data_len = sb->buf_offset;
874 *stream_offset = sb->stream_offset;
875 return 1;
876 } else {
877 *data = NULL;
878 *data_len = 0;
879 *stream_offset = 0;
880 return 0;
881 }
882}
883
884int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb,
885 const uint8_t **data, uint32_t *data_len,
886 uint64_t offset)
887{
888 if (sb != NULL && sb->buf != NULL &&
889 offset >= sb->stream_offset &&
890 offset < (sb->stream_offset + sb->buf_offset))
891 {
892 uint32_t skip = offset - sb->stream_offset;
893 *data = sb->buf + skip;
894 *data_len = sb->buf_offset - skip;
895 return 1;
896 } else {
897 *data = NULL;
898 *data_len = 0;
899 return 0;
900 }
901}
902
903/**
904 * \retval 1 data is the same
905 * \retval 0 data is different
906 */
907int StreamingBufferCompareRawData(const StreamingBuffer *sb,
908 const uint8_t *rawdata, uint32_t rawdata_len)
909{
910 const uint8_t *sbdata = NULL;
911 uint32_t sbdata_len = 0;
912 uint64_t offset = 0;
913 StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset);
914 if (offset == 0 &&
915 sbdata && sbdata_len &&
916 sbdata_len == rawdata_len &&
917 memcmp(sbdata, rawdata, sbdata_len) == 0)
918 {
919 return 1;
920 }
afed6fe4 921 SCLogDebug("sbdata_len %u, offset %"PRIu64, sbdata_len, offset);
3fa2e868
VJ
922 printf("got:\n");
923 PrintRawDataFp(stdout, sbdata,sbdata_len);
924 printf("wanted:\n");
925 PrintRawDataFp(stdout, rawdata,rawdata_len);
81b2984c
VJ
926 return 0;
927}
928
ab1200fb
VJ
929#ifdef UNITTESTS
930static void Dump(StreamingBuffer *sb)
81b2984c
VJ
931{
932 PrintRawDataFp(stdout, sb->buf, sb->buf_offset);
933}
934
ab1200fb 935static void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg)
81b2984c
VJ
936{
937 const uint8_t *data = NULL;
938 uint32_t data_len = 0;
939 StreamingBufferSegmentGetData(sb, seg, &data, &data_len);
940 if (data && data_len) {
941 PrintRawDataFp(stdout, data, data_len);
942 }
943}
944
81b2984c
VJ
945static int StreamingBufferTest01(void)
946{
947 StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 16, NULL, NULL, NULL, NULL };
948 StreamingBuffer *sb = StreamingBufferInit(&cfg);
949 FAIL_IF(sb == NULL);
950
951 StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(sb, (const uint8_t *)"ABCDEFGH", 8);
952 StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(sb, (const uint8_t *)"01234567", 8);
953 FAIL_IF(sb->stream_offset != 0);
954 FAIL_IF(sb->buf_offset != 16);
955 FAIL_IF(seg1->stream_offset != 0);
956 FAIL_IF(seg2->stream_offset != 8);
957 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg1));
958 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
959 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg1,(const uint8_t *)"ABCDEFGH", 8));
960 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg2,(const uint8_t *)"01234567", 8));
961 Dump(sb);
be1baa8c 962 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 963 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
964
965 StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(sb, (const uint8_t *)"QWERTY", 6);
966 FAIL_IF(sb->stream_offset != 8);
967 FAIL_IF(sb->buf_offset != 14);
968 FAIL_IF(seg3->stream_offset != 16);
969 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
970 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
971 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
972 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg3,(const uint8_t *)"QWERTY", 6));
973 Dump(sb);
be1baa8c 974 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 975 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
976
977 StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(sb, (const uint8_t *)"KLM", 3);
978 FAIL_IF(sb->stream_offset != 14);
979 FAIL_IF(sb->buf_offset != 11);
980 FAIL_IF(seg4->stream_offset != 22);
981 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
982 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
983 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
984 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
985 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg4,(const uint8_t *)"KLM", 3));
986 Dump(sb);
be1baa8c 987 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 988 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
989
990 StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(sb, (const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27);
991 FAIL_IF(sb->stream_offset != 17);
992 FAIL_IF(sb->buf_offset != 35);
993 FAIL_IF(seg5->stream_offset != 25);
994 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
995 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2));
996 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
997 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
998 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5));
999 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg5,(const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27));
1000 Dump(sb);
be1baa8c 1001 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1002 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1003
1004 StreamingBufferSegment *seg6 = StreamingBufferAppendRaw(sb, (const uint8_t *)"UVWXYZ", 6);
1005 FAIL_IF(sb->stream_offset != 17);
1006 FAIL_IF(sb->buf_offset != 41);
1007 FAIL_IF(seg6->stream_offset != 52);
1008 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
1009 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2));
1010 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
1011 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
1012 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5));
1013 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg6));
1014 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg6,(const uint8_t *)"UVWXYZ", 6));
1015 Dump(sb);
be1baa8c 1016 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1017 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1018
1019 SCFree(seg1);
1020 SCFree(seg2);
1021 SCFree(seg3);
1022 SCFree(seg4);
1023 SCFree(seg5);
1024 SCFree(seg6);
1025 StreamingBufferFree(sb);
1026 PASS;
1027}
1028
1029static int StreamingBufferTest02(void)
1030{
1031 StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL };
1032 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1033 FAIL_IF(sb == NULL);
1034
1035 StreamingBufferSegment seg1;
40af9aad 1036 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
81b2984c 1037 StreamingBufferSegment seg2;
40af9aad 1038 FAIL_IF(StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8) != 0);
81b2984c
VJ
1039 FAIL_IF(sb->stream_offset != 0);
1040 FAIL_IF(sb->buf_offset != 16);
1041 FAIL_IF(seg1.stream_offset != 0);
1042 FAIL_IF(seg2.stream_offset != 8);
1043 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1044 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1045 Dump(sb);
1046 DumpSegment(sb, &seg1);
1047 DumpSegment(sb, &seg2);
be1baa8c 1048 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1049 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1050
1051 StreamingBufferSlide(sb, 6);
be1baa8c 1052 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1053 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1054
1055 StreamingBufferSegment seg3;
40af9aad 1056 FAIL_IF(StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6) != 0);
81b2984c
VJ
1057 FAIL_IF(sb->stream_offset != 6);
1058 FAIL_IF(sb->buf_offset != 16);
1059 FAIL_IF(seg3.stream_offset != 16);
1060 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1061 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1062 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1063 Dump(sb);
1064 DumpSegment(sb, &seg1);
1065 DumpSegment(sb, &seg2);
1066 DumpSegment(sb, &seg3);
be1baa8c 1067 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1068 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1069
1070 StreamingBufferSlide(sb, 6);
1071 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1072 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1073 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1074 Dump(sb);
1075 DumpSegment(sb, &seg1);
1076 DumpSegment(sb, &seg2);
1077 DumpSegment(sb, &seg3);
be1baa8c 1078 FAIL_IF_NOT_NULL(sb->head);
bbf1f78f 1079 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1080
1081 StreamingBufferFree(sb);
1082 PASS;
1083}
1084
1085static int StreamingBufferTest03(void)
1086{
1087 StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL };
1088 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1089 FAIL_IF(sb == NULL);
1090
1091 StreamingBufferSegment seg1;
40af9aad 1092 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
81b2984c 1093 StreamingBufferSegment seg2;
40af9aad 1094 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
81b2984c
VJ
1095 FAIL_IF(sb->stream_offset != 0);
1096 FAIL_IF(sb->buf_offset != 22);
1097 FAIL_IF(seg1.stream_offset != 0);
1098 FAIL_IF(seg2.stream_offset != 14);
1099 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1100 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1101 Dump(sb);
1102 DumpSegment(sb, &seg1);
1103 DumpSegment(sb, &seg2);
be1baa8c
VJ
1104 FAIL_IF_NULL(sb->head);
1105 FAIL_IF_NOT(sb->sbb_size == 16);
bbf1f78f 1106 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1107
1108 StreamingBufferSegment seg3;
40af9aad 1109 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
81b2984c
VJ
1110 FAIL_IF(sb->stream_offset != 0);
1111 FAIL_IF(sb->buf_offset != 22);
1112 FAIL_IF(seg3.stream_offset != 8);
1113 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1114 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1115 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1116 Dump(sb);
1117 DumpSegment(sb, &seg1);
1118 DumpSegment(sb, &seg2);
1119 DumpSegment(sb, &seg3);
be1baa8c
VJ
1120 FAIL_IF_NULL(sb->head);
1121 FAIL_IF_NOT(sb->sbb_size == 22);
bbf1f78f 1122 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1123
1124 StreamingBufferSlide(sb, 10);
1125 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1126 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1127 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1128 Dump(sb);
1129 DumpSegment(sb, &seg1);
1130 DumpSegment(sb, &seg2);
1131 DumpSegment(sb, &seg3);
be1baa8c
VJ
1132 FAIL_IF_NULL(sb->head);
1133 FAIL_IF_NOT(sb->sbb_size == 12);
bbf1f78f 1134 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1135
1136 StreamingBufferFree(sb);
1137 PASS;
1138}
1139
1140static int StreamingBufferTest04(void)
1141{
1142 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1143 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1144 FAIL_IF(sb == NULL);
1145
1146 StreamingBufferSegment seg1;
40af9aad 1147 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
450500e6 1148 FAIL_IF(!RB_EMPTY(&sb->sbb_tree));
81b2984c 1149 StreamingBufferSegment seg2;
40af9aad 1150 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
81b2984c
VJ
1151 FAIL_IF(sb->stream_offset != 0);
1152 FAIL_IF(sb->buf_offset != 22);
1153 FAIL_IF(seg1.stream_offset != 0);
1154 FAIL_IF(seg2.stream_offset != 14);
1155 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1156 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
450500e6
VJ
1157 FAIL_IF(RB_EMPTY(&sb->sbb_tree));
1158 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
bbf1f78f 1159 FAIL_IF(sbb1 != sb->head);
450500e6
VJ
1160 FAIL_IF_NULL(sbb1);
1161 FAIL_IF(sbb1->offset != 0);
1162 FAIL_IF(sbb1->len != 8);
1163 StreamingBufferBlock *sbb2 = SBB_RB_NEXT(sbb1);
1164 FAIL_IF_NULL(sbb2);
bbf1f78f 1165 FAIL_IF(sbb2 == sb->head);
450500e6
VJ
1166 FAIL_IF(sbb2->offset != 14);
1167 FAIL_IF(sbb2->len != 8);
81b2984c
VJ
1168 Dump(sb);
1169 DumpSegment(sb, &seg1);
1170 DumpSegment(sb, &seg2);
bbf1f78f 1171 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1172
1173 StreamingBufferSegment seg3;
40af9aad 1174 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
81b2984c
VJ
1175 FAIL_IF(sb->stream_offset != 0);
1176 FAIL_IF(sb->buf_offset != 22);
1177 FAIL_IF(seg3.stream_offset != 8);
1178 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1179 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1180 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
450500e6
VJ
1181 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1182 FAIL_IF_NULL(sbb1);
bbf1f78f 1183 FAIL_IF(sbb1 != sb->head);
450500e6
VJ
1184 FAIL_IF(sbb1->offset != 0);
1185 FAIL_IF(sbb1->len != 22);
1186 FAIL_IF(SBB_RB_NEXT(sbb1));
81b2984c
VJ
1187 Dump(sb);
1188 DumpSegment(sb, &seg1);
1189 DumpSegment(sb, &seg2);
1190 DumpSegment(sb, &seg3);
be1baa8c
VJ
1191 FAIL_IF_NULL(sb->head);
1192 FAIL_IF_NOT(sb->sbb_size == 22);
bbf1f78f 1193 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1194
1195 /* far ahead of curve: */
1196 StreamingBufferSegment seg4;
40af9aad 1197 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0);
81b2984c
VJ
1198 FAIL_IF(sb->stream_offset != 0);
1199 FAIL_IF(sb->buf_offset != 127);
1200 FAIL_IF(sb->buf_size != 128);
1201 FAIL_IF(seg4.stream_offset != 124);
1202 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1203 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1204 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1205 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4));
450500e6
VJ
1206 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1207 FAIL_IF_NULL(sbb1);
bbf1f78f 1208 FAIL_IF(sbb1 != sb->head);
450500e6
VJ
1209 FAIL_IF(sbb1->offset != 0);
1210 FAIL_IF(sbb1->len != 22);
1211 FAIL_IF(!SBB_RB_NEXT(sbb1));
81b2984c
VJ
1212 Dump(sb);
1213 DumpSegment(sb, &seg1);
1214 DumpSegment(sb, &seg2);
1215 DumpSegment(sb, &seg3);
1216 DumpSegment(sb, &seg4);
be1baa8c
VJ
1217 FAIL_IF_NULL(sb->head);
1218 FAIL_IF_NOT(sb->sbb_size == 25);
bbf1f78f 1219 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
81b2984c
VJ
1220
1221 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8));
1222 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8));
1223 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6));
1224 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3));
1225
1226 StreamingBufferFree(sb);
1227 PASS;
1228}
1229
1230static int StreamingBufferTest05(void)
1231{
1232 StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 32, NULL, NULL, NULL, NULL };
1233 StreamingBuffer sb = STREAMING_BUFFER_INITIALIZER(&cfg);
1234
1235 StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"AAAAAAAA", 8);
1236 StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"BBBBBBBB", 8);
1237 StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"CCCCCCCC", 8);
1238 StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"DDDDDDDD", 8);
1239 FAIL_IF(sb.stream_offset != 0);
1240 FAIL_IF(sb.buf_offset != 32);
1241 FAIL_IF(seg1->stream_offset != 0);
1242 FAIL_IF(seg2->stream_offset != 8);
1243 FAIL_IF(seg3->stream_offset != 16);
1244 FAIL_IF(seg4->stream_offset != 24);
1245 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg1));
1246 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg2));
1247 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg3));
1248 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg4));
1249 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg1,(const uint8_t *)"AAAAAAAA", 8));
1250 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg2,(const uint8_t *)"BBBBBBBB", 8));
1251 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg3,(const uint8_t *)"CCCCCCCC", 8));
1252 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg4,(const uint8_t *)"DDDDDDDD", 8));
1253 Dump(&sb);
bbf1f78f 1254 FAIL_IF_NOT(sb.head == RB_MIN(SBB, &sb.sbb_tree));
81b2984c
VJ
1255 StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"EEEEEEEE", 8);
1256 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg5,(const uint8_t *)"EEEEEEEE", 8));
1257 Dump(&sb);
bbf1f78f 1258 FAIL_IF_NOT(sb.head == RB_MIN(SBB, &sb.sbb_tree));
81b2984c
VJ
1259
1260 SCFree(seg1);
1261 SCFree(seg2);
1262 SCFree(seg3);
1263 SCFree(seg4);
1264 SCFree(seg5);
1265 StreamingBufferClear(&sb);
1266 PASS;
1267}
d789dc7e
VJ
1268
1269/** \test lots of gaps in block list */
1270static int StreamingBufferTest06(void)
1271{
1272 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1273 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1274 FAIL_IF(sb == NULL);
1275
1276 StreamingBufferSegment seg1;
1277 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"A", 1) != 0);
1278 StreamingBufferSegment seg2;
1279 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"C", 1, 2) != 0);
1280 Dump(sb);
be1baa8c
VJ
1281 FAIL_IF_NULL(sb->head);
1282 FAIL_IF_NOT(sb->sbb_size == 2);
bbf1f78f 1283 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1284
1285 StreamingBufferSegment seg3;
1286 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1287 Dump(sb);
be1baa8c
VJ
1288 FAIL_IF_NULL(sb->head);
1289 FAIL_IF_NOT(sb->sbb_size == 3);
bbf1f78f 1290 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1291
1292 StreamingBufferSegment seg4;
1293 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1294 Dump(sb);
be1baa8c
VJ
1295 FAIL_IF_NULL(sb->head);
1296 FAIL_IF_NOT(sb->sbb_size == 4);
bbf1f78f 1297 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1298
1299 StreamingBufferSegment seg5;
1300 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1301 Dump(sb);
450500e6
VJ
1302 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1303 FAIL_IF_NULL(sbb1);
1304 FAIL_IF(sbb1->offset != 0);
1305 FAIL_IF(sbb1->len != 10);
1306 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1307 FAIL_IF_NULL(sb->head);
1308 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1309 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1310
1311 StreamingBufferSegment seg6;
1312 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1313 Dump(sb);
450500e6
VJ
1314 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1315 FAIL_IF_NULL(sbb1);
1316 FAIL_IF(sbb1->offset != 0);
1317 FAIL_IF(sbb1->len != 10);
1318 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1319 FAIL_IF_NULL(sb->head);
1320 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1321 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1322
1323 StreamingBufferFree(sb);
1324 PASS;
1325}
1326
1327/** \test lots of gaps in block list */
1328static int StreamingBufferTest07(void)
1329{
1330 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1331 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1332 FAIL_IF(sb == NULL);
1333
1334 StreamingBufferSegment seg1;
1335 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1336 StreamingBufferSegment seg2;
1337 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1338 Dump(sb);
be1baa8c
VJ
1339 FAIL_IF_NULL(sb->head);
1340 FAIL_IF_NOT(sb->sbb_size == 2);
bbf1f78f 1341 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1342
1343 StreamingBufferSegment seg3;
1344 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1345 Dump(sb);
be1baa8c
VJ
1346 FAIL_IF_NULL(sb->head);
1347 FAIL_IF_NOT(sb->sbb_size == 3);
bbf1f78f 1348 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1349
1350 StreamingBufferSegment seg4;
1351 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1352 Dump(sb);
be1baa8c
VJ
1353 FAIL_IF_NULL(sb->head);
1354 FAIL_IF_NOT(sb->sbb_size == 4);
bbf1f78f 1355 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1356
1357 StreamingBufferSegment seg5;
1358 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1359 Dump(sb);
450500e6
VJ
1360 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1361 FAIL_IF_NULL(sbb1);
1362 FAIL_IF(sbb1->offset != 0);
1363 FAIL_IF(sbb1->len != 10);
1364 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1365 FAIL_IF_NULL(sb->head);
1366 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1367 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1368
1369 StreamingBufferSegment seg6;
1370 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1371 Dump(sb);
450500e6
VJ
1372 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1373 FAIL_IF_NULL(sbb1);
1374 FAIL_IF(sbb1->offset != 0);
1375 FAIL_IF(sbb1->len != 10);
1376 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1377 FAIL_IF_NULL(sb->head);
1378 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1379 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1380
1381 StreamingBufferFree(sb);
1382 PASS;
1383}
1384
1385/** \test lots of gaps in block list */
1386static int StreamingBufferTest08(void)
1387{
1388 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1389 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1390 FAIL_IF(sb == NULL);
1391
1392 StreamingBufferSegment seg1;
1393 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1394 StreamingBufferSegment seg2;
1395 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1396 Dump(sb);
be1baa8c
VJ
1397 FAIL_IF_NULL(sb->head);
1398 FAIL_IF_NOT(sb->sbb_size == 2);
bbf1f78f 1399 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1400
1401 StreamingBufferSegment seg3;
1402 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1403 Dump(sb);
be1baa8c
VJ
1404 FAIL_IF_NULL(sb->head);
1405 FAIL_IF_NOT(sb->sbb_size == 3);
bbf1f78f 1406 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1407
1408 StreamingBufferSegment seg4;
1409 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1410 Dump(sb);
be1baa8c
VJ
1411 FAIL_IF_NULL(sb->head);
1412 FAIL_IF_NOT(sb->sbb_size == 4);
bbf1f78f 1413 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1414
1415 StreamingBufferSegment seg5;
1416 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1417 Dump(sb);
450500e6
VJ
1418 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1419 FAIL_IF_NULL(sbb1);
1420 FAIL_IF(sbb1->offset != 0);
1421 FAIL_IF(sbb1->len != 10);
1422 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1423 FAIL_IF_NULL(sb->head);
1424 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1425 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1426
1427 StreamingBufferSegment seg6;
1428 FAIL_IF(StreamingBufferAppend(sb, &seg6, (const uint8_t *)"abcdefghij", 10) != 0);
1429 Dump(sb);
450500e6
VJ
1430 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1431 FAIL_IF_NULL(sbb1);
1432 FAIL_IF(sbb1->offset != 0);
1433 FAIL_IF(sbb1->len != 20);
1434 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1435 FAIL_IF_NULL(sb->head);
1436 FAIL_IF_NOT(sb->sbb_size == 20);
bbf1f78f 1437 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1438
1439 StreamingBufferFree(sb);
1440 PASS;
1441}
1442
1443/** \test lots of gaps in block list */
1444static int StreamingBufferTest09(void)
1445{
1446 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1447 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1448 FAIL_IF(sb == NULL);
1449
1450 StreamingBufferSegment seg1;
1451 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1452 StreamingBufferSegment seg2;
1453 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1454 Dump(sb);
be1baa8c
VJ
1455 FAIL_IF_NULL(sb->head);
1456 FAIL_IF_NOT(sb->sbb_size == 2);
bbf1f78f 1457 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1458
1459 StreamingBufferSegment seg3;
1460 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"H", 1, 7) != 0);
1461 Dump(sb);
be1baa8c
VJ
1462 FAIL_IF_NULL(sb->head);
1463 FAIL_IF_NOT(sb->sbb_size == 3);
bbf1f78f 1464 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1465
1466 StreamingBufferSegment seg4;
1467 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"F", 1, 5) != 0);
1468 Dump(sb);
be1baa8c
VJ
1469 FAIL_IF_NULL(sb->head);
1470 FAIL_IF_NOT(sb->sbb_size == 4);
bbf1f78f 1471 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1472
1473 StreamingBufferSegment seg5;
1474 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1475 Dump(sb);
450500e6
VJ
1476 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1477 FAIL_IF_NULL(sbb1);
1478 FAIL_IF(sbb1->offset != 0);
1479 FAIL_IF(sbb1->len != 10);
1480 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1481 FAIL_IF_NULL(sb->head);
1482 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1483 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1484
1485 StreamingBufferSegment seg6;
1486 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1487 Dump(sb);
450500e6
VJ
1488 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1489 FAIL_IF_NULL(sbb1);
1490 FAIL_IF(sbb1->offset != 0);
1491 FAIL_IF(sbb1->len != 10);
1492 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1493 FAIL_IF_NULL(sb->head);
1494 FAIL_IF_NOT(sb->sbb_size == 10);
bbf1f78f 1495 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
d789dc7e
VJ
1496
1497 StreamingBufferFree(sb);
1498 PASS;
1499}
1500
1501/** \test lots of gaps in block list */
1502static int StreamingBufferTest10(void)
1503{
1504 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1505 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1506 FAIL_IF(sb == NULL);
1507
1508 StreamingBufferSegment seg1;
1509 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"A", 1, 0) != 0);
450500e6 1510 Dump(sb);
d789dc7e
VJ
1511 StreamingBufferSegment seg2;
1512 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1513 Dump(sb);
d789dc7e
VJ
1514 StreamingBufferSegment seg3;
1515 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"H", 1, 7) != 0);
1516 Dump(sb);
be1baa8c
VJ
1517 FAIL_IF_NULL(sb->head);
1518 FAIL_IF_NOT(sb->sbb_size == 3);
d789dc7e
VJ
1519
1520 StreamingBufferSegment seg4;
1521 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"B", 1, 1) != 0);
1522 Dump(sb);
1523 StreamingBufferSegment seg5;
1524 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"C", 1, 2) != 0);
1525 Dump(sb);
1526 StreamingBufferSegment seg6;
1527 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"G", 1, 6) != 0);
1528 Dump(sb);
bbf1f78f 1529 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
be1baa8c
VJ
1530 FAIL_IF_NULL(sb->head);
1531 FAIL_IF_NOT(sb->sbb_size == 6);
d789dc7e
VJ
1532
1533 StreamingBufferSegment seg7;
1534 FAIL_IF(StreamingBufferInsertAt(sb, &seg7, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1535 Dump(sb);
450500e6
VJ
1536 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1537 FAIL_IF_NULL(sbb1);
1538 FAIL_IF(sbb1->offset != 0);
1539 FAIL_IF(sbb1->len != 10);
1540 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1541 FAIL_IF_NULL(sb->head);
1542 FAIL_IF_NOT(sb->sbb_size == 10);
d789dc7e
VJ
1543
1544 StreamingBufferSegment seg8;
1545 FAIL_IF(StreamingBufferInsertAt(sb, &seg8, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1546 Dump(sb);
450500e6 1547 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
bbf1f78f 1548 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
450500e6
VJ
1549 FAIL_IF_NULL(sbb1);
1550 FAIL_IF(sbb1->offset != 0);
1551 FAIL_IF(sbb1->len != 10);
1552 FAIL_IF(SBB_RB_NEXT(sbb1));
be1baa8c
VJ
1553 FAIL_IF_NULL(sb->head);
1554 FAIL_IF_NOT(sb->sbb_size == 10);
d789dc7e
VJ
1555
1556 StreamingBufferFree(sb);
1557 PASS;
1558}
1559
81b2984c
VJ
1560#endif
1561
1562void StreamingBufferRegisterTests(void)
1563{
1564#ifdef UNITTESTS
1565 UtRegisterTest("StreamingBufferTest01", StreamingBufferTest01);
1566 UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02);
1567 UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03);
1568 UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04);
1569 UtRegisterTest("StreamingBufferTest05", StreamingBufferTest05);
d789dc7e
VJ
1570 UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06);
1571 UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07);
1572 UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
1573 UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
1574 UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
81b2984c
VJ
1575#endif
1576}