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 /****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 /* Inline functions */
197 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
202 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
206 * Allocates new SilcBuffer and returns it. Returns NULL on error.
211 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
215 /* Allocate new SilcBuffer */
216 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
221 /* Allocate the actual data area */
222 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
226 /* Set pointers to the new buffer */
229 sb->end = sb->head + len;
235 /****f* silcutil/SilcBufferAPI/silc_buffer_free
240 * void silc_buffer_free(SilcBuffer sb);
244 * Frees SilcBuffer. Can be called safely `sb' as NULL.
249 void silc_buffer_free(SilcBuffer sb)
252 #if defined(SILC_DEBUG)
254 memset(sb->head, 'F', silc_buffer_truelen(sb));
261 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
266 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
270 * Steals the data from the buffer `sb'. This returns pointer to the
271 * start of the buffer and the true length of that buffer. The `sb'
272 * cannot be used anymore after calling this function because the
273 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
274 * The caller is responsible of freeing the stolen data buffer with
280 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
282 unsigned char *buf = sb->head;
284 *data_len = silc_buffer_truelen(sb);
285 sb->head = sb->data = sb->tail = sb->end = NULL;
289 /****f* silcutil/SilcBufferAPI/silc_buffer_set
294 * void silc_buffer_set(SilcBuffer sb,
295 * unsigned char *data,
296 * SilcUInt32 data_len);
300 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
301 * The data area is automatically set to the `data_len'. This function
302 * can be used to set the data to static buffer without needing any
303 * memory allocations. The `data' will not be copied to the buffer.
307 * SilcBufferStruct buf;
308 * silc_buffer_set(&buf, data, data_len);
313 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
315 sb->data = sb->head = data;
316 sb->tail = sb->end = data + data_len;
319 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
324 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
328 * Pulls current data area towards end. The length of the currently
329 * valid data area is also decremented. Returns pointer to the data
330 * area before pulling. Returns NULL on error.
334 * ---------------------------------
335 * | head | data | tail |
336 * ---------------------------------
338 * Pulls the start of the data area.
340 * ---------------------------------
341 * | head | data | tail |
342 * ---------------------------------
345 * silc_buffer_pull(sb, 20);
350 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
352 unsigned char *old_data = sb->data;
353 #if defined(SILC_DEBUG)
354 assert(len <= silc_buffer_len(sb));
356 if (len > silc_buffer_len(sb))
363 /****f* silcutil/SilcBufferAPI/silc_buffer_push
368 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
372 * Pushes current data area towards beginning. Length of the currently
373 * valid data area is also incremented. Returns a pointer to the
374 * data area before pushing. Returns NULL on error.
378 * ---------------------------------
379 * | head | data | tail |
380 * ---------------------------------
382 * Pushes the start of the data area.
384 * ---------------------------------
385 * | head | data | tail |
386 * ---------------------------------
389 * silc_buffer_push(sb, 20);
394 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
396 unsigned char *old_data = sb->data;
397 #if defined(SILC_DEBUG)
398 assert((sb->data - len) >= sb->head);
400 if ((sb->data - len) < sb->head)
407 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
412 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
416 * Pulls current tail section towards end. Length of the current valid
417 * data area is also incremented. Returns a pointer to the data area
418 * before pulling. Returns NULL on error.
422 * ---------------------------------
423 * | head | data | tail |
424 * ---------------------------------
426 * Pulls the start of the tail section.
428 * ---------------------------------
429 * | head | data | tail |
430 * ---------------------------------
433 * silc_buffer_pull_tail(sb, 23);
438 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
440 unsigned char *old_tail = sb->tail;
441 #if defined(SILC_DEBUG)
442 assert(len <= silc_buffer_taillen(sb));
444 if (len > silc_buffer_taillen(sb))
451 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
456 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
460 * Pushes current tail section towards beginning. Length of the current
461 * valid data area is also decremented. Returns a pointer to the
462 * tail section before pushing. Returns NULL on error.
466 * ---------------------------------
467 * | head | data | tail |
468 * ---------------------------------
470 * Pushes the start of the tail section.
472 * ---------------------------------
473 * | head | data | tail |
474 * ---------------------------------
477 * silc_buffer_push_tail(sb, 23);
482 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
484 unsigned char *old_tail = sb->tail;
485 #if defined(SILC_DEBUG)
486 assert((sb->tail - len) >= sb->data);
488 if ((sb->tail - len) < sb->data)
495 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
500 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
501 * const unsigned char *data,
506 * Puts data at the head of the buffer. Returns pointer to the copied
507 * data area. Returns NULL on error.
511 * ---------------------------------
512 * | head | data | tail |
513 * ---------------------------------
515 * Puts data to the head section.
517 * silc_buffer_put_head(sb, data, data_len);
522 unsigned char *silc_buffer_put_head(SilcBuffer sb,
523 const unsigned char *data,
526 #if defined(SILC_DEBUG)
527 assert(len <= silc_buffer_headlen(sb));
529 if (len > silc_buffer_headlen(sb))
532 return (unsigned char *)memcpy(sb->head, data, len);
535 /****f* silcutil/SilcBufferAPI/silc_buffer_put
540 * unsigned char *silc_buffer_put(SilcBuffer sb,
541 * const unsigned char *data,
546 * Puts data at the start of the valid data area. Returns a pointer
547 * to the copied data area. Returns NULL on error.
551 * ---------------------------------
552 * | head | data | tail |
553 * ---------------------------------
555 * Puts data to the data section.
557 * silc_buffer_put(sb, data, data_len);
562 unsigned char *silc_buffer_put(SilcBuffer sb,
563 const unsigned char *data,
566 #if defined(SILC_DEBUG)
567 assert(len <= silc_buffer_len(sb));
569 if (len > silc_buffer_len(sb))
572 return (unsigned char *)memcpy(sb->data, data, len);
575 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
580 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
581 * const unsigned char *data,
586 * Puts data at the tail of the buffer. Returns pointer to the copied
587 * data area. Returns NULL on error.
591 * ---------------------------------
592 * | head | data | tail |
593 * ---------------------------------
595 * Puts data to the tail section.
597 * silc_buffer_put_tail(sb, data, data_len);
602 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
603 const unsigned char *data,
606 #if defined(SILC_DEBUG)
607 assert(len <= silc_buffer_taillen(sb));
609 if (len > silc_buffer_taillen(sb))
612 return (unsigned char *)memcpy(sb->tail, data, len);
615 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
620 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
624 * Allocates `len' bytes size buffer and moves the tail area automatically
625 * `len' bytes so that the buffer is ready to use without calling the
626 * silc_buffer_pull_tail. Returns NULL on error.
631 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
633 SilcBuffer sb = silc_buffer_alloc(len);
636 silc_buffer_pull_tail(sb, len);
640 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
645 * void silc_buffer_reset(SilcBuffer sb);
649 * Resets the buffer to the state as if it was just allocated by
650 * silc_buffer_alloc. This does not clear the data area. Use
651 * silc_buffer_clear if you also want to clear the data area.
656 void silc_buffer_reset(SilcBuffer sb)
658 sb->data = sb->tail = sb->head;
661 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
666 * void silc_buffer_clear(SilcBuffer sb);
670 * Clears and initialiazes the buffer to the state as if it was just
671 * allocated by silc_buffer_alloc.
676 void silc_buffer_clear(SilcBuffer sb)
678 memset(sb->head, 0, silc_buffer_truelen(sb));
679 silc_buffer_reset(sb);
682 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
687 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
691 * Generates copy of a SilcBuffer. This copies everything inside the
692 * currently valid data area, nothing more. Use silc_buffer_clone to
693 * copy entire buffer. Returns NULL on error.
698 SilcBuffer silc_buffer_copy(SilcBuffer sb)
702 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
705 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
710 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
715 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
719 * Clones SilcBuffer. This generates new SilcBuffer and copies
720 * everything from the source buffer. The result is exact clone of
721 * the original buffer. Returns NULL on error.
726 SilcBuffer silc_buffer_clone(SilcBuffer sb)
730 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
733 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
734 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
735 sb_new->tail = sb_new->data + silc_buffer_len(sb);
740 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
745 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
749 * Reallocates buffer. Old data is saved into the new buffer. The buffer
750 * is exact clone of the old one except that there is now more space
751 * at the end of buffer. This always returns the same `sb' unless `sb'
752 * was NULL. Returns NULL on error.
757 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
759 SilcUInt32 hlen, dlen;
763 return silc_buffer_alloc(newsize);
765 if (newsize <= silc_buffer_truelen(sb))
768 hlen = silc_buffer_headlen(sb);
769 dlen = silc_buffer_len(sb);
770 h = (unsigned char *)silc_realloc(sb->head, newsize);
774 sb->data = sb->head + hlen;
775 sb->tail = sb->data + dlen;
776 sb->end = sb->head + newsize;
781 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
786 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
790 * Same as silc_buffer_realloc but moves moves the tail area
791 * automatically so that the buffer is ready to use without calling the
792 * silc_buffer_pull_tail. Returns NULL on error.
797 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
799 sb = silc_buffer_realloc(sb, newsize);
802 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
807 /* SilcStack aware SilcBuffer routines */
809 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
814 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
818 * Allocates new SilcBuffer and returns it.
820 * This routine use SilcStack are memory source. If `stack' is NULL
821 * reverts back to normal allocating routine.
826 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
831 return silc_buffer_alloc(len);
833 /* Allocate new SilcBuffer */
834 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
838 /* Allocate the actual data area */
839 sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
843 /* Set pointers to the new buffer */
846 sb->end = sb->head + len;
851 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
856 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
860 * Allocates `len' bytes size buffer and moves the tail area automatically
861 * `len' bytes so that the buffer is ready to use without calling the
862 * silc_buffer_pull_tail.
864 * This routine use SilcStack are memory source. If `stack' is NULL
865 * reverts back to normal allocating routine.
870 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
872 SilcBuffer sb = silc_buffer_salloc(stack, len);
875 silc_buffer_pull_tail(sb, len);
879 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
884 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
885 * SilcBuffer sb, SilcUInt32 newsize);
889 * Reallocates buffer. Old data is saved into the new buffer. The buffer
890 * is exact clone of the old one except that there is now more space
891 * at the end of buffer.
893 * This routine use SilcStack are memory source. If `stack' is NULL
894 * reverts back to normal allocating routine.
899 SilcBuffer silc_buffer_srealloc(SilcStack stack,
900 SilcBuffer sb, SilcUInt32 newsize)
902 SilcUInt32 hlen, dlen;
906 return silc_buffer_realloc(sb, newsize);
909 return silc_buffer_salloc(stack, newsize);
911 if (newsize <= silc_buffer_truelen(sb))
914 hlen = silc_buffer_headlen(sb);
915 dlen = silc_buffer_len(sb);
916 h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
919 /* Do slow and stack wasting realloc. The old sb->head is lost and
920 is freed eventually. */
921 h = silc_smalloc_ua(stack, newsize);
924 memcpy(h, sb->head, silc_buffer_truelen(sb));
928 sb->data = sb->head + hlen;
929 sb->tail = sb->data + dlen;
930 sb->end = sb->head + newsize;
935 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
940 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
941 * SilcBuffer sb, SilcUInt32 newsize);
945 * Same as silc_buffer_srealloc but moves moves the tail area
946 * automatically so that the buffer is ready to use without calling the
947 * silc_buffer_pull_tail.
949 * This routine use SilcStack are memory source. If `stack' is NULL
950 * reverts back to normal allocating routine.
955 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
956 SilcBuffer sb, SilcUInt32 newsize)
958 sb = silc_buffer_srealloc(stack, sb, newsize);
961 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
965 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
970 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
974 * Generates copy of a SilcBuffer. This copies everything inside the
975 * currently valid data area, nothing more. Use silc_buffer_clone to
976 * copy entire buffer.
978 * This routine use SilcStack are memory source. If `stack' is NULL
979 * reverts back to normal allocating routine.
984 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
988 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
991 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
996 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1001 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1005 * Clones SilcBuffer. This generates new SilcBuffer and copies
1006 * everything from the source buffer. The result is exact clone of
1007 * the original buffer.
1009 * This routine use SilcStack are memory source. If `stack' is NULL
1010 * reverts back to normal allocating routine.
1015 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1019 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1022 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1023 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1024 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1029 #endif /* SILCBUFFER_H */