5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 /* Optimized buffer managing routines. These are short inline functions. */
25 /****h* silcutil/SILC Buffer Interface
29 * SilcBuffer is very simple and easy to use, yet you can do to the
30 * buffer almost anything you want with its method functions. The buffer
31 * is constructed of four different data sections that in whole creates
32 * the allocated data area.
34 * This buffer scheme is based on Linux kernel's Socket Buffer, the
35 * idea were taken directly from there and credits should go there.
39 /****s* silcutil/SilcBufferAPI/SilcBuffer
43 * typedef struct { ... } *SilcBuffer, SilcBufferStruct;
47 * SILC Buffer object. Following short description of the fields
54 * True length of the buffer. This is set at the allocation of the
55 * buffer and it should not be touched after that. This field should
56 * be considered read-only.
60 * Length of the currently valid data area. Tells the length of the
61 * data at the buffer. This is set to zero at the allocation of the
62 * buffer and should not be updated by hand. Method functions of the
63 * buffer automatically updates this field. However, it is not
64 * read-only field and can be updated manually if necessary.
68 * Head of the allocated buffer. This is the start of the allocated
69 * data area and remains as same throughout the lifetime of the buffer.
70 * However, the end of the head area or the start of the currently valid
71 * data area is variable.
73 * --------------------------------
74 * | head | data | tail |
75 * --------------------------------
78 * Current head section in the buffer is sb->data - sb->head.
80 * unsigned char *data;
82 * Currently valid data area. This is the start of the currently valid
83 * main data area. The data area is variable in all directions.
85 * --------------------------------
86 * | head | data | tail |
87 * --------------------------------
90 * Current valid data area in the buffer is sb->tail - sb->data.
92 * unsigned char *tail;
94 * Tail of the buffer. This is the end of the currently valid data area
95 * or start of the tail area. The start of the tail area is variable.
97 * --------------------------------
98 * | head | data | tail |
99 * --------------------------------
102 * Current tail section in the buffer is sb->end - sb->tail.
104 * unsigned char *end;
106 * End of the allocated buffer. This is the end of the allocated data
107 * area and remains as same throughout the lifetime of the buffer.
108 * Usually this field is not needed except when checking the size
111 * --------------------------------
112 * | head | data | tail |
113 * --------------------------------
116 * Length of the entire buffer is (ie. truelen) sb->end - sb->head.
118 * Currently valid data area is considered to be the main data area in
119 * the buffer. However, the entire buffer is of course valid data and can
120 * be used as such. Usually head section of the buffer includes different
121 * kind of headers or similar. Data section includes the main data of
122 * the buffer. Tail section can be seen as a reserve space of the data
123 * section. Tail section can be pulled towards end, and thus the data
124 * section becomes larger.
135 } *SilcBuffer, SilcBufferStruct;
140 /****d* silcutil/SilcBufferAPI/SILC_BUFFER_END
144 * #define SILC_BUFFER_END(...)
148 * Returns the true length of the buffer. This is used to pull
149 * the buffer area to the end of the buffer.
153 #define SILC_BUFFER_END(x) ((x)->end - (x)->head)
156 /* Inline functions */
158 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
163 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
167 * Allocates new SilcBuffer and returns it.
172 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
176 /* Allocate new SilcBuffer */
177 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
181 /* Allocate the actual data area */
182 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
186 /* Set pointers to the new buffer */
190 sb->end = sb->head + sb->truelen;
195 /****f* silcutil/SilcBufferAPI/silc_buffer_free
200 * void silc_buffer_free(SilcBuffer sb);
209 void silc_buffer_free(SilcBuffer sb)
212 #if defined(SILC_DEBUG)
214 memset(sb->head, 'F', sb->truelen);
221 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
226 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
230 * Steals the data from the buffer `sb'. This returns pointer to the
231 * start of the buffer and the true length of that buffer. The `sb'
232 * cannot be used anymore after calling this function because the
233 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
234 * The caller is responsible of freeing the stolen data buffer with
240 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
242 unsigned char *buf = sb->head;
244 *data_len = sb->truelen;
245 sb->head = sb->data = sb->tail = sb->end = NULL;
246 sb->len = sb->truelen = 0;
250 /****f* silcutil/SilcBufferAPI/silc_buffer_set
255 * void silc_buffer_set(SilcBuffer sb,
256 * unsigned char *data,
257 * SilcUInt32 data_len);
261 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
262 * The data area is automatically set to the `data_len'. This function
263 * can be used to set the data to static buffer without needing any
264 * memory allocations. The `data' will not be copied to the buffer.
269 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
271 sb->data = sb->head = data;
272 sb->tail = sb->end = data + data_len;
273 sb->len = sb->truelen = data_len;
276 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
281 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
285 * Pulls current data area towards end. The length of the currently
286 * valid data area is also decremented. Returns pointer to the data
287 * area before pulling.
291 * ---------------------------------
292 * | head | data | tail |
293 * ---------------------------------
295 * Pulls the start of the data area.
297 * ---------------------------------
298 * | head | data | tail |
299 * ---------------------------------
304 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
306 unsigned char *old_data = sb->data;
308 #if defined(SILC_DEBUG)
309 assert(len <= (SilcUInt32)(sb->tail - sb->data));
318 /****f* silcutil/SilcBufferAPI/silc_buffer_push
323 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
327 * Pushes current data area towards beginning. Length of the currently
328 * valid data area is also incremented. Returns a pointer to the
329 * data area before pushing.
333 * ---------------------------------
334 * | head | data | tail |
335 * ---------------------------------
337 * Pushes the start of the data area.
339 * ---------------------------------
340 * | head | data | tail |
341 * ---------------------------------
347 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
349 unsigned char *old_data = sb->data;
351 #if defined(SILC_DEBUG)
352 assert((sb->data - len) >= sb->head);
361 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
366 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
370 * Pulls current tail section towards end. Length of the current valid
371 * data area is also incremented. Returns a pointer to the data area
376 * ---------------------------------
377 * | head | data | tail |
378 * ---------------------------------
380 * Pulls the start of the tail section.
382 * ---------------------------------
383 * | head | data | tail |
384 * ---------------------------------
390 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
392 unsigned char *old_tail = sb->tail;
394 #if defined(SILC_DEBUG)
395 assert((SilcUInt32)(sb->end - sb->tail) >= len);
404 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
409 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
413 * Pushes current tail section towards beginning. Length of the current
414 * valid data area is also decremented. Returns a pointer to the
415 * tail section before pushing.
419 * ---------------------------------
420 * | head | data | tail |
421 * ---------------------------------
423 * Pushes the start of the tail section.
425 * ---------------------------------
426 * | head | data | tail |
427 * ---------------------------------
433 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
435 unsigned char *old_tail = sb->tail;
437 #if defined(SILC_DEBUG)
438 assert((sb->tail - len) >= sb->data);
447 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
452 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
453 * const unsigned char *data,
458 * Puts data at the head of the buffer. Returns pointer to the copied
463 * ---------------------------------
464 * | head | data | tail |
465 * ---------------------------------
467 * Puts data to the head section.
472 unsigned char *silc_buffer_put_head(SilcBuffer sb,
473 const unsigned char *data,
476 #if defined(SILC_DEBUG)
477 assert((SilcUInt32)(sb->data - sb->head) >= len);
479 return (unsigned char *)memcpy(sb->head, data, len);
482 /****f* silcutil/SilcBufferAPI/silc_buffer_put
487 * unsigned char *silc_buffer_put(SilcBuffer sb,
488 * const unsigned char *data,
493 * Puts data at the start of the valid data area. Returns a pointer
494 * to the copied data area.
498 * ---------------------------------
499 * | head | data | tail |
500 * ---------------------------------
502 * Puts data to the data section.
507 unsigned char *silc_buffer_put(SilcBuffer sb,
508 const unsigned char *data,
511 #if defined(SILC_DEBUG)
512 assert((SilcUInt32)(sb->tail - sb->data) >= len);
514 return (unsigned char *)memcpy(sb->data, data, len);
517 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
522 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
523 * const unsigned char *data,
528 * Puts data at the tail of the buffer. Returns pointer to the copied
533 * ---------------------------------
534 * | head | data | tail |
535 * ---------------------------------
537 * Puts data to the tail section.
542 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
543 const unsigned char *data,
546 #if defined(SILC_DEBUG)
547 assert((SilcUInt32)(sb->end - sb->tail) >= len);
549 return (unsigned char *)memcpy(sb->tail, data, len);
552 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
557 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
561 * Allocates `len' bytes size buffer and moves the tail area automatically
562 * `len' bytes so that the buffer is ready to use without calling the
563 * silc_buffer_pull_tail.
568 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
570 SilcBuffer sb = silc_buffer_alloc(len);
573 silc_buffer_pull_tail(sb, len);
577 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
582 * void silc_buffer_clear(SilcBuffer sb);
586 * Clears and initialiazes the buffer to the state as if it was just
587 * allocated by silc_buffer_alloc.
592 void silc_buffer_clear(SilcBuffer sb)
596 memset(sb->head, 0, sb->truelen);
602 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
607 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
611 * Generates copy of a SilcBuffer. This copies everything inside the
612 * currently valid data area, nothing more. Use silc_buffer_clone to
613 * copy entire buffer.
618 SilcBuffer silc_buffer_copy(SilcBuffer sb)
622 sb_new = silc_buffer_alloc_size(sb->len);
625 silc_buffer_put(sb_new, sb->data, sb->len);
630 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
635 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
639 * Clones SilcBuffer. This generates new SilcBuffer and copies
640 * everything from the source buffer. The result is exact clone of
641 * the original buffer.
646 SilcBuffer silc_buffer_clone(SilcBuffer sb)
650 sb_new = silc_buffer_alloc_size(sb->truelen);
653 silc_buffer_put(sb_new, sb->head, sb->truelen);
654 sb_new->data = sb_new->head + (sb->data - sb->head);
655 sb_new->tail = sb_new->data + sb->len;
656 sb_new->len = sb->len;
661 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
666 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
670 * Reallocates buffer. Old data is saved into the new buffer. Returns
671 * new SilcBuffer pointer. The buffer is exact clone of the old one
672 * except that there is now more space at the end of buffer.
677 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
682 return silc_buffer_alloc(newsize);
684 if (newsize <= sb->truelen)
687 sb_new = silc_buffer_alloc_size(newsize);
690 silc_buffer_put(sb_new, sb->head, sb->truelen);
691 sb_new->data = sb_new->head + (sb->data - sb->head);
692 sb_new->tail = sb_new->data + sb->len;
693 sb_new->len = sb->len;
695 silc_buffer_free(sb);