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 * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
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 * SilcUInt32 silc_buffer_len(SilcBuffer sb)
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 * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
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 * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
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 /****f* silcutil/SilcBufferAPI/silc_buffer_data
184 * unsigned char *silc_buffer_data(SilcBuffer sb)
188 * Returns pointer to the data area of the buffer.
192 #define silc_buffer_data(x) (x)->data
195 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
199 * #define silc_buffer_datalen ...
203 * Macro that can be used in function argument list to give the data
204 * pointer and the data length, instead of calling both silc_buffer_data
205 * and silc_buffer_len separately.
209 * // Following are the same thing
210 * silc_foo_function(foo, silc_buffer_datalen(buf));
211 * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
215 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
216 (x) ? silc_buffer_len((x)) : 0
219 /* Inline functions */
221 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
226 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
230 * Allocates new SilcBuffer and returns it. Returns NULL on error.
235 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
239 /* Allocate new SilcBuffer */
240 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
245 /* Allocate the actual data area */
246 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
250 /* Set pointers to the new buffer */
253 sb->end = sb->head + len;
259 /****f* silcutil/SilcBufferAPI/silc_buffer_free
264 * void silc_buffer_free(SilcBuffer sb);
268 * Frees SilcBuffer. Can be called safely `sb' as NULL.
273 void silc_buffer_free(SilcBuffer sb)
276 #if defined(SILC_DEBUG)
278 memset(sb->head, 'F', silc_buffer_truelen(sb));
285 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
290 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
294 * Steals the data from the buffer `sb'. This returns pointer to the
295 * start of the buffer and the true length of that buffer. The `sb'
296 * cannot be used anymore after calling this function because the
297 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
298 * The caller is responsible of freeing the stolen data buffer with
304 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
306 unsigned char *buf = sb->head;
308 *data_len = silc_buffer_truelen(sb);
309 sb->head = sb->data = sb->tail = sb->end = NULL;
313 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
318 * void silc_buffer_purge(SilcBuffer sb);
322 * Same as silc_buffer_free but free's only the contents of the buffer
323 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
324 * is ready for re-use after calling this function.
329 void silc_buffer_purge(SilcBuffer sb)
331 silc_free(silc_buffer_steal(sb, NULL));
334 /****f* silcutil/SilcBufferAPI/silc_buffer_set
339 * void silc_buffer_set(SilcBuffer sb,
340 * unsigned char *data,
341 * SilcUInt32 data_len);
345 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
346 * The data area is automatically set to the `data_len'. This function
347 * can be used to set the data to static buffer without needing any
348 * memory allocations. The `data' will not be copied to the buffer.
352 * SilcBufferStruct buf;
353 * silc_buffer_set(&buf, data, data_len);
358 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
360 sb->data = sb->head = data;
361 sb->tail = sb->end = data + data_len;
364 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
369 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
373 * Pulls current data area towards end. The length of the currently
374 * valid data area is also decremented. Returns pointer to the data
375 * area before pulling. Returns NULL on error.
379 * ---------------------------------
380 * | head | data | tail |
381 * ---------------------------------
383 * Pulls the start of the data area.
385 * ---------------------------------
386 * | head | data | tail |
387 * ---------------------------------
390 * silc_buffer_pull(sb, 20);
395 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
397 unsigned char *old_data = sb->data;
398 #if defined(SILC_DEBUG)
399 assert(len <= silc_buffer_len(sb));
401 if (len > silc_buffer_len(sb))
408 /****f* silcutil/SilcBufferAPI/silc_buffer_push
413 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
417 * Pushes current data area towards beginning. Length of the currently
418 * valid data area is also incremented. Returns a pointer to the
419 * data area before pushing. Returns NULL on error.
423 * ---------------------------------
424 * | head | data | tail |
425 * ---------------------------------
427 * Pushes the start of the data area.
429 * ---------------------------------
430 * | head | data | tail |
431 * ---------------------------------
434 * silc_buffer_push(sb, 20);
439 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
441 unsigned char *old_data = sb->data;
442 #if defined(SILC_DEBUG)
443 assert((sb->data - len) >= sb->head);
445 if ((sb->data - len) < sb->head)
452 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
457 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
461 * Pulls current tail section towards end. Length of the current valid
462 * data area is also incremented. Returns a pointer to the data area
463 * before pulling. Returns NULL on error.
467 * ---------------------------------
468 * | head | data | tail |
469 * ---------------------------------
471 * Pulls the start of the tail section.
473 * ---------------------------------
474 * | head | data | tail |
475 * ---------------------------------
478 * silc_buffer_pull_tail(sb, 23);
483 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
485 unsigned char *old_tail = sb->tail;
486 #if defined(SILC_DEBUG)
487 assert(len <= silc_buffer_taillen(sb));
489 if (len > silc_buffer_taillen(sb))
496 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
501 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
505 * Pushes current tail section towards beginning. Length of the current
506 * valid data area is also decremented. Returns a pointer to the
507 * tail section before pushing. Returns NULL on error.
511 * ---------------------------------
512 * | head | data | tail |
513 * ---------------------------------
515 * Pushes the start of the tail section.
517 * ---------------------------------
518 * | head | data | tail |
519 * ---------------------------------
522 * silc_buffer_push_tail(sb, 23);
527 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
529 unsigned char *old_tail = sb->tail;
530 #if defined(SILC_DEBUG)
531 assert((sb->tail - len) >= sb->data);
533 if ((sb->tail - len) < sb->data)
540 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
545 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
546 * const unsigned char *data,
551 * Puts data at the head of the buffer. Returns pointer to the copied
552 * data area. Returns NULL on error.
556 * ---------------------------------
557 * | head | data | tail |
558 * ---------------------------------
560 * Puts data to the head section.
562 * silc_buffer_put_head(sb, data, data_len);
567 unsigned char *silc_buffer_put_head(SilcBuffer sb,
568 const unsigned char *data,
571 #if defined(SILC_DEBUG)
572 assert(len <= silc_buffer_headlen(sb));
574 if (len > silc_buffer_headlen(sb))
577 return (unsigned char *)memcpy(sb->head, data, len);
580 /****f* silcutil/SilcBufferAPI/silc_buffer_put
585 * unsigned char *silc_buffer_put(SilcBuffer sb,
586 * const unsigned char *data,
591 * Puts data at the start of the valid data area. Returns a pointer
592 * to the copied data area. Returns NULL on error.
596 * ---------------------------------
597 * | head | data | tail |
598 * ---------------------------------
600 * Puts data to the data section.
602 * silc_buffer_put(sb, data, data_len);
607 unsigned char *silc_buffer_put(SilcBuffer sb,
608 const unsigned char *data,
611 #if defined(SILC_DEBUG)
612 assert(len <= silc_buffer_len(sb));
614 if (len > silc_buffer_len(sb))
617 return (unsigned char *)memcpy(sb->data, data, len);
620 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
625 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
626 * const unsigned char *data,
631 * Puts data at the tail of the buffer. Returns pointer to the copied
632 * data area. Returns NULL on error.
636 * ---------------------------------
637 * | head | data | tail |
638 * ---------------------------------
640 * Puts data to the tail section.
642 * silc_buffer_put_tail(sb, data, data_len);
647 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
648 const unsigned char *data,
651 #if defined(SILC_DEBUG)
652 assert(len <= silc_buffer_taillen(sb));
654 if (len > silc_buffer_taillen(sb))
657 return (unsigned char *)memcpy(sb->tail, data, len);
660 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
665 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
669 * Allocates `len' bytes size buffer and moves the tail area automatically
670 * `len' bytes so that the buffer is ready to use without calling the
671 * silc_buffer_pull_tail. Returns NULL on error.
676 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
678 SilcBuffer sb = silc_buffer_alloc(len);
681 silc_buffer_pull_tail(sb, len);
685 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
690 * void silc_buffer_reset(SilcBuffer sb);
694 * Resets the buffer to the state as if it was just allocated by
695 * silc_buffer_alloc. This does not clear the data area. Use
696 * silc_buffer_clear if you also want to clear the data area.
701 void silc_buffer_reset(SilcBuffer sb)
703 sb->data = sb->tail = sb->head;
706 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
711 * void silc_buffer_clear(SilcBuffer sb);
715 * Clears and initialiazes the buffer to the state as if it was just
716 * allocated by silc_buffer_alloc.
721 void silc_buffer_clear(SilcBuffer sb)
723 memset(sb->head, 0, silc_buffer_truelen(sb));
724 silc_buffer_reset(sb);
727 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
732 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
736 * Generates copy of a SilcBuffer. This copies everything inside the
737 * currently valid data area, nothing more. Use silc_buffer_clone to
738 * copy entire buffer. Returns NULL on error.
743 SilcBuffer silc_buffer_copy(SilcBuffer sb)
747 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
750 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
755 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
760 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
764 * Clones SilcBuffer. This generates new SilcBuffer and copies
765 * everything from the source buffer. The result is exact clone of
766 * the original buffer. Returns NULL on error.
771 SilcBuffer silc_buffer_clone(SilcBuffer sb)
775 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
778 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
779 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
780 sb_new->tail = sb_new->data + silc_buffer_len(sb);
785 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
790 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
794 * Reallocates buffer. Old data is saved into the new buffer. The buffer
795 * is exact clone of the old one except that there is now more space
796 * at the end of buffer. This always returns the same `sb' unless `sb'
797 * was NULL. Returns NULL on error.
802 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
804 SilcUInt32 hlen, dlen;
808 return silc_buffer_alloc(newsize);
810 if (newsize <= silc_buffer_truelen(sb))
813 hlen = silc_buffer_headlen(sb);
814 dlen = silc_buffer_len(sb);
815 h = (unsigned char *)silc_realloc(sb->head, newsize);
819 sb->data = sb->head + hlen;
820 sb->tail = sb->data + dlen;
821 sb->end = sb->head + newsize;
826 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
831 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
835 * Same as silc_buffer_realloc but moves moves the tail area
836 * automatically so that the buffer is ready to use without calling the
837 * silc_buffer_pull_tail. Returns NULL on error.
842 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
844 sb = silc_buffer_realloc(sb, newsize);
847 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
852 /* SilcStack aware SilcBuffer routines */
854 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
859 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
863 * Allocates new SilcBuffer and returns it.
865 * This routine use SilcStack are memory source. If `stack' is NULL
866 * reverts back to normal allocating routine.
871 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
876 return silc_buffer_alloc(len);
878 /* Allocate new SilcBuffer */
879 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
883 /* Allocate the actual data area */
884 sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
888 /* Set pointers to the new buffer */
891 sb->end = sb->head + len;
896 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
901 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
905 * Allocates `len' bytes size buffer and moves the tail area automatically
906 * `len' bytes so that the buffer is ready to use without calling the
907 * silc_buffer_pull_tail.
909 * This routine use SilcStack are memory source. If `stack' is NULL
910 * reverts back to normal allocating routine.
915 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
917 SilcBuffer sb = silc_buffer_salloc(stack, len);
920 silc_buffer_pull_tail(sb, len);
924 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
929 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
930 * SilcBuffer sb, SilcUInt32 newsize);
934 * Reallocates buffer. Old data is saved into the new buffer. The buffer
935 * is exact clone of the old one except that there is now more space
936 * at the end of buffer.
938 * This routine use SilcStack are memory source. If `stack' is NULL
939 * reverts back to normal allocating routine.
944 SilcBuffer silc_buffer_srealloc(SilcStack stack,
945 SilcBuffer sb, SilcUInt32 newsize)
947 SilcUInt32 hlen, dlen;
951 return silc_buffer_realloc(sb, newsize);
954 return silc_buffer_salloc(stack, newsize);
956 if (newsize <= silc_buffer_truelen(sb))
959 hlen = silc_buffer_headlen(sb);
960 dlen = silc_buffer_len(sb);
961 h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
964 /* Do slow and stack wasting realloc. The old sb->head is lost and
965 is freed eventually. */
966 h = silc_smalloc_ua(stack, newsize);
969 memcpy(h, sb->head, silc_buffer_truelen(sb));
973 sb->data = sb->head + hlen;
974 sb->tail = sb->data + dlen;
975 sb->end = sb->head + newsize;
980 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
985 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
986 * SilcBuffer sb, SilcUInt32 newsize);
990 * Same as silc_buffer_srealloc but moves moves the tail area
991 * automatically so that the buffer is ready to use without calling the
992 * silc_buffer_pull_tail.
994 * This routine use SilcStack are memory source. If `stack' is NULL
995 * reverts back to normal allocating routine.
1000 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1001 SilcBuffer sb, SilcUInt32 newsize)
1003 sb = silc_buffer_srealloc(stack, sb, newsize);
1006 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1010 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1015 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1019 * Generates copy of a SilcBuffer. This copies everything inside the
1020 * currently valid data area, nothing more. Use silc_buffer_clone to
1021 * copy entire buffer.
1023 * This routine use SilcStack are memory source. If `stack' is NULL
1024 * reverts back to normal allocating routine.
1029 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1033 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1036 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1041 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1046 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1050 * Clones SilcBuffer. This generates new SilcBuffer and copies
1051 * everything from the source buffer. The result is exact clone of
1052 * the original buffer.
1054 * This routine use SilcStack are memory source. If `stack' is NULL
1055 * reverts back to normal allocating routine.
1060 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1064 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1067 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1068 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1069 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1074 #endif /* SILCBUFFER_H */