5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2006 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.
21 /****h* silcutil/SILC Buffer Interface
25 * SilcBuffer is very simple and easy to use, yet you can do to the
26 * buffer almost anything you want with its method functions. The buffer
27 * is constructed of four different data sections that in whole creates
28 * the allocated data area.
35 /****s* silcutil/SilcBufferAPI/SilcBuffer
39 * typedef struct { ... } *SilcBuffer, SilcBufferStruct;
43 * SILC Buffer object. Following short description of the fields
50 * Head of the allocated buffer. This is the start of the allocated
51 * data area and remains as same throughout the lifetime of the buffer.
52 * However, the end of the head area or the start of the currently valid
53 * data area is variable.
55 * --------------------------------
56 * | head | data | tail |
57 * --------------------------------
60 * Current head section in the buffer is sb->data - sb->head.
62 * unsigned char *data;
64 * Currently valid data area. This is the start of the currently valid
65 * main data area. The data area is variable in all directions.
67 * --------------------------------
68 * | head | data | tail |
69 * --------------------------------
72 * Current valid data area in the buffer is sb->tail - sb->data.
74 * unsigned char *tail;
76 * Tail of the buffer. This is the end of the currently valid data area
77 * or start of the tail area. The start of the tail area is variable.
79 * --------------------------------
80 * | head | data | tail |
81 * --------------------------------
84 * Current tail section in the buffer is sb->end - sb->tail.
88 * End of the allocated buffer. This is the end of the allocated data
89 * area and remains as same throughout the lifetime of the buffer.
90 * Usually this field is not needed except when checking the size
93 * --------------------------------
94 * | head | data | tail |
95 * --------------------------------
98 * Length of the entire buffer is (ie. truelen) sb->end - sb->head.
100 * Currently valid data area is considered to be the main data area in
101 * the buffer. However, the entire buffer is of course valid data and can
102 * be used as such. Usually head section of the buffer includes different
103 * kind of headers or similar. Data section includes the main data of
104 * the buffer. Tail section can be seen as a reserve space of the data
105 * section. Tail section can be pulled towards end, and thus the data
106 * section becomes larger.
115 } *SilcBuffer, SilcBufferStruct;
120 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
124 * #define silc_buffer_truelen(buffer)
128 * Returns the true length of the buffer.
132 #define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
135 /****d* silcutil/SilcBufferAPI/silc_buffer_len
139 * #define silc_buffer_len(buffer)
143 * Returns the current length of the data area of the buffer.
147 #define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
150 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
154 * #define silc_buffer_headlen(buffer)
158 * Returns the current length of the head data area of the buffer.
162 #define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
165 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
169 * #define silc_buffer_taillen(buffer)
173 * Returns the current length of the tail data area of the buffer.
177 #define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
180 /* Inline functions */
182 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
187 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
191 * Allocates new SilcBuffer and returns it. Returns NULL on error.
196 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
200 /* Allocate new SilcBuffer */
201 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
206 /* Allocate the actual data area */
207 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
211 /* Set pointers to the new buffer */
214 sb->end = sb->head + len;
220 /****f* silcutil/SilcBufferAPI/silc_buffer_free
225 * void silc_buffer_free(SilcBuffer sb);
234 void silc_buffer_free(SilcBuffer sb)
237 #if defined(SILC_DEBUG)
239 memset(sb->head, 'F', silc_buffer_truelen(sb));
246 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
251 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
255 * Steals the data from the buffer `sb'. This returns pointer to the
256 * start of the buffer and the true length of that buffer. The `sb'
257 * cannot be used anymore after calling this function because the
258 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
259 * The caller is responsible of freeing the stolen data buffer with
265 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
267 unsigned char *buf = sb->head;
269 *data_len = silc_buffer_truelen(sb);
270 sb->head = sb->data = sb->tail = sb->end = NULL;
274 /****f* silcutil/SilcBufferAPI/silc_buffer_set
279 * void silc_buffer_set(SilcBuffer sb,
280 * unsigned char *data,
281 * SilcUInt32 data_len);
285 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
286 * The data area is automatically set to the `data_len'. This function
287 * can be used to set the data to static buffer without needing any
288 * memory allocations. The `data' will not be copied to the buffer.
292 * SilcBufferStruct buf;
293 * silc_buffer_set(&buf, data, data_len);
298 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
300 sb->data = sb->head = data;
301 sb->tail = sb->end = data + data_len;
304 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
309 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
313 * Pulls current data area towards end. The length of the currently
314 * valid data area is also decremented. Returns pointer to the data
315 * area before pulling. Returns NULL on error.
319 * ---------------------------------
320 * | head | data | tail |
321 * ---------------------------------
323 * Pulls the start of the data area.
325 * ---------------------------------
326 * | head | data | tail |
327 * ---------------------------------
330 * silc_buffer_pull(sb, 20);
335 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
337 unsigned char *old_data = sb->data;
338 #if defined(SILC_DEBUG)
339 assert(len <= silc_buffer_len(sb));
341 if (len > silc_buffer_len(sb))
348 /****f* silcutil/SilcBufferAPI/silc_buffer_push
353 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
357 * Pushes current data area towards beginning. Length of the currently
358 * valid data area is also incremented. Returns a pointer to the
359 * data area before pushing. Returns NULL on error.
363 * ---------------------------------
364 * | head | data | tail |
365 * ---------------------------------
367 * Pushes the start of the data area.
369 * ---------------------------------
370 * | head | data | tail |
371 * ---------------------------------
374 * silc_buffer_push(sb, 20);
379 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
381 unsigned char *old_data = sb->data;
382 #if defined(SILC_DEBUG)
383 assert((sb->data - len) >= sb->head);
385 if ((sb->data - len) < sb->head)
392 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
397 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
401 * Pulls current tail section towards end. Length of the current valid
402 * data area is also incremented. Returns a pointer to the data area
403 * before pulling. Returns NULL on error.
407 * ---------------------------------
408 * | head | data | tail |
409 * ---------------------------------
411 * Pulls the start of the tail section.
413 * ---------------------------------
414 * | head | data | tail |
415 * ---------------------------------
418 * silc_buffer_pull_tail(sb, 23);
423 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
425 unsigned char *old_tail = sb->tail;
426 #if defined(SILC_DEBUG)
427 assert(len <= silc_buffer_taillen(sb));
429 if (len > silc_buffer_taillen(sb))
436 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
441 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
445 * Pushes current tail section towards beginning. Length of the current
446 * valid data area is also decremented. Returns a pointer to the
447 * tail section before pushing. Returns NULL on error.
451 * ---------------------------------
452 * | head | data | tail |
453 * ---------------------------------
455 * Pushes the start of the tail section.
457 * ---------------------------------
458 * | head | data | tail |
459 * ---------------------------------
462 * silc_buffer_push_tail(sb, 23);
467 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
469 unsigned char *old_tail = sb->tail;
470 #if defined(SILC_DEBUG)
471 assert((sb->tail - len) >= sb->data);
473 if ((sb->tail - len) < sb->data)
480 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
485 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
486 * const unsigned char *data,
491 * Puts data at the head of the buffer. Returns pointer to the copied
492 * data area. Returns NULL on error.
496 * ---------------------------------
497 * | head | data | tail |
498 * ---------------------------------
500 * Puts data to the head section.
502 * silc_buffer_put_head(sb, data, data_len);
507 unsigned char *silc_buffer_put_head(SilcBuffer sb,
508 const unsigned char *data,
511 #if defined(SILC_DEBUG)
512 assert(len <= silc_buffer_headlen(sb));
514 if (len > silc_buffer_headlen(sb))
517 return (unsigned char *)memcpy(sb->head, data, len);
520 /****f* silcutil/SilcBufferAPI/silc_buffer_put
525 * unsigned char *silc_buffer_put(SilcBuffer sb,
526 * const unsigned char *data,
531 * Puts data at the start of the valid data area. Returns a pointer
532 * to the copied data area. Returns NULL on error.
536 * ---------------------------------
537 * | head | data | tail |
538 * ---------------------------------
540 * Puts data to the data section.
542 * silc_buffer_put(sb, data, data_len);
547 unsigned char *silc_buffer_put(SilcBuffer sb,
548 const unsigned char *data,
551 #if defined(SILC_DEBUG)
552 assert(len <= silc_buffer_len(sb));
554 if (len > silc_buffer_len(sb))
557 return (unsigned char *)memcpy(sb->data, data, len);
560 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
565 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
566 * const unsigned char *data,
571 * Puts data at the tail of the buffer. Returns pointer to the copied
572 * data area. Returns NULL on error.
576 * ---------------------------------
577 * | head | data | tail |
578 * ---------------------------------
580 * Puts data to the tail section.
582 * silc_buffer_put_tail(sb, data, data_len);
587 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
588 const unsigned char *data,
591 #if defined(SILC_DEBUG)
592 assert(len <= silc_buffer_taillen(sb));
594 if (len > silc_buffer_taillen(sb))
597 return (unsigned char *)memcpy(sb->tail, data, len);
600 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
605 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
609 * Allocates `len' bytes size buffer and moves the tail area automatically
610 * `len' bytes so that the buffer is ready to use without calling the
611 * silc_buffer_pull_tail. Returns NULL on error.
616 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
618 SilcBuffer sb = silc_buffer_alloc(len);
621 silc_buffer_pull_tail(sb, len);
625 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
630 * void silc_buffer_reset(SilcBuffer sb);
634 * Resets the buffer to the state as if it was just allocated by
635 * silc_buffer_alloc. This does not clear the data area. Use
636 * silc_buffer_clear if you also want to clear the data area.
641 void silc_buffer_reset(SilcBuffer sb)
643 sb->data = sb->tail = sb->head;
646 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
651 * void silc_buffer_clear(SilcBuffer sb);
655 * Clears and initialiazes the buffer to the state as if it was just
656 * allocated by silc_buffer_alloc.
661 void silc_buffer_clear(SilcBuffer sb)
663 memset(sb->head, 0, silc_buffer_truelen(sb));
664 silc_buffer_reset(sb);
667 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
672 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
676 * Generates copy of a SilcBuffer. This copies everything inside the
677 * currently valid data area, nothing more. Use silc_buffer_clone to
678 * copy entire buffer. Returns NULL on error.
683 SilcBuffer silc_buffer_copy(SilcBuffer sb)
687 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
690 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
695 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
700 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
704 * Clones SilcBuffer. This generates new SilcBuffer and copies
705 * everything from the source buffer. The result is exact clone of
706 * the original buffer. Returns NULL on error.
711 SilcBuffer silc_buffer_clone(SilcBuffer sb)
715 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
718 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
719 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
720 sb_new->tail = sb_new->data + silc_buffer_len(sb);
725 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
730 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
734 * Reallocates buffer. Old data is saved into the new buffer. The buffer
735 * is exact clone of the old one except that there is now more space
736 * at the end of buffer. This always returns the same `sb' unless `sb'
737 * was NULL. Returns NULL on error.
742 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
744 SilcUInt32 hlen, dlen;
748 return silc_buffer_alloc(newsize);
750 if (newsize <= silc_buffer_truelen(sb))
753 hlen = silc_buffer_headlen(sb);
754 dlen = silc_buffer_len(sb);
755 h = (unsigned char *)silc_realloc(sb->head, newsize);
759 sb->data = sb->head + hlen;
760 sb->tail = sb->data + dlen;
761 sb->end = sb->head + newsize;
766 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
771 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
775 * Same as silc_buffer_realloc but moves moves the tail area
776 * automatically so that the buffer is ready to use without calling the
777 * silc_buffer_pull_tail. Returns NULL on error.
782 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
784 sb = silc_buffer_realloc(sb, newsize);
787 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
792 /* SilcStack aware SilcBuffer routines */
794 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
799 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
803 * Allocates new SilcBuffer and returns it.
805 * This routine use SilcStack are memory source. If `stack' is NULL
806 * reverts back to normal allocating routine.
811 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
816 return silc_buffer_alloc(len);
818 /* Allocate new SilcBuffer */
819 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
823 /* Allocate the actual data area */
824 sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
828 /* Set pointers to the new buffer */
831 sb->end = sb->head + len;
836 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
841 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
845 * Allocates `len' bytes size buffer and moves the tail area automatically
846 * `len' bytes so that the buffer is ready to use without calling the
847 * silc_buffer_pull_tail.
849 * This routine use SilcStack are memory source. If `stack' is NULL
850 * reverts back to normal allocating routine.
855 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
857 SilcBuffer sb = silc_buffer_salloc(stack, len);
860 silc_buffer_pull_tail(sb, len);
864 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
869 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
870 * SilcBuffer sb, SilcUInt32 newsize);
874 * Reallocates buffer. Old data is saved into the new buffer. The buffer
875 * is exact clone of the old one except that there is now more space
876 * at the end of buffer.
878 * This routine use SilcStack are memory source. If `stack' is NULL
879 * reverts back to normal allocating routine.
884 SilcBuffer silc_buffer_srealloc(SilcStack stack,
885 SilcBuffer sb, SilcUInt32 newsize)
887 SilcUInt32 hlen, dlen;
891 return silc_buffer_realloc(sb, newsize);
894 return silc_buffer_salloc(stack, newsize);
896 if (newsize <= silc_buffer_truelen(sb))
899 hlen = silc_buffer_headlen(sb);
900 dlen = silc_buffer_len(sb);
901 h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
904 /* Do slow and stack wasting realloc. The old sb->head is lost and
905 is freed eventually. */
906 h = silc_smalloc_ua(stack, newsize);
909 memcpy(h, sb->head, silc_buffer_truelen(sb));
913 sb->data = sb->head + hlen;
914 sb->tail = sb->data + dlen;
915 sb->end = sb->head + newsize;
920 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
925 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
926 * SilcBuffer sb, SilcUInt32 newsize);
930 * Same as silc_buffer_srealloc but moves moves the tail area
931 * automatically so that the buffer is ready to use without calling the
932 * silc_buffer_pull_tail.
934 * This routine use SilcStack are memory source. If `stack' is NULL
935 * reverts back to normal allocating routine.
940 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
941 SilcBuffer sb, SilcUInt32 newsize)
943 sb = silc_buffer_srealloc(stack, sb, newsize);
946 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
950 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
955 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
959 * Generates copy of a SilcBuffer. This copies everything inside the
960 * currently valid data area, nothing more. Use silc_buffer_clone to
961 * copy entire buffer.
963 * This routine use SilcStack are memory source. If `stack' is NULL
964 * reverts back to normal allocating routine.
969 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
973 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
976 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
981 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
986 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
990 * Clones SilcBuffer. This generates new SilcBuffer and copies
991 * everything from the source buffer. The result is exact clone of
992 * the original buffer.
994 * This routine use SilcStack are memory source. If `stack' is NULL
995 * reverts back to normal allocating routine.
1000 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1004 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1007 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1008 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1009 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1014 #endif /* SILCBUFFER_H */