silc_buffer_format reallocates automatically now.
[crypto.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2006 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  * SOURCE
109  */
110 typedef struct {
111   unsigned char *head;
112   unsigned char *data;
113   unsigned char *tail;
114   unsigned char *end;
115 } *SilcBuffer, SilcBufferStruct;
116 /***/
117
118 /* Macros */
119
120 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
121  *
122  * NAME
123  *
124  *    #define silc_buffer_truelen(buffer)
125  *
126  * DESCRIPTION
127  *
128  *    Returns the true length of the buffer.
129  *
130  * SOURCE
131  */
132 #define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
133 /***/
134
135 /****d* silcutil/SilcBufferAPI/silc_buffer_len
136  *
137  * NAME
138  *
139  *    #define silc_buffer_len(buffer)
140  *
141  * DESCRIPTION
142  *
143  *    Returns the current length of the data area of the buffer.
144  *
145  * SOURCE
146  */
147 #define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
148 /***/
149
150 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
151  *
152  * NAME
153  *
154  *    #define silc_buffer_headlen(buffer)
155  *
156  * DESCRIPTION
157  *
158  *    Returns the current length of the head data area of the buffer.
159  *
160  * SOURCE
161  */
162 #define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
163 /***/
164
165 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
166  *
167  * NAME
168  *
169  *    #define silc_buffer_taillen(buffer)
170  *
171  * DESCRIPTION
172  *
173  *    Returns the current length of the tail data area of the buffer.
174  *
175  * SOURCE
176  */
177 #define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
178 /***/
179
180 /* Inline functions */
181
182 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
183  *
184  * SYNOPSIS
185  *
186  *    static inline
187  *    SilcBuffer silc_buffer_alloc(SilcUInt32 len);
188  *
189  * DESCRIPTION
190  *
191  *    Allocates new SilcBuffer and returns it.  Returns NULL on error.
192  *
193  ***/
194
195 static inline
196 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
197 {
198   SilcBuffer sb;
199
200   /* Allocate new SilcBuffer */
201   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
202   if (!sb)
203     return NULL;
204
205   if (len) {
206     /* Allocate the actual data area */
207     sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
208     if (!sb->head)
209       return NULL;
210
211     /* Set pointers to the new buffer */
212     sb->data = sb->head;
213     sb->tail = sb->head;
214     sb->end = sb->head + len;
215   }
216
217   return sb;
218 }
219
220 /****f* silcutil/SilcBufferAPI/silc_buffer_free
221  *
222  * SYNOPSIS
223  *
224  *    static inline
225  *    void silc_buffer_free(SilcBuffer sb);
226  *
227  * DESCRIPTION
228  *
229  *    Frees SilcBuffer.
230  *
231  ***/
232
233 static inline
234 void silc_buffer_free(SilcBuffer sb)
235 {
236   if (sb) {
237 #if defined(SILC_DEBUG)
238     if (sb->head)
239       memset(sb->head, 'F', silc_buffer_truelen(sb));
240 #endif
241     silc_free(sb->head);
242     silc_free(sb);
243   }
244 }
245
246 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
247  *
248  * SYNOPSIS
249  *
250  *    static inline
251  *    unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
252  *
253  * DESCRIPTION
254  *
255  *    Steals the data from the buffer `sb'.  This returns pointer to the
256  *    start of the buffer and the true length of that buffer.  The `sb'
257  *    cannot be used anymore after calling this function because the
258  *    data buffer was stolen.  The `sb' must be freed with silc_buffer_free.
259  *    The caller is responsible of freeing the stolen data buffer with
260  *    silc_free.
261  *
262  ***/
263
264 static inline
265 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
266 {
267   unsigned char *buf = sb->head;
268   if (data_len)
269     *data_len = silc_buffer_truelen(sb);
270   sb->head = sb->data = sb->tail = sb->end = NULL;
271   return buf;
272 }
273
274 /****f* silcutil/SilcBufferAPI/silc_buffer_set
275  *
276  * SYNOPSIS
277  *
278  *    static inline
279  *    void silc_buffer_set(SilcBuffer sb,
280  *                         unsigned char *data,
281  *                         SilcUInt32 data_len);
282  *
283  * DESCRIPTION
284  *
285  *    Sets the `data' and `data_len' to the buffer pointer sent as argument.
286  *    The data area is automatically set to the `data_len'. This function
287  *    can be used to set the data to static buffer without needing any
288  *    memory allocations. The `data' will not be copied to the buffer.
289  *
290  * EXAMPLE
291  *
292  *    SilcBufferStruct buf;
293  *    silc_buffer_set(&buf, data, data_len);
294  *
295  ***/
296
297 static inline
298 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
299 {
300   sb->data = sb->head = data;
301   sb->tail = sb->end = data + data_len;
302 }
303
304 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
305  *
306  * SYNOPSIS
307  *
308  *    static inline
309  *    unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
310  *
311  * DESCRIPTION
312  *
313  *    Pulls current data area towards end. The length of the currently
314  *    valid data area is also decremented. Returns pointer to the data
315  *    area before pulling. Returns NULL on error.
316  *
317  * EXAMPLE
318  *
319  *    ---------------------------------
320  *    | head  | data       | tail     |
321  *    ---------------------------------
322  *            ^
323  *            Pulls the start of the data area.
324  *
325  *    ---------------------------------
326  *    | head     | data    | tail     |
327  *    ---------------------------------
328  *            ^
329  *
330  *    silc_buffer_pull(sb, 20);
331  *
332  ***/
333
334 static inline
335 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
336 {
337   unsigned char *old_data = sb->data;
338 #if defined(SILC_DEBUG)
339   assert(len <= silc_buffer_len(sb));
340 #else
341   if (len > silc_buffer_len(sb))
342     return NULL;
343 #endif
344   sb->data += len;
345   return old_data;
346 }
347
348 /****f* silcutil/SilcBufferAPI/silc_buffer_push
349  *
350  * SYNOPSIS
351  *
352  *    static inline
353  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
354  *
355  * DESCRIPTION
356  *
357  *    Pushes current data area towards beginning. Length of the currently
358  *    valid data area is also incremented. Returns a pointer to the
359  *    data area before pushing. Returns NULL on error.
360  *
361  * EXAMPLE
362  *
363  *    ---------------------------------
364  *    | head     | data    | tail     |
365  *    ---------------------------------
366  *               ^
367  *               Pushes the start of the data area.
368  *
369  *    ---------------------------------
370  *    | head  | data       | tail     |
371  *    ---------------------------------
372  *               ^
373  *
374  *    silc_buffer_push(sb, 20);
375  *
376  ***/
377
378 static inline
379 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
380 {
381   unsigned char *old_data = sb->data;
382 #if defined(SILC_DEBUG)
383   assert((sb->data - len) >= sb->head);
384 #else
385   if ((sb->data - len) < sb->head)
386     return NULL;
387 #endif
388   sb->data -= len;
389   return old_data;
390 }
391
392 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
393  *
394  * SYNOPSIS
395  *
396  *    static inline
397  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
398  *
399  * DESCRIPTION
400  *
401  *    Pulls current tail section towards end. Length of the current valid
402  *    data area is also incremented. Returns a pointer to the data area
403  *    before pulling. Returns NULL on error.
404  *
405  * EXAMPLE
406  *
407  *    ---------------------------------
408  *    | head  | data       | tail     |
409  *    ---------------------------------
410  *                         ^
411  *                         Pulls the start of the tail section.
412  *
413  *    ---------------------------------
414  *    | head  | data           | tail |
415  *    ---------------------------------
416  *                         ^
417  *
418  *    silc_buffer_pull_tail(sb, 23);
419  *
420  ***/
421
422 static inline
423 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
424 {
425   unsigned char *old_tail = sb->tail;
426 #if defined(SILC_DEBUG)
427   assert(len <= silc_buffer_taillen(sb));
428 #else
429   if (len > silc_buffer_taillen(sb))
430     return NULL;
431 #endif
432   sb->tail += len;
433   return old_tail;
434 }
435
436 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
437  *
438  * SYNOPSIS
439  *
440  *    static inline
441  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
442  *
443  * DESCRIPTION
444  *
445  *    Pushes current tail section towards beginning. Length of the current
446  *    valid data area is also decremented. Returns a pointer to the
447  *    tail section before pushing. Returns NULL on error.
448  *
449  * EXAMPLE
450  *
451  *    ---------------------------------
452  *    | head  | data           | tail |
453  *    ---------------------------------
454  *                             ^
455  *                             Pushes the start of the tail section.
456  *
457  *    ---------------------------------
458  *    | head  | data       | tail     |
459  *    ---------------------------------
460  *                             ^
461  *
462  *    silc_buffer_push_tail(sb, 23);
463  *
464  ***/
465
466 static inline
467 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
468 {
469   unsigned char *old_tail = sb->tail;
470 #if defined(SILC_DEBUG)
471   assert((sb->tail - len) >= sb->data);
472 #else
473   if ((sb->tail - len) < sb->data)
474     return NULL;
475 #endif
476   sb->tail -= len;
477   return old_tail;
478 }
479
480 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
481  *
482  * SYNOPSIS
483  *
484  *    static inline
485  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
486  *                                        const unsigned char *data,
487  *                                        SilcUInt32 len);
488  *
489  * DESCRIPTION
490  *
491  *    Puts data at the head of the buffer. Returns pointer to the copied
492  *    data area. Returns NULL on error.
493  *
494  * EXAMPLE
495  *
496  *    ---------------------------------
497  *    | head  | data       | tail     |
498  *    ---------------------------------
499  *    ^
500  *    Puts data to the head section.
501  *
502  *    silc_buffer_put_head(sb, data, data_len);
503  *
504  ***/
505
506 static inline
507 unsigned char *silc_buffer_put_head(SilcBuffer sb,
508                                     const unsigned char *data,
509                                     SilcUInt32 len)
510 {
511 #if defined(SILC_DEBUG)
512   assert(len <= silc_buffer_headlen(sb));
513 #else
514   if (len > silc_buffer_headlen(sb))
515     return NULL;
516 #endif
517   return (unsigned char *)memcpy(sb->head, data, len);
518 }
519
520 /****f* silcutil/SilcBufferAPI/silc_buffer_put
521  *
522  * SYNOPSIS
523  *
524  *    static inline
525  *    unsigned char *silc_buffer_put(SilcBuffer sb,
526  *                                   const unsigned char *data,
527  *                                   SilcUInt32 len);
528  *
529  * DESCRIPTION
530  *
531  *    Puts data at the start of the valid data area. Returns a pointer
532  *    to the copied data area.  Returns NULL on error.
533  *
534  * EXAMPLE
535  *
536  *    ---------------------------------
537  *    | head  | data       | tail     |
538  *    ---------------------------------
539  *            ^
540  *            Puts data to the data section.
541  *
542  *    silc_buffer_put(sb, data, data_len);
543  *
544  ***/
545
546 static inline
547 unsigned char *silc_buffer_put(SilcBuffer sb,
548                                const unsigned char *data,
549                                SilcUInt32 len)
550 {
551 #if defined(SILC_DEBUG)
552   assert(len <= silc_buffer_len(sb));
553 #else
554   if (len > silc_buffer_len(sb))
555     return NULL;
556 #endif
557   return (unsigned char *)memcpy(sb->data, data, len);
558 }
559
560 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
561  *
562  * SYNOPSIS
563  *
564  *    static inline
565  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
566  *                                        const unsigned char *data,
567  *                                        SilcUInt32 len);
568  *
569  * DESCRIPTION
570  *
571  *    Puts data at the tail of the buffer. Returns pointer to the copied
572  *    data area.  Returns NULL on error.
573  *
574  * EXAMPLE
575  *
576  *    ---------------------------------
577  *    | head  | data           | tail |
578  *    ---------------------------------
579  *                             ^
580  *                             Puts data to the tail section.
581  *
582  *    silc_buffer_put_tail(sb, data, data_len);
583  *
584  ***/
585
586 static inline
587 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
588                                     const unsigned char *data,
589                                     SilcUInt32 len)
590 {
591 #if defined(SILC_DEBUG)
592   assert(len <= silc_buffer_taillen(sb));
593 #else
594   if (len > silc_buffer_taillen(sb))
595     return NULL;
596 #endif
597   return (unsigned char *)memcpy(sb->tail, data, len);
598 }
599
600 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
601  *
602  * SYNOPSIS
603  *
604  *    static inline
605  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
606  *
607  * DESCRIPTION
608  *
609  *    Allocates `len' bytes size buffer and moves the tail area automatically
610  *    `len' bytes so that the buffer is ready to use without calling the
611  *    silc_buffer_pull_tail.  Returns NULL on error.
612  *
613  ***/
614
615 static inline
616 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
617 {
618   SilcBuffer sb = silc_buffer_alloc(len);
619   if (!sb)
620     return NULL;
621   silc_buffer_pull_tail(sb, len);
622   return sb;
623 }
624
625 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
626  *
627  * SYNOPSIS
628  *
629  *    static inline
630  *    void silc_buffer_reset(SilcBuffer sb);
631  *
632  * DESCRIPTION
633  *
634  *    Resets the buffer to the state as if it was just allocated by
635  *    silc_buffer_alloc.  This does not clear the data area.  Use
636  *    silc_buffer_clear if you also want to clear the data area.
637  *
638  ***/
639
640 static inline
641 void silc_buffer_reset(SilcBuffer sb)
642 {
643   sb->data = sb->tail = sb->head;
644 }
645
646 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
647  *
648  * SYNOPSIS
649  *
650  *    static inline
651  *    void silc_buffer_clear(SilcBuffer sb);
652  *
653  * DESCRIPTION
654  *
655  *    Clears and initialiazes the buffer to the state as if it was just
656  *    allocated by silc_buffer_alloc.
657  *
658  ***/
659
660 static inline
661 void silc_buffer_clear(SilcBuffer sb)
662 {
663   memset(sb->head, 0, silc_buffer_truelen(sb));
664   silc_buffer_reset(sb);
665 }
666
667 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
668  *
669  * SYNOPSIS
670  *
671  *    static inline
672  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
673  *
674  * DESCRIPTION
675  *
676  *    Generates copy of a SilcBuffer. This copies everything inside the
677  *    currently valid data area, nothing more. Use silc_buffer_clone to
678  *    copy entire buffer.  Returns NULL on error.
679  *
680  ***/
681
682 static inline
683 SilcBuffer silc_buffer_copy(SilcBuffer sb)
684 {
685   SilcBuffer sb_new;
686
687   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
688   if (!sb_new)
689     return NULL;
690   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
691
692   return sb_new;
693 }
694
695 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
696  *
697  * SYNOPSIS
698  *
699  *    static inline
700  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
701  *
702  * DESCRIPTION
703  *
704  *    Clones SilcBuffer. This generates new SilcBuffer and copies
705  *    everything from the source buffer. The result is exact clone of
706  *    the original buffer.  Returns NULL on error.
707  *
708  ***/
709
710 static inline
711 SilcBuffer silc_buffer_clone(SilcBuffer sb)
712 {
713   SilcBuffer sb_new;
714
715   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
716   if (!sb_new)
717     return NULL;
718   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
719   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
720   sb_new->tail = sb_new->data + silc_buffer_len(sb);
721
722   return sb_new;
723 }
724
725 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
726  *
727  * SYNOPSIS
728  *
729  *    static inline
730  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
731  *
732  * DESCRIPTION
733  *
734  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
735  *    is exact clone of the old one except that there is now more space
736  *    at the end of buffer.  This always returns the same `sb' unless `sb'
737  *    was NULL. Returns NULL on error.
738  *
739  ***/
740
741 static inline
742 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
743 {
744   SilcUInt32 hlen, dlen;
745   unsigned char *h;
746
747   if (!sb)
748     return silc_buffer_alloc(newsize);
749
750   if (newsize <= silc_buffer_truelen(sb))
751     return sb;
752
753   hlen = silc_buffer_headlen(sb);
754   dlen = silc_buffer_len(sb);
755   h = (unsigned char *)silc_realloc(sb->head, newsize);
756   if (!h)
757     return NULL;
758   sb->head = h;
759   sb->data = sb->head + hlen;
760   sb->tail = sb->data + dlen;
761   sb->end = sb->head + newsize;
762
763   return sb;
764 }
765
766 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
767  *
768  * SYNOPSIS
769  *
770  *    static inline
771  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
772  *
773  * DESCRIPTION
774  *
775  *    Same as silc_buffer_realloc but moves moves the tail area
776  *    automatically so that the buffer is ready to use without calling the
777  *    silc_buffer_pull_tail.  Returns NULL on error.
778  *
779  ***/
780
781 static inline
782 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
783 {
784   sb = silc_buffer_realloc(sb, newsize);
785   if (!sb)
786     return NULL;
787   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
788   return sb;
789 }
790
791
792 /* SilcStack aware SilcBuffer routines */
793
794 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
795  *
796  * SYNOPSIS
797  *
798  *    static inline
799  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
800  *
801  * DESCRIPTION
802  *
803  *    Allocates new SilcBuffer and returns it.
804  *
805  *    This routine use SilcStack are memory source.  If `stack' is NULL
806  *    reverts back to normal allocating routine.
807  *
808  ***/
809
810 static inline
811 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
812 {
813   SilcBuffer sb;
814
815   if (!stack)
816     return silc_buffer_alloc(len);
817
818   /* Allocate new SilcBuffer */
819   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
820   if (!sb)
821     return NULL;
822
823   /* Allocate the actual data area */
824   sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
825   if (!sb->head)
826     return NULL;
827
828   /* Set pointers to the new buffer */
829   sb->data = sb->head;
830   sb->tail = sb->head;
831   sb->end = sb->head + len;
832
833   return sb;
834 }
835
836 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
837  *
838  * SYNOPSIS
839  *
840  *    static inline
841  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
842  *
843  * DESCRIPTION
844  *
845  *    Allocates `len' bytes size buffer and moves the tail area automatically
846  *    `len' bytes so that the buffer is ready to use without calling the
847  *    silc_buffer_pull_tail.
848  *
849  *    This routine use SilcStack are memory source.  If `stack' is NULL
850  *    reverts back to normal allocating routine.
851  *
852  ***/
853
854 static inline
855 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
856 {
857   SilcBuffer sb = silc_buffer_salloc(stack, len);
858   if (!sb)
859     return NULL;
860   silc_buffer_pull_tail(sb, len);
861   return sb;
862 }
863
864 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
865  *
866  * SYNOPSIS
867  *
868  *    static inline
869  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
870  *                                    SilcBuffer sb, SilcUInt32 newsize);
871  *
872  * DESCRIPTION
873  *
874  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
875  *    is exact clone of the old one except that there is now more space
876  *    at the end of buffer.
877  *
878  *    This routine use SilcStack are memory source.  If `stack' is NULL
879  *    reverts back to normal allocating routine.
880  *
881  ***/
882
883 static inline
884 SilcBuffer silc_buffer_srealloc(SilcStack stack,
885                                 SilcBuffer sb, SilcUInt32 newsize)
886 {
887   SilcUInt32 hlen, dlen;
888   unsigned char *h;
889
890   if (!stack)
891     return silc_buffer_realloc(sb, newsize);
892
893   if (!sb)
894     return silc_buffer_salloc(stack, newsize);
895
896   if (newsize <= silc_buffer_truelen(sb))
897     return sb;
898
899   hlen = silc_buffer_headlen(sb);
900   dlen = silc_buffer_len(sb);
901   h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
902                                         sb->head, newsize);
903   if (!h) {
904     /* Do slow and stack wasting realloc.  The old sb->head is lost and
905        is freed eventually. */
906     h = silc_smalloc_ua(stack, newsize);
907     if (!h)
908       return NULL;
909     memcpy(h, sb->head, silc_buffer_truelen(sb));
910   }
911
912   sb->head = h;
913   sb->data = sb->head + hlen;
914   sb->tail = sb->data + dlen;
915   sb->end = sb->head + newsize;
916
917   return sb;
918 }
919
920 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
921  *
922  * SYNOPSIS
923  *
924  *    static inline
925  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
926  *                                         SilcBuffer sb, SilcUInt32 newsize);
927  *
928  * DESCRIPTION
929  *
930  *    Same as silc_buffer_srealloc but moves moves the tail area
931  *    automatically so that the buffer is ready to use without calling the
932  *    silc_buffer_pull_tail.
933  *
934  *    This routine use SilcStack are memory source.  If `stack' is NULL
935  *    reverts back to normal allocating routine.
936  *
937  ***/
938
939 static inline
940 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
941                                      SilcBuffer sb, SilcUInt32 newsize)
942 {
943   sb = silc_buffer_srealloc(stack, sb, newsize);
944   if (!sb)
945     return NULL;
946   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
947   return sb;
948 }
949
950 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
951  *
952  * SYNOPSIS
953  *
954  *    static inline
955  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
956  *
957  * DESCRIPTION
958  *
959  *    Generates copy of a SilcBuffer. This copies everything inside the
960  *    currently valid data area, nothing more. Use silc_buffer_clone to
961  *    copy entire buffer.
962  *
963  *    This routine use SilcStack are memory source.  If `stack' is NULL
964  *    reverts back to normal allocating routine.
965  *
966  ***/
967
968 static inline
969 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
970 {
971   SilcBuffer sb_new;
972
973   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
974   if (!sb_new)
975     return NULL;
976   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
977
978   return sb_new;
979 }
980
981 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
982  *
983  * SYNOPSIS
984  *
985  *    static inline
986  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
987  *
988  * DESCRIPTION
989  *
990  *    Clones SilcBuffer. This generates new SilcBuffer and copies
991  *    everything from the source buffer. The result is exact clone of
992  *    the original buffer.
993  *
994  *    This routine use SilcStack are memory source.  If `stack' is NULL
995  *    reverts back to normal allocating routine.
996  *
997  ***/
998
999 static inline
1000 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1001 {
1002   SilcBuffer sb_new;
1003
1004   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1005   if (!sb_new)
1006     return NULL;
1007   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1008   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1009   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1010
1011   return sb_new;
1012 }
1013
1014 #endif /* SILCBUFFER_H */