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.
108 * SILC Buffer is not thread-safe. If the same buffer context must be used
109 * in multithreaded environment concurrency control must be employed.
118 } *SilcBuffer, SilcBufferStruct;
123 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
127 * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
131 * Returns the true length of the buffer.
135 #define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
138 /****d* silcutil/SilcBufferAPI/silc_buffer_len
142 * SilcUInt32 silc_buffer_len(SilcBuffer sb)
146 * Returns the current length of the data area of the buffer.
150 #define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
153 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
157 * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
161 * Returns the current length of the head data area of the buffer.
165 #define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
168 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
172 * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
176 * Returns the current length of the tail data area of the buffer.
180 #define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
183 /****f* silcutil/SilcBufferAPI/silc_buffer_data
187 * unsigned char *silc_buffer_data(SilcBuffer sb)
191 * Returns pointer to the data area of the buffer.
195 #define silc_buffer_data(x) (x)->data
198 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
202 * #define silc_buffer_datalen ...
206 * Macro that can be used in function argument list to give the data
207 * pointer and the data length, instead of calling both silc_buffer_data
208 * and silc_buffer_len separately.
212 * // Following are the same thing
213 * silc_foo_function(foo, silc_buffer_datalen(buf));
214 * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
218 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
219 (x) ? silc_buffer_len((x)) : 0
222 /* Inline functions */
224 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
229 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
233 * Allocates new SilcBuffer and returns it. Returns NULL on error.
238 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
242 /* Allocate new SilcBuffer */
243 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
248 /* Allocate the actual data area */
249 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
253 /* Set pointers to the new buffer */
256 sb->end = sb->head + len;
262 /****f* silcutil/SilcBufferAPI/silc_buffer_free
267 * void silc_buffer_free(SilcBuffer sb);
271 * Frees SilcBuffer. Can be called safely `sb' as NULL.
276 void silc_buffer_free(SilcBuffer sb)
279 #if defined(SILC_DEBUG)
281 memset(sb->head, 'F', silc_buffer_truelen(sb));
288 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
293 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
297 * Steals the data from the buffer `sb'. This returns pointer to the
298 * start of the buffer and the true length of that buffer. The `sb'
299 * cannot be used anymore after calling this function because the
300 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
301 * The caller is responsible of freeing the stolen data buffer with
307 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
309 unsigned char *buf = sb->head;
311 *data_len = silc_buffer_truelen(sb);
312 sb->head = sb->data = sb->tail = sb->end = NULL;
316 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
321 * void silc_buffer_purge(SilcBuffer sb);
325 * Same as silc_buffer_free but free's only the contents of the buffer
326 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
327 * is ready for re-use after calling this function.
332 void silc_buffer_purge(SilcBuffer sb)
334 silc_free(silc_buffer_steal(sb, NULL));
337 /****f* silcutil/SilcBufferAPI/silc_buffer_set
342 * void silc_buffer_set(SilcBuffer sb,
343 * unsigned char *data,
344 * SilcUInt32 data_len);
348 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
349 * The data area is automatically set to the `data_len'. This function
350 * can be used to set the data to static buffer without needing any
351 * memory allocations. The `data' will not be copied to the buffer.
355 * SilcBufferStruct buf;
356 * silc_buffer_set(&buf, data, data_len);
361 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
363 sb->data = sb->head = data;
364 sb->tail = sb->end = data + data_len;
367 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
372 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
376 * Pulls current data area towards end. The length of the currently
377 * valid data area is also decremented. Returns pointer to the data
378 * area before pulling. Returns NULL on error.
382 * ---------------------------------
383 * | head | data | tail |
384 * ---------------------------------
386 * Pulls the start of the data area.
388 * ---------------------------------
389 * | head | data | tail |
390 * ---------------------------------
393 * silc_buffer_pull(sb, 20);
398 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
400 unsigned char *old_data = sb->data;
401 #if defined(SILC_DEBUG)
402 assert(len <= silc_buffer_len(sb));
404 if (len > silc_buffer_len(sb))
411 /****f* silcutil/SilcBufferAPI/silc_buffer_push
416 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
420 * Pushes current data area towards beginning. Length of the currently
421 * valid data area is also incremented. Returns a pointer to the
422 * data area before pushing. Returns NULL on error.
426 * ---------------------------------
427 * | head | data | tail |
428 * ---------------------------------
430 * Pushes the start of the data area.
432 * ---------------------------------
433 * | head | data | tail |
434 * ---------------------------------
437 * silc_buffer_push(sb, 20);
442 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
444 unsigned char *old_data = sb->data;
445 #if defined(SILC_DEBUG)
446 assert((sb->data - len) >= sb->head);
448 if ((sb->data - len) < sb->head)
455 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
460 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
464 * Pulls current tail section towards end. Length of the current valid
465 * data area is also incremented. Returns a pointer to the data area
466 * before pulling. Returns NULL on error.
470 * ---------------------------------
471 * | head | data | tail |
472 * ---------------------------------
474 * Pulls the start of the tail section.
476 * ---------------------------------
477 * | head | data | tail |
478 * ---------------------------------
481 * silc_buffer_pull_tail(sb, 23);
486 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
488 unsigned char *old_tail = sb->tail;
489 #if defined(SILC_DEBUG)
490 assert(len <= silc_buffer_taillen(sb));
492 if (len > silc_buffer_taillen(sb))
499 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
504 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
508 * Pushes current tail section towards beginning. Length of the current
509 * valid data area is also decremented. Returns a pointer to the
510 * tail section before pushing. Returns NULL on error.
514 * ---------------------------------
515 * | head | data | tail |
516 * ---------------------------------
518 * Pushes the start of the tail section.
520 * ---------------------------------
521 * | head | data | tail |
522 * ---------------------------------
525 * silc_buffer_push_tail(sb, 23);
530 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
532 unsigned char *old_tail = sb->tail;
533 #if defined(SILC_DEBUG)
534 assert((sb->tail - len) >= sb->data);
536 if ((sb->tail - len) < sb->data)
543 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
548 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
549 * const unsigned char *data,
554 * Puts data at the head of the buffer. Returns pointer to the copied
555 * data area. Returns NULL on error.
559 * ---------------------------------
560 * | head | data | tail |
561 * ---------------------------------
563 * Puts data to the head section.
565 * silc_buffer_put_head(sb, data, data_len);
570 unsigned char *silc_buffer_put_head(SilcBuffer sb,
571 const unsigned char *data,
574 #if defined(SILC_DEBUG)
575 assert(len <= silc_buffer_headlen(sb));
577 if (len > silc_buffer_headlen(sb))
580 return (unsigned char *)memcpy(sb->head, data, len);
583 /****f* silcutil/SilcBufferAPI/silc_buffer_put
588 * unsigned char *silc_buffer_put(SilcBuffer sb,
589 * const unsigned char *data,
594 * Puts data at the start of the valid data area. Returns a pointer
595 * to the copied data area. Returns NULL on error.
599 * ---------------------------------
600 * | head | data | tail |
601 * ---------------------------------
603 * Puts data to the data section.
605 * silc_buffer_put(sb, data, data_len);
610 unsigned char *silc_buffer_put(SilcBuffer sb,
611 const unsigned char *data,
614 #if defined(SILC_DEBUG)
615 assert(len <= silc_buffer_len(sb));
617 if (len > silc_buffer_len(sb))
620 return (unsigned char *)memcpy(sb->data, data, len);
623 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
628 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
629 * const unsigned char *data,
634 * Puts data at the tail of the buffer. Returns pointer to the copied
635 * data area. Returns NULL on error.
639 * ---------------------------------
640 * | head | data | tail |
641 * ---------------------------------
643 * Puts data to the tail section.
645 * silc_buffer_put_tail(sb, data, data_len);
650 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
651 const unsigned char *data,
654 #if defined(SILC_DEBUG)
655 assert(len <= silc_buffer_taillen(sb));
657 if (len > silc_buffer_taillen(sb))
660 return (unsigned char *)memcpy(sb->tail, data, len);
663 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
668 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
672 * Allocates `len' bytes size buffer and moves the tail area automatically
673 * `len' bytes so that the buffer is ready to use without calling the
674 * silc_buffer_pull_tail. Returns NULL on error.
679 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
681 SilcBuffer sb = silc_buffer_alloc(len);
684 silc_buffer_pull_tail(sb, len);
688 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
693 * void silc_buffer_reset(SilcBuffer sb);
697 * Resets the buffer to the state as if it was just allocated by
698 * silc_buffer_alloc. This does not clear the data area. Use
699 * silc_buffer_clear if you also want to clear the data area.
704 void silc_buffer_reset(SilcBuffer sb)
706 sb->data = sb->tail = sb->head;
709 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
714 * void silc_buffer_clear(SilcBuffer sb);
718 * Clears and initialiazes the buffer to the state as if it was just
719 * allocated by silc_buffer_alloc.
724 void silc_buffer_clear(SilcBuffer sb)
726 memset(sb->head, 0, silc_buffer_truelen(sb));
727 silc_buffer_reset(sb);
730 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
735 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
739 * Generates copy of a SilcBuffer. This copies everything inside the
740 * currently valid data area, nothing more. Use silc_buffer_clone to
741 * copy entire buffer. Returns NULL on error.
746 SilcBuffer silc_buffer_copy(SilcBuffer sb)
750 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
753 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
758 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
763 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
767 * Clones SilcBuffer. This generates new SilcBuffer and copies
768 * everything from the source buffer. The result is exact clone of
769 * the original buffer. Returns NULL on error.
774 SilcBuffer silc_buffer_clone(SilcBuffer sb)
778 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
781 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
782 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
783 sb_new->tail = sb_new->data + silc_buffer_len(sb);
788 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
793 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
797 * Reallocates buffer. Old data is saved into the new buffer. The buffer
798 * is exact clone of the old one except that there is now more space
799 * at the end of buffer. This always returns the same `sb' unless `sb'
800 * was NULL. Returns NULL on error.
805 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
807 SilcUInt32 hlen, dlen;
811 return silc_buffer_alloc(newsize);
813 if (newsize <= silc_buffer_truelen(sb))
816 hlen = silc_buffer_headlen(sb);
817 dlen = silc_buffer_len(sb);
818 h = (unsigned char *)silc_realloc(sb->head, newsize);
822 sb->data = sb->head + hlen;
823 sb->tail = sb->data + dlen;
824 sb->end = sb->head + newsize;
829 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
834 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
838 * Same as silc_buffer_realloc but moves moves the tail area
839 * automatically so that the buffer is ready to use without calling the
840 * silc_buffer_pull_tail. Returns NULL on error.
845 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
847 sb = silc_buffer_realloc(sb, newsize);
850 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
855 /* SilcStack aware SilcBuffer routines */
857 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
862 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
866 * Allocates new SilcBuffer and returns it.
868 * This routine use SilcStack are memory source. If `stack' is NULL
869 * reverts back to normal allocating routine.
874 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
879 return silc_buffer_alloc(len);
881 /* Allocate new SilcBuffer */
882 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
886 /* Allocate the actual data area */
887 sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
891 /* Set pointers to the new buffer */
894 sb->end = sb->head + len;
899 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
904 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
908 * Allocates `len' bytes size buffer and moves the tail area automatically
909 * `len' bytes so that the buffer is ready to use without calling the
910 * silc_buffer_pull_tail.
912 * This routine use SilcStack are memory source. If `stack' is NULL
913 * reverts back to normal allocating routine.
918 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
920 SilcBuffer sb = silc_buffer_salloc(stack, len);
923 silc_buffer_pull_tail(sb, len);
927 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
932 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
933 * SilcBuffer sb, SilcUInt32 newsize);
937 * Reallocates buffer. Old data is saved into the new buffer. The buffer
938 * is exact clone of the old one except that there is now more space
939 * at the end of buffer.
941 * This routine use SilcStack are memory source. If `stack' is NULL
942 * reverts back to normal allocating routine.
947 SilcBuffer silc_buffer_srealloc(SilcStack stack,
948 SilcBuffer sb, SilcUInt32 newsize)
950 SilcUInt32 hlen, dlen;
954 return silc_buffer_realloc(sb, newsize);
957 return silc_buffer_salloc(stack, newsize);
959 if (newsize <= silc_buffer_truelen(sb))
962 hlen = silc_buffer_headlen(sb);
963 dlen = silc_buffer_len(sb);
964 h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
967 /* Do slow and stack wasting realloc. The old sb->head is lost and
968 is freed eventually. */
969 h = silc_smalloc_ua(stack, newsize);
972 memcpy(h, sb->head, silc_buffer_truelen(sb));
976 sb->data = sb->head + hlen;
977 sb->tail = sb->data + dlen;
978 sb->end = sb->head + newsize;
983 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
988 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
989 * SilcBuffer sb, SilcUInt32 newsize);
993 * Same as silc_buffer_srealloc but moves moves the tail area
994 * automatically so that the buffer is ready to use without calling the
995 * silc_buffer_pull_tail.
997 * This routine use SilcStack are memory source. If `stack' is NULL
998 * reverts back to normal allocating routine.
1003 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1004 SilcBuffer sb, SilcUInt32 newsize)
1006 sb = silc_buffer_srealloc(stack, sb, newsize);
1009 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1013 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1018 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1022 * Generates copy of a SilcBuffer. This copies everything inside the
1023 * currently valid data area, nothing more. Use silc_buffer_clone to
1024 * copy entire buffer.
1026 * This routine use SilcStack are memory source. If `stack' is NULL
1027 * reverts back to normal allocating routine.
1032 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1036 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1039 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1044 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1049 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1053 * Clones SilcBuffer. This generates new SilcBuffer and copies
1054 * everything from the source buffer. The result is exact clone of
1055 * the original buffer.
1057 * This routine use SilcStack are memory source. If `stack' is NULL
1058 * reverts back to normal allocating routine.
1063 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1067 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1070 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1071 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1072 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1077 #endif /* SILCBUFFER_H */