0a249cb0c812841954863e94dc78d532d3f80c7a
[silc.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 /****h* silcutil/SILC Buffer Interface
22  *
23  * DESCRIPTION
24  *
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.
29  *
30  ***/
31
32 #ifndef SILCBUFFER_H
33 #define SILCBUFFER_H
34
35 /****s* silcutil/SilcBufferAPI/SilcBuffer
36  *
37  * NAME
38  *
39  *    typedef struct { ... } *SilcBuffer, SilcBufferStruct;
40  *
41  * DESCRIPTION
42  *
43  *    SILC Buffer object. Following short description of the fields
44  *    of the buffer.
45  *
46  * EXAMPLE
47  *
48  *    unsiged char *head;
49  *
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.
54  *
55  *        --------------------------------
56  *        | head  | data         | tail  |
57  *        --------------------------------
58  *        ^       ^
59  *
60  *        Current head section in the buffer is sb->data - sb->head.
61  *
62  *    unsigned char *data;
63  *
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.
66  *
67  *        --------------------------------
68  *        | head  | data         | tail  |
69  *        --------------------------------
70  *                ^              ^
71  *
72  *        Current valid data area in the buffer is sb->tail - sb->data.
73  *
74  *     unsigned char *tail;
75  *
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.
78  *
79  *        --------------------------------
80  *        | head  | data         | tail  |
81  *        --------------------------------
82  *                               ^       ^
83  *
84  *        Current tail section in the buffer is sb->end - sb->tail.
85  *
86  *    unsigned char *end;
87  *
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
91  *        of the buffer.
92  *
93  *        --------------------------------
94  *        | head  | data         | tail  |
95  *        --------------------------------
96  *                                       ^
97  *
98  *        Length of the entire buffer is (ie. truelen) sb->end - sb->head.
99  *
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.
107  *
108  * SILC Buffer is not thread-safe.  If the same SilcBuffer context must be
109  * used in multithreaded environment concurrency control must be employed.
110  *
111  * SOURCE
112  */
113 typedef struct SilcBufferObject {
114   unsigned char *head;
115   unsigned char *data;
116   unsigned char *tail;
117   unsigned char *end;
118 } *SilcBuffer, SilcBufferStruct;
119 /***/
120
121 /* Macros */
122
123 /****f* silcutil/SilcBufferAPI/silc_buffer_data
124  *
125  * NAME
126  *
127  *    unsigned char *silc_buffer_data(SilcBuffer sb)
128  *
129  * DESCRIPTION
130  *
131  *    Returns pointer to the data area of the buffer.
132  *
133  * SOURCE
134  */
135 #define silc_buffer_data(x) (x)->data
136 /***/
137
138 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
139  *
140  * NAME
141  *
142  *    #define silc_buffer_datalen ...
143  *
144  * DESCRIPTION
145  *
146  *    Macro that can be used in function argument list to give the data
147  *    pointer and the data length, instead of calling both silc_buffer_data
148  *    and silc_buffer_len separately.
149  *
150  * EXAMPLE
151  *
152  *    // Following are the same thing
153  *    silc_foo_function(foo, silc_buffer_datalen(buf));
154  *    silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
155  *
156  * SOURCE
157  */
158 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
159   (x) ? silc_buffer_len((x)) : 0
160 /***/
161
162 /* Inline functions */
163
164 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
165  *
166  * NAME
167  *
168  *    SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
169  *
170  * DESCRIPTION
171  *
172  *    Returns the true length of the buffer.
173  *
174  ***/
175 static inline
176 SilcUInt32 silc_buffer_truelen(SilcBuffer x)
177 {
178   return (SilcUInt32)(x->end - x->head);
179 }
180
181 /****d* silcutil/SilcBufferAPI/silc_buffer_len
182  *
183  * NAME
184  *
185  *    SilcUInt32 silc_buffer_len(SilcBuffer sb)
186  *
187  * DESCRIPTION
188  *
189  *    Returns the current length of the data area of the buffer.
190  *
191  ***/
192 static inline
193 SilcUInt32 silc_buffer_len(SilcBuffer x)
194 {
195   return (SilcUInt32)(x->tail - x->data);
196 }
197
198 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
199  *
200  * NAME
201  *
202  *    SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
203  *
204  * DESCRIPTION
205  *
206  *    Returns the current length of the head data area of the buffer.
207  *
208  ***/
209 static inline
210 SilcUInt32 silc_buffer_headlen(SilcBuffer x)
211 {
212   return (SilcUInt32)(x->data - x->head);
213 }
214
215 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
216  *
217  * NAME
218  *
219  *    SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
220  *
221  * DESCRIPTION
222  *
223  *    Returns the current length of the tail data area of the buffer.
224  *
225  ***/
226 static inline
227 SilcUInt32 silc_buffer_taillen(SilcBuffer x)
228 {
229   return (SilcUInt32)(x->end - x->tail);
230 }
231
232 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
233  *
234  * SYNOPSIS
235  *
236  *    static inline
237  *    SilcBuffer silc_buffer_alloc(SilcUInt32 len);
238  *
239  * DESCRIPTION
240  *
241  *    Allocates new SilcBuffer and returns it.  Returns NULL if system is
242  *    out of memory.
243  *
244  ***/
245
246 static inline
247 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
248 {
249   SilcBuffer sb;
250
251   /* Allocate new SilcBuffer */
252   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
253   if (silc_unlikely(!sb))
254     return NULL;
255
256   if (silc_likely(len)) {
257     /* Allocate the actual data area */
258     sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head));
259     if (silc_unlikely(!sb->head))
260       return NULL;
261
262     /* Set pointers to the new buffer */
263     sb->data = sb->head;
264     sb->tail = sb->head;
265     sb->end = sb->head + len;
266   }
267
268   return sb;
269 }
270
271 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
272  *
273  * SYNOPSIS
274  *
275  *    static inline
276  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
277  *
278  * DESCRIPTION
279  *
280  *    Allocates new SilcBuffer and returns it.  Returns NULL if system is
281  *    out of memory.
282  *
283  *    This routine use SilcStack are memory source.  If `stack' is NULL
284  *    reverts back to normal allocating routine.
285  *
286  *    Note that this call consumes the `stack'.  The caller should push the
287  *    stack before calling the function and pop it later.
288  *
289  ***/
290
291 static inline
292 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
293 {
294   SilcBuffer sb;
295
296   if (!stack)
297     return silc_buffer_alloc(len);
298
299   /* Allocate new SilcBuffer */
300   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
301   if (silc_unlikely(!sb))
302     return NULL;
303
304   if (silc_likely(len)) {
305     /* Allocate the actual data area */
306     sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head));
307     if (silc_unlikely(!sb->head))
308       return NULL;
309
310     /* Set pointers to the new buffer */
311     sb->data = sb->head;
312     sb->tail = sb->head;
313     sb->end = sb->head + len;
314   }
315
316   return sb;
317 }
318
319 /****f* silcutil/SilcBufferAPI/silc_buffer_free
320  *
321  * SYNOPSIS
322  *
323  *    static inline
324  *    void silc_buffer_free(SilcBuffer sb);
325  *
326  * DESCRIPTION
327  *
328  *    Frees SilcBuffer.  Can be called safely `sb' as NULL.
329  *
330  * NOTES
331  *
332  *    Must not be called for buffers allocated with silc_buffer_salloc,
333  *    silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
334  *    Call silc_buffer_sfree instead.
335  *
336  ***/
337
338 static inline
339 void silc_buffer_free(SilcBuffer sb)
340 {
341   if (sb) {
342 #if defined(SILC_DEBUG)
343     if (sb->head)
344       memset(sb->head, 'F', silc_buffer_truelen(sb));
345 #endif
346     silc_free(sb->head);
347     silc_free(sb);
348   }
349 }
350
351 /****f* silcutil/SilcBufferAPI/silc_buffer_sfree
352  *
353  * SYNOPSIS
354  *
355  *    static inline
356  *    void silc_buffer_free(SilcStack stack, SilcBuffer sb);
357  *
358  * DESCRIPTION
359  *
360  *    Frees SilcBuffer.  If `stack' is NULL this calls silc_buffer_free.  Can
361  *    be called safely `sb' as NULL.
362  *
363  ***/
364
365 static inline
366 void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
367 {
368   if (stack) {
369 #ifdef SILC_DEBUG
370     if (sb) {
371       if (sb->head)
372         memset(sb->head, 'F', silc_buffer_truelen(sb));
373       memset(sb, 'F', sizeof(*sb));
374     }
375 #endif /* SILC_DEBUG */
376     return;
377   }
378
379   silc_buffer_free(sb);
380 }
381
382 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
383  *
384  * SYNOPSIS
385  *
386  *    static inline
387  *    unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
388  *
389  * DESCRIPTION
390  *
391  *    Steals the data from the buffer `sb'.  This returns pointer to the
392  *    start of the buffer and the true length of that buffer.  The `sb'
393  *    cannot be used anymore after calling this function because the
394  *    data buffer was stolen.  The `sb' must be freed with silc_buffer_free.
395  *    The caller is responsible of freeing the stolen data buffer with
396  *    silc_free.
397  *
398  ***/
399
400 static inline
401 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
402 {
403   unsigned char *buf = sb->head;
404   if (data_len)
405     *data_len = silc_buffer_truelen(sb);
406   sb->head = sb->data = sb->tail = sb->end = NULL;
407   return buf;
408 }
409
410 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
411  *
412  * SYNOPSIS
413  *
414  *    static inline
415  *    void silc_buffer_purge(SilcBuffer sb);
416  *
417  * DESCRIPTION
418  *
419  *    Same as silc_buffer_free but free's only the contents of the buffer
420  *    not the buffer itself.  The `sb' remains intact, data is freed.  Buffer
421  *    is ready for re-use after calling this function.
422  *
423  * NOTES
424  *
425  *    Must not be called for buffers allocated with silc_buffer_salloc,
426  *    silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
427  *    Use silc_buffer_spurge instead.
428  *
429  ***/
430
431 static inline
432 void silc_buffer_purge(SilcBuffer sb)
433 {
434   silc_free(silc_buffer_steal(sb, NULL));
435 }
436
437 /****f* silcutil/SilcBufferAPI/silc_buffer_spurge
438  *
439  * SYNOPSIS
440  *
441  *    static inline
442  *    void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
443  *
444  * DESCRIPTION
445  *
446  *    Same as silc_buffer_free but free's only the contents of the buffer
447  *    not the buffer itself.  The `sb' remains intact, data is freed.  Buffer
448  *    is ready for re-use after calling this function.  If `stack' is NULL
449  *    this calls silc_buffer_purge.
450  *
451  ***/
452
453 static inline
454 void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
455 {
456   if (stack) {
457 #ifdef SILC_DEBUG
458     if (sb && sb->head)
459       memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
460 #endif /* SILC_DEBUG */
461     return;
462   }
463
464   silc_buffer_purge(sb);
465 }
466
467 /****f* silcutil/SilcBufferAPI/silc_buffer_set
468  *
469  * SYNOPSIS
470  *
471  *    static inline
472  *    void silc_buffer_set(SilcBuffer sb,
473  *                         unsigned char *data,
474  *                         SilcUInt32 data_len);
475  *
476  * DESCRIPTION
477  *
478  *    Sets the `data' and `data_len' to the buffer pointer sent as argument.
479  *    The data area is automatically set to the `data_len'. This function
480  *    can be used to set the data to static buffer without needing any
481  *    memory allocations. The `data' will not be copied to the buffer.
482  *
483  * EXAMPLE
484  *
485  *    SilcBufferStruct buf;
486  *    silc_buffer_set(&buf, data, data_len);
487  *
488  ***/
489
490 static inline
491 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
492 {
493   sb->data = sb->head = data;
494   sb->tail = sb->end = data + data_len;
495 }
496
497 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
498  *
499  * SYNOPSIS
500  *
501  *    static inline
502  *    unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
503  *
504  * DESCRIPTION
505  *
506  *    Pulls current data area towards end. The length of the currently
507  *    valid data area is also decremented. Returns pointer to the data
508  *    area before pulling. Returns NULL if the pull would lead to buffer
509  *    overflow or would go beyond the valid data area.
510  *
511  * EXAMPLE
512  *
513  *    ---------------------------------
514  *    | head  | data       | tail     |
515  *    ---------------------------------
516  *            ^
517  *            Pulls the start of the data area.
518  *
519  *    ---------------------------------
520  *    | head     | data    | tail     |
521  *    ---------------------------------
522  *            ^
523  *
524  *    silc_buffer_pull(sb, 20);
525  *
526  ***/
527
528 static inline
529 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
530 {
531   unsigned char *old_data = sb->data;
532
533 #ifdef SILC_DIST_INPLACE
534   SILC_ASSERT(len <= silc_buffer_len(sb));
535 #endif /* SILC_DIST_INPLACE */
536   if (silc_unlikely(len > silc_buffer_len(sb)))
537     return NULL;
538
539   sb->data += len;
540   return old_data;
541 }
542
543 /****f* silcutil/SilcBufferAPI/silc_buffer_push
544  *
545  * SYNOPSIS
546  *
547  *    static inline
548  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
549  *
550  * DESCRIPTION
551  *
552  *    Pushes current data area towards beginning. Length of the currently
553  *    valid data area is also incremented. Returns a pointer to the
554  *    data area before pushing. Returns NULL if the push would lead to
555  *    buffer underflow or would go under the valid data area.
556  *
557  * EXAMPLE
558  *
559  *    ---------------------------------
560  *    | head     | data    | tail     |
561  *    ---------------------------------
562  *               ^
563  *               Pushes the start of the data area.
564  *
565  *    ---------------------------------
566  *    | head  | data       | tail     |
567  *    ---------------------------------
568  *               ^
569  *
570  *    silc_buffer_push(sb, 20);
571  *
572  ***/
573
574 static inline
575 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
576 {
577   unsigned char *old_data = sb->data;
578
579 #ifdef SILC_DIST_INPLACE
580   SILC_ASSERT((sb->data - len) >= sb->head);
581 #endif /* SILC_DIST_INPLACE */
582   if (silc_unlikely((sb->data - len) < sb->head))
583     return NULL;
584
585   sb->data -= len;
586   return old_data;
587 }
588
589 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
590  *
591  * SYNOPSIS
592  *
593  *    static inline
594  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
595  *
596  * DESCRIPTION
597  *
598  *    Pulls current tail section towards end. Length of the current valid
599  *    data area is also incremented. Returns a pointer to the data area
600  *    before pulling. Returns NULL if the pull would lead to buffer overflow.
601  *
602  * EXAMPLE
603  *
604  *    ---------------------------------
605  *    | head  | data       | tail     |
606  *    ---------------------------------
607  *                         ^
608  *                         Pulls the start of the tail section.
609  *
610  *    ---------------------------------
611  *    | head  | data           | tail |
612  *    ---------------------------------
613  *                         ^
614  *
615  *    silc_buffer_pull_tail(sb, 23);
616  *
617  ***/
618
619 static inline
620 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
621 {
622   unsigned char *old_tail = sb->tail;
623
624 #ifdef SILC_DIST_INPLACE
625   SILC_ASSERT(len <= silc_buffer_taillen(sb));
626 #endif /* SILC_DIST_INPLACE */
627   if (silc_unlikely(len > silc_buffer_taillen(sb)))
628     return NULL;
629
630   sb->tail += len;
631   return old_tail;
632 }
633
634 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
635  *
636  * SYNOPSIS
637  *
638  *    static inline
639  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
640  *
641  * DESCRIPTION
642  *
643  *    Pushes current tail section towards beginning. Length of the current
644  *    valid data area is also decremented. Returns a pointer to the
645  *    tail section before pushing. Returns NULL if the push would lead to
646  *    buffer underflow or go under valid tail area.
647  *
648  * EXAMPLE
649  *
650  *    ---------------------------------
651  *    | head  | data           | tail |
652  *    ---------------------------------
653  *                             ^
654  *                             Pushes the start of the tail section.
655  *
656  *    ---------------------------------
657  *    | head  | data       | tail     |
658  *    ---------------------------------
659  *                             ^
660  *
661  *    silc_buffer_push_tail(sb, 23);
662  *
663  ***/
664
665 static inline
666 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
667 {
668   unsigned char *old_tail = sb->tail;
669
670 #ifdef SILC_DIST_INPLACE
671   SILC_ASSERT((sb->tail - len) >= sb->data);
672 #endif /* SILC_DIST_INPLACE */
673   if (silc_unlikely((sb->tail - len) < sb->data))
674     return NULL;
675
676   sb->tail -= len;
677   return old_tail;
678 }
679
680 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
681  *
682  * SYNOPSIS
683  *
684  *    static inline
685  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
686  *                                        const unsigned char *data,
687  *                                        SilcUInt32 len);
688  *
689  * DESCRIPTION
690  *
691  *    Puts data at the head of the buffer. Returns pointer to the copied
692  *    data area. Returns NULL if the data is longer that the current head
693  *    area.
694  *
695  * EXAMPLE
696  *
697  *    ---------------------------------
698  *    | head  | data       | tail     |
699  *    ---------------------------------
700  *    ^
701  *    Puts data to the head section.
702  *
703  *    silc_buffer_put_head(sb, data, data_len);
704  *
705  ***/
706
707 static inline
708 unsigned char *silc_buffer_put_head(SilcBuffer sb,
709                                     const unsigned char *data,
710                                     SilcUInt32 len)
711 {
712 #ifdef SILC_DIST_INPLACE
713   SILC_ASSERT(len <= silc_buffer_headlen(sb));
714 #endif /* SILC_DIST_INPLACE */
715   if (silc_unlikely(len > silc_buffer_headlen(sb)))
716     return NULL;
717
718   return (unsigned char *)memcpy(sb->head, data, len);
719 }
720
721 /****f* silcutil/SilcBufferAPI/silc_buffer_put
722  *
723  * SYNOPSIS
724  *
725  *    static inline
726  *    unsigned char *silc_buffer_put(SilcBuffer sb,
727  *                                   const unsigned char *data,
728  *                                   SilcUInt32 len);
729  *
730  * DESCRIPTION
731  *
732  *    Puts data at the start of the valid data area. Returns a pointer
733  *    to the copied data area.  Returns NULL if the data is longer than the
734  *    current data area.
735  *
736  * EXAMPLE
737  *
738  *    ---------------------------------
739  *    | head  | data       | tail     |
740  *    ---------------------------------
741  *            ^
742  *            Puts data to the data section.
743  *
744  *    silc_buffer_put(sb, data, data_len);
745  *
746  ***/
747
748 static inline
749 unsigned char *silc_buffer_put(SilcBuffer sb,
750                                const unsigned char *data,
751                                SilcUInt32 len)
752 {
753 #ifdef SILC_DIST_INPLACE
754   SILC_ASSERT(len <= silc_buffer_len(sb));
755 #endif /* SILC_DIST_INPLACE */
756   if (silc_unlikely(len > silc_buffer_len(sb)))
757     return NULL;
758
759   return (unsigned char *)memcpy(sb->data, data, len);
760 }
761
762 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
763  *
764  * SYNOPSIS
765  *
766  *    static inline
767  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
768  *                                        const unsigned char *data,
769  *                                        SilcUInt32 len);
770  *
771  * DESCRIPTION
772  *
773  *    Puts data at the tail of the buffer. Returns pointer to the copied
774  *    data area.  Returns NULL if the data is longer than the current tail
775  *    area.
776  *
777  * EXAMPLE
778  *
779  *    ---------------------------------
780  *    | head  | data           | tail |
781  *    ---------------------------------
782  *                             ^
783  *                             Puts data to the tail section.
784  *
785  *    silc_buffer_put_tail(sb, data, data_len);
786  *
787  ***/
788
789 static inline
790 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
791                                     const unsigned char *data,
792                                     SilcUInt32 len)
793 {
794 #ifdef SILC_DIST_INPLACE
795   SILC_ASSERT(len <= silc_buffer_taillen(sb));
796 #endif /* SILC_DIST_INPLACE */
797   if (silc_unlikely(len > silc_buffer_taillen(sb)))
798     return NULL;
799
800   return (unsigned char *)memcpy(sb->tail, data, len);
801 }
802
803 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
804  *
805  * SYNOPSIS
806  *
807  *    static inline
808  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
809  *
810  * DESCRIPTION
811  *
812  *    Allocates `len' bytes size buffer and moves the tail area automatically
813  *    `len' bytes so that the buffer is ready to use without calling the
814  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
815  *
816  ***/
817
818 static inline
819 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
820 {
821   SilcBuffer sb = silc_buffer_alloc(len);
822   if (silc_unlikely(!sb))
823     return NULL;
824   silc_buffer_pull_tail(sb, len);
825   return sb;
826 }
827
828 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
829  *
830  * SYNOPSIS
831  *
832  *    static inline
833  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
834  *
835  * DESCRIPTION
836  *
837  *    Allocates `len' bytes size buffer and moves the tail area automatically
838  *    `len' bytes so that the buffer is ready to use without calling the
839  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
840  *
841  *    This routine use SilcStack are memory source.  If `stack' is NULL
842  *    reverts back to normal allocating routine.
843  *
844  *    Note that this call consumes the `stack'.  The caller should push the
845  *    stack before calling the function and pop it later.
846  *
847  ***/
848
849 static inline
850 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
851 {
852   SilcBuffer sb = silc_buffer_salloc(stack, len);
853   if (silc_unlikely(!sb))
854     return NULL;
855   silc_buffer_pull_tail(sb, len);
856   return sb;
857 }
858
859 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
860  *
861  * SYNOPSIS
862  *
863  *    static inline
864  *    void silc_buffer_reset(SilcBuffer sb);
865  *
866  * DESCRIPTION
867  *
868  *    Resets the buffer to the state as if it was just allocated by
869  *    silc_buffer_alloc.  This does not clear the data area.  Use
870  *    silc_buffer_clear if you also want to clear the data area.
871  *
872  ***/
873
874 static inline
875 void silc_buffer_reset(SilcBuffer sb)
876 {
877   sb->data = sb->tail = sb->head;
878 }
879
880 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
881  *
882  * SYNOPSIS
883  *
884  *    static inline
885  *    void silc_buffer_clear(SilcBuffer sb);
886  *
887  * DESCRIPTION
888  *
889  *    Clears and initialiazes the buffer to the state as if it was just
890  *    allocated by silc_buffer_alloc.
891  *
892  ***/
893
894 static inline
895 void silc_buffer_clear(SilcBuffer sb)
896 {
897   memset(sb->head, 0, silc_buffer_truelen(sb));
898   silc_buffer_reset(sb);
899 }
900
901 /****f* silcutil/SilcBufferAPI/silc_buffer_start
902  *
903  * SYNOPSIS
904  *
905  *    static inline
906  *    void silc_buffer_start(SilcBuffer sb);
907  *
908  * DESCRIPTION
909  *
910  *    Moves the data area at the start of the buffer.  The tail area remains
911  *    as is.
912  *
913  ***/
914
915 static inline
916 void silc_buffer_start(SilcBuffer sb)
917 {
918   sb->data = sb->head;
919 }
920
921 /****f* silcutil/SilcBufferAPI/silc_buffer_end
922  *
923  * SYNOPSIS
924  *
925  *    static inline
926  *    void silc_buffer_end(SilcBuffer sb);
927  *
928  * DESCRIPTION
929  *
930  *    Moves the end of the data area to the end of the buffer.  The start
931  *    of the data area remains same.  If the start of data area is at the
932  *    start of the buffer, after this function returns the buffer's data
933  *    area length is the length of the entire buffer.
934  *
935  ***/
936
937 static inline
938 void silc_buffer_end(SilcBuffer sb)
939 {
940   sb->tail = sb->end;
941 }
942
943 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
944  *
945  * SYNOPSIS
946  *
947  *    static inline
948  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
949  *
950  * DESCRIPTION
951  *
952  *    Generates copy of a SilcBuffer. This copies everything inside the
953  *    currently valid data area, nothing more. Use silc_buffer_clone to
954  *    copy entire buffer.  Returns NULL if system is out of memory.
955  *
956  ***/
957
958 static inline
959 SilcBuffer silc_buffer_copy(SilcBuffer sb)
960 {
961   SilcBuffer sb_new;
962
963   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
964   if (silc_unlikely(!sb_new))
965     return NULL;
966   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
967
968   return sb_new;
969 }
970
971 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
972  *
973  * SYNOPSIS
974  *
975  *    static inline
976  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
977  *
978  * DESCRIPTION
979  *
980  *    Generates copy of a SilcBuffer. This copies everything inside the
981  *    currently valid data area, nothing more. Use silc_buffer_clone to
982  *    copy entire buffer.  Returns NULL if system is out of memory.
983  *
984  *    This routine use SilcStack are memory source.  If `stack' is NULL
985  *    reverts back to normal allocating routine.
986  *
987  *    Note that this call consumes the `stack'.  The caller should push the
988  *    stack before calling the function and pop it later.
989  *
990  ***/
991
992 static inline
993 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
994 {
995   SilcBuffer sb_new;
996
997   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
998   if (silc_unlikely(!sb_new))
999     return NULL;
1000   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1001
1002   return sb_new;
1003 }
1004
1005 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1006  *
1007  * SYNOPSIS
1008  *
1009  *    static inline
1010  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
1011  *
1012  * DESCRIPTION
1013  *
1014  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1015  *    everything from the source buffer. The result is exact clone of
1016  *    the original buffer.  Returns NULL if system is out of memory.
1017  *
1018  ***/
1019
1020 static inline
1021 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1022 {
1023   SilcBuffer sb_new;
1024
1025   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1026   if (silc_unlikely(!sb_new))
1027     return NULL;
1028   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1029   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1030   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1031
1032   return sb_new;
1033 }
1034
1035 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1036  *
1037  * SYNOPSIS
1038  *
1039  *    static inline
1040  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1041  *
1042  * DESCRIPTION
1043  *
1044  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1045  *    everything from the source buffer. The result is exact clone of
1046  *    the original buffer.  Returns NULL if system is out of memory.
1047  *
1048  *    This routine use SilcStack are memory source.  If `stack' is NULL
1049  *    reverts back to normal allocating routine.
1050  *
1051  *    Note that this call consumes the `stack'.  The caller should push the
1052  *    stack before calling the function and pop it later.
1053  *
1054  ***/
1055
1056 static inline
1057 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1058 {
1059   SilcBuffer sb_new;
1060
1061   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1062   if (silc_unlikely(!sb_new))
1063     return NULL;
1064   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1065   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1066   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1067
1068   return sb_new;
1069 }
1070
1071 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1072  *
1073  * SYNOPSIS
1074  *
1075  *    static inline
1076  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1077  *
1078  * DESCRIPTION
1079  *
1080  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1081  *    is exact clone of the old one except that there is now more space
1082  *    at the end of buffer.  This always returns the same `sb' unless `sb'
1083  *    was NULL. Returns NULL if system is out of memory.
1084  *
1085  ***/
1086
1087 static inline
1088 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1089 {
1090   SilcUInt32 hlen, dlen;
1091   unsigned char *h;
1092
1093   if (!sb)
1094     return silc_buffer_alloc(newsize);
1095
1096   if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1097     return sb;
1098
1099   hlen = silc_buffer_headlen(sb);
1100   dlen = silc_buffer_len(sb);
1101   h = (unsigned char *)silc_realloc(sb->head, newsize);
1102   if (silc_unlikely(!h))
1103     return NULL;
1104   sb->head = h;
1105   sb->data = sb->head + hlen;
1106   sb->tail = sb->data + dlen;
1107   sb->end = sb->head + newsize;
1108
1109   return sb;
1110 }
1111
1112 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1113  *
1114  * SYNOPSIS
1115  *
1116  *    static inline
1117  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
1118  *                                    SilcBuffer sb, SilcUInt32 newsize);
1119  *
1120  * DESCRIPTION
1121  *
1122  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1123  *    is exact clone of the old one except that there is now more space
1124  *    at the end of buffer.  Returns NULL if system is out of memory.
1125  *
1126  *    This routine use SilcStack are memory source.  If `stack' is NULL
1127  *    reverts back to normal allocating routine.
1128  *
1129  *    Note that this call consumes the `stack'.  The caller should push the
1130  *    stack before calling the function and pop it later.
1131  *
1132  ***/
1133
1134 static inline
1135 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1136                                 SilcBuffer sb, SilcUInt32 newsize)
1137 {
1138   SilcUInt32 hlen, dlen;
1139   unsigned char *h;
1140
1141   if (!stack)
1142     return silc_buffer_realloc(sb, newsize);
1143
1144   if (!sb)
1145     return silc_buffer_salloc(stack, newsize);
1146
1147   if (newsize <= silc_buffer_truelen(sb))
1148     return sb;
1149
1150   hlen = silc_buffer_headlen(sb);
1151   dlen = silc_buffer_len(sb);
1152   h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1153                                      sb->head, newsize);
1154   if (!h) {
1155     /* Do slow and stack wasting realloc.  The old sb->head is lost and
1156        is freed eventually. */
1157     h = (unsigned char *)silc_smalloc(stack, newsize);
1158     if (silc_unlikely(!h))
1159       return NULL;
1160     memcpy(h, sb->head, silc_buffer_truelen(sb));
1161   }
1162
1163   sb->head = h;
1164   sb->data = sb->head + hlen;
1165   sb->tail = sb->data + dlen;
1166   sb->end = sb->head + newsize;
1167
1168   return sb;
1169 }
1170
1171 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1172  *
1173  * SYNOPSIS
1174  *
1175  *    static inline
1176  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1177  *
1178  * DESCRIPTION
1179  *
1180  *    Same as silc_buffer_realloc but moves moves the tail area
1181  *    automatically so that the buffer is ready to use without calling the
1182  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1183  *
1184  ***/
1185
1186 static inline
1187 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1188 {
1189   sb = silc_buffer_realloc(sb, newsize);
1190   if (silc_unlikely(!sb))
1191     return NULL;
1192   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1193   return sb;
1194 }
1195
1196 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1197  *
1198  * SYNOPSIS
1199  *
1200  *    static inline
1201  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1202  *                                         SilcBuffer sb, SilcUInt32 newsize);
1203  *
1204  * DESCRIPTION
1205  *
1206  *    Same as silc_buffer_srealloc but moves moves the tail area
1207  *    automatically so that the buffer is ready to use without calling the
1208  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1209  *
1210  *    This routine use SilcStack are memory source.  If `stack' is NULL
1211  *    reverts back to normal allocating routine.
1212  *
1213  *    Note that this call consumes the `stack'.  The caller should push the
1214  *    stack before calling the function and pop it later.
1215  *
1216  ***/
1217
1218 static inline
1219 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1220                                      SilcBuffer sb, SilcUInt32 newsize)
1221 {
1222   sb = silc_buffer_srealloc(stack, sb, newsize);
1223   if (silc_unlikely(!sb))
1224     return NULL;
1225   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1226   return sb;
1227 }
1228
1229 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1230  *
1231  * SYNOPSIS
1232  *
1233  *    static inline
1234  *    SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1235  *
1236  * DESCRIPTION
1237  *
1238  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1239  *    must space in the data area and in the tail area.  Moves the tail
1240  *    area automatically after enlarging so that the current data area
1241  *    is at least the size of `size'.  If there is more space than `size'
1242  *    in the data area this does not do anything.  If there is enough
1243  *    space in the tail area this merely moves the tail area to reveal
1244  *    the extra space.  Returns FALSE if system is out of memory.
1245  *
1246  ***/
1247
1248 static inline
1249 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1250 {
1251   if (size > silc_buffer_len(sb)) {
1252     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1253       if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1254                                              (size - silc_buffer_taillen(sb) -
1255                                               silc_buffer_len(sb)))))
1256         return FALSE;
1257     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1258   }
1259   return TRUE;
1260 }
1261
1262 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1263  *
1264  * SYNOPSIS
1265  *
1266  *    static inline
1267  *    SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1268  *                                    SilcUInt32 size);
1269  *
1270  * DESCRIPTION
1271  *
1272  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1273  *    must space in the data area and in the tail area.  Moves the tail
1274  *    area automatically after enlarging so that the current data area
1275  *    is at least the size of `size'.  If there is more space than `size'
1276  *    in the data area this does not do anything.  If there is enough
1277  *    space in the tail area this merely moves the tail area to reveal
1278  *    the extra space.  Returns FALSE if system is out of memory.
1279  *
1280  *    This routine use SilcStack are memory source.  If `stack' is NULL
1281  *    reverts back to normal allocating routine.
1282  *
1283  *    Note that this call consumes the `stack'.  The caller should push the
1284  *    stack before calling the function and pop it later.
1285  *
1286  ***/
1287
1288 static inline
1289 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1290 {
1291   if (size > silc_buffer_len(sb)) {
1292     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1293       if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1294                                               silc_buffer_truelen(sb) +
1295                                               (size - silc_buffer_taillen(sb) -
1296                                                silc_buffer_len(sb)))))
1297         return FALSE;
1298     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1299   }
1300   return TRUE;
1301 }
1302
1303 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1304  *
1305  * SYNOPSIS
1306  *
1307  *    static inline
1308  *    unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1309  *
1310  * DESCRIPTION
1311  *
1312  *    Returns pointer to the occurence of the character `c' in the buffer
1313  *    `sb'.  If the `first' is TRUE this finds the first occurene of `c',
1314  *    if it is FALSE this finds the last occurence of `c'.  If the character
1315  *    is found the `sb' data area is moved to that location and its pointer
1316  *    is returned.  The silc_buffer_data call will return the same pointer.
1317  *    Returns NULL if such character could not be located and the buffer
1318  *    remains unmodified.
1319  *
1320  *    This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1321  *    except it works with SilcBuffer.
1322  *
1323  * NOTES
1324  *
1325  *    This searches only the data area of the buffer.  Head and tail area
1326  *    are not searched.
1327  *
1328  *    The `sb' data need not be NULL terminated.
1329  *
1330  ***/
1331
1332 static inline
1333 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1334 {
1335   int i;
1336
1337   if (first) {
1338     for (i = 0; i < silc_buffer_len(sb); i++) {
1339       if (sb->data[i] == (unsigned char)c) {
1340         sb->data = &sb->data[i];
1341         return sb->data;
1342       }
1343     }
1344   } else {
1345     for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1346       if (sb->data[i] == (unsigned char)c) {
1347         sb->data = &sb->data[i];
1348         return sb->data;
1349       }
1350     }
1351   }
1352
1353   return NULL;
1354 }
1355
1356 #endif /* SILCBUFFER_H */