Added silc_buffer_data.
[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 /****f* silcutil/SilcBufferAPI/silc_buffer_data
181  *
182  * NAME
183  *
184  *    unsigned char *silc_buffer_data(SilcBuffer sb)
185  *
186  * DESCRIPTION
187  *
188  *    Returns pointer to the data area of the buffer.
189  *
190  * SOURCE
191  */
192 #define silc_buffer_data(x) (x)->data
193 /***/
194
195 /* Inline functions */
196
197 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
198  *
199  * SYNOPSIS
200  *
201  *    static inline
202  *    SilcBuffer silc_buffer_alloc(SilcUInt32 len);
203  *
204  * DESCRIPTION
205  *
206  *    Allocates new SilcBuffer and returns it.  Returns NULL on error.
207  *
208  ***/
209
210 static inline
211 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
212 {
213   SilcBuffer sb;
214
215   /* Allocate new SilcBuffer */
216   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
217   if (!sb)
218     return NULL;
219
220   if (len) {
221     /* Allocate the actual data area */
222     sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
223     if (!sb->head)
224       return NULL;
225
226     /* Set pointers to the new buffer */
227     sb->data = sb->head;
228     sb->tail = sb->head;
229     sb->end = sb->head + len;
230   }
231
232   return sb;
233 }
234
235 /****f* silcutil/SilcBufferAPI/silc_buffer_free
236  *
237  * SYNOPSIS
238  *
239  *    static inline
240  *    void silc_buffer_free(SilcBuffer sb);
241  *
242  * DESCRIPTION
243  *
244  *    Frees SilcBuffer.  Can be called safely `sb' as NULL.
245  *
246  ***/
247
248 static inline
249 void silc_buffer_free(SilcBuffer sb)
250 {
251   if (sb) {
252 #if defined(SILC_DEBUG)
253     if (sb->head)
254       memset(sb->head, 'F', silc_buffer_truelen(sb));
255 #endif
256     silc_free(sb->head);
257     silc_free(sb);
258   }
259 }
260
261 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
262  *
263  * SYNOPSIS
264  *
265  *    static inline
266  *    unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
267  *
268  * DESCRIPTION
269  *
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
275  *    silc_free.
276  *
277  ***/
278
279 static inline
280 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
281 {
282   unsigned char *buf = sb->head;
283   if (data_len)
284     *data_len = silc_buffer_truelen(sb);
285   sb->head = sb->data = sb->tail = sb->end = NULL;
286   return buf;
287 }
288
289 /****f* silcutil/SilcBufferAPI/silc_buffer_set
290  *
291  * SYNOPSIS
292  *
293  *    static inline
294  *    void silc_buffer_set(SilcBuffer sb,
295  *                         unsigned char *data,
296  *                         SilcUInt32 data_len);
297  *
298  * DESCRIPTION
299  *
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.
304  *
305  * EXAMPLE
306  *
307  *    SilcBufferStruct buf;
308  *    silc_buffer_set(&buf, data, data_len);
309  *
310  ***/
311
312 static inline
313 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
314 {
315   sb->data = sb->head = data;
316   sb->tail = sb->end = data + data_len;
317 }
318
319 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
320  *
321  * SYNOPSIS
322  *
323  *    static inline
324  *    unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
325  *
326  * DESCRIPTION
327  *
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.
331  *
332  * EXAMPLE
333  *
334  *    ---------------------------------
335  *    | head  | data       | tail     |
336  *    ---------------------------------
337  *            ^
338  *            Pulls the start of the data area.
339  *
340  *    ---------------------------------
341  *    | head     | data    | tail     |
342  *    ---------------------------------
343  *            ^
344  *
345  *    silc_buffer_pull(sb, 20);
346  *
347  ***/
348
349 static inline
350 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
351 {
352   unsigned char *old_data = sb->data;
353 #if defined(SILC_DEBUG)
354   assert(len <= silc_buffer_len(sb));
355 #else
356   if (len > silc_buffer_len(sb))
357     return NULL;
358 #endif
359   sb->data += len;
360   return old_data;
361 }
362
363 /****f* silcutil/SilcBufferAPI/silc_buffer_push
364  *
365  * SYNOPSIS
366  *
367  *    static inline
368  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
369  *
370  * DESCRIPTION
371  *
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.
375  *
376  * EXAMPLE
377  *
378  *    ---------------------------------
379  *    | head     | data    | tail     |
380  *    ---------------------------------
381  *               ^
382  *               Pushes the start of the data area.
383  *
384  *    ---------------------------------
385  *    | head  | data       | tail     |
386  *    ---------------------------------
387  *               ^
388  *
389  *    silc_buffer_push(sb, 20);
390  *
391  ***/
392
393 static inline
394 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
395 {
396   unsigned char *old_data = sb->data;
397 #if defined(SILC_DEBUG)
398   assert((sb->data - len) >= sb->head);
399 #else
400   if ((sb->data - len) < sb->head)
401     return NULL;
402 #endif
403   sb->data -= len;
404   return old_data;
405 }
406
407 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
408  *
409  * SYNOPSIS
410  *
411  *    static inline
412  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
413  *
414  * DESCRIPTION
415  *
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.
419  *
420  * EXAMPLE
421  *
422  *    ---------------------------------
423  *    | head  | data       | tail     |
424  *    ---------------------------------
425  *                         ^
426  *                         Pulls the start of the tail section.
427  *
428  *    ---------------------------------
429  *    | head  | data           | tail |
430  *    ---------------------------------
431  *                         ^
432  *
433  *    silc_buffer_pull_tail(sb, 23);
434  *
435  ***/
436
437 static inline
438 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
439 {
440   unsigned char *old_tail = sb->tail;
441 #if defined(SILC_DEBUG)
442   assert(len <= silc_buffer_taillen(sb));
443 #else
444   if (len > silc_buffer_taillen(sb))
445     return NULL;
446 #endif
447   sb->tail += len;
448   return old_tail;
449 }
450
451 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
452  *
453  * SYNOPSIS
454  *
455  *    static inline
456  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
457  *
458  * DESCRIPTION
459  *
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.
463  *
464  * EXAMPLE
465  *
466  *    ---------------------------------
467  *    | head  | data           | tail |
468  *    ---------------------------------
469  *                             ^
470  *                             Pushes the start of the tail section.
471  *
472  *    ---------------------------------
473  *    | head  | data       | tail     |
474  *    ---------------------------------
475  *                             ^
476  *
477  *    silc_buffer_push_tail(sb, 23);
478  *
479  ***/
480
481 static inline
482 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
483 {
484   unsigned char *old_tail = sb->tail;
485 #if defined(SILC_DEBUG)
486   assert((sb->tail - len) >= sb->data);
487 #else
488   if ((sb->tail - len) < sb->data)
489     return NULL;
490 #endif
491   sb->tail -= len;
492   return old_tail;
493 }
494
495 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
496  *
497  * SYNOPSIS
498  *
499  *    static inline
500  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
501  *                                        const unsigned char *data,
502  *                                        SilcUInt32 len);
503  *
504  * DESCRIPTION
505  *
506  *    Puts data at the head of the buffer. Returns pointer to the copied
507  *    data area. Returns NULL on error.
508  *
509  * EXAMPLE
510  *
511  *    ---------------------------------
512  *    | head  | data       | tail     |
513  *    ---------------------------------
514  *    ^
515  *    Puts data to the head section.
516  *
517  *    silc_buffer_put_head(sb, data, data_len);
518  *
519  ***/
520
521 static inline
522 unsigned char *silc_buffer_put_head(SilcBuffer sb,
523                                     const unsigned char *data,
524                                     SilcUInt32 len)
525 {
526 #if defined(SILC_DEBUG)
527   assert(len <= silc_buffer_headlen(sb));
528 #else
529   if (len > silc_buffer_headlen(sb))
530     return NULL;
531 #endif
532   return (unsigned char *)memcpy(sb->head, data, len);
533 }
534
535 /****f* silcutil/SilcBufferAPI/silc_buffer_put
536  *
537  * SYNOPSIS
538  *
539  *    static inline
540  *    unsigned char *silc_buffer_put(SilcBuffer sb,
541  *                                   const unsigned char *data,
542  *                                   SilcUInt32 len);
543  *
544  * DESCRIPTION
545  *
546  *    Puts data at the start of the valid data area. Returns a pointer
547  *    to the copied data area.  Returns NULL on error.
548  *
549  * EXAMPLE
550  *
551  *    ---------------------------------
552  *    | head  | data       | tail     |
553  *    ---------------------------------
554  *            ^
555  *            Puts data to the data section.
556  *
557  *    silc_buffer_put(sb, data, data_len);
558  *
559  ***/
560
561 static inline
562 unsigned char *silc_buffer_put(SilcBuffer sb,
563                                const unsigned char *data,
564                                SilcUInt32 len)
565 {
566 #if defined(SILC_DEBUG)
567   assert(len <= silc_buffer_len(sb));
568 #else
569   if (len > silc_buffer_len(sb))
570     return NULL;
571 #endif
572   return (unsigned char *)memcpy(sb->data, data, len);
573 }
574
575 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
576  *
577  * SYNOPSIS
578  *
579  *    static inline
580  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
581  *                                        const unsigned char *data,
582  *                                        SilcUInt32 len);
583  *
584  * DESCRIPTION
585  *
586  *    Puts data at the tail of the buffer. Returns pointer to the copied
587  *    data area.  Returns NULL on error.
588  *
589  * EXAMPLE
590  *
591  *    ---------------------------------
592  *    | head  | data           | tail |
593  *    ---------------------------------
594  *                             ^
595  *                             Puts data to the tail section.
596  *
597  *    silc_buffer_put_tail(sb, data, data_len);
598  *
599  ***/
600
601 static inline
602 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
603                                     const unsigned char *data,
604                                     SilcUInt32 len)
605 {
606 #if defined(SILC_DEBUG)
607   assert(len <= silc_buffer_taillen(sb));
608 #else
609   if (len > silc_buffer_taillen(sb))
610     return NULL;
611 #endif
612   return (unsigned char *)memcpy(sb->tail, data, len);
613 }
614
615 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
616  *
617  * SYNOPSIS
618  *
619  *    static inline
620  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
621  *
622  * DESCRIPTION
623  *
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.
627  *
628  ***/
629
630 static inline
631 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
632 {
633   SilcBuffer sb = silc_buffer_alloc(len);
634   if (!sb)
635     return NULL;
636   silc_buffer_pull_tail(sb, len);
637   return sb;
638 }
639
640 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
641  *
642  * SYNOPSIS
643  *
644  *    static inline
645  *    void silc_buffer_reset(SilcBuffer sb);
646  *
647  * DESCRIPTION
648  *
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.
652  *
653  ***/
654
655 static inline
656 void silc_buffer_reset(SilcBuffer sb)
657 {
658   sb->data = sb->tail = sb->head;
659 }
660
661 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
662  *
663  * SYNOPSIS
664  *
665  *    static inline
666  *    void silc_buffer_clear(SilcBuffer sb);
667  *
668  * DESCRIPTION
669  *
670  *    Clears and initialiazes the buffer to the state as if it was just
671  *    allocated by silc_buffer_alloc.
672  *
673  ***/
674
675 static inline
676 void silc_buffer_clear(SilcBuffer sb)
677 {
678   memset(sb->head, 0, silc_buffer_truelen(sb));
679   silc_buffer_reset(sb);
680 }
681
682 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
683  *
684  * SYNOPSIS
685  *
686  *    static inline
687  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
688  *
689  * DESCRIPTION
690  *
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.
694  *
695  ***/
696
697 static inline
698 SilcBuffer silc_buffer_copy(SilcBuffer sb)
699 {
700   SilcBuffer sb_new;
701
702   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
703   if (!sb_new)
704     return NULL;
705   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
706
707   return sb_new;
708 }
709
710 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
711  *
712  * SYNOPSIS
713  *
714  *    static inline
715  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
716  *
717  * DESCRIPTION
718  *
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.
722  *
723  ***/
724
725 static inline
726 SilcBuffer silc_buffer_clone(SilcBuffer sb)
727 {
728   SilcBuffer sb_new;
729
730   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
731   if (!sb_new)
732     return NULL;
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);
736
737   return sb_new;
738 }
739
740 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
741  *
742  * SYNOPSIS
743  *
744  *    static inline
745  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
746  *
747  * DESCRIPTION
748  *
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.
753  *
754  ***/
755
756 static inline
757 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
758 {
759   SilcUInt32 hlen, dlen;
760   unsigned char *h;
761
762   if (!sb)
763     return silc_buffer_alloc(newsize);
764
765   if (newsize <= silc_buffer_truelen(sb))
766     return sb;
767
768   hlen = silc_buffer_headlen(sb);
769   dlen = silc_buffer_len(sb);
770   h = (unsigned char *)silc_realloc(sb->head, newsize);
771   if (!h)
772     return NULL;
773   sb->head = h;
774   sb->data = sb->head + hlen;
775   sb->tail = sb->data + dlen;
776   sb->end = sb->head + newsize;
777
778   return sb;
779 }
780
781 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
782  *
783  * SYNOPSIS
784  *
785  *    static inline
786  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
787  *
788  * DESCRIPTION
789  *
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.
793  *
794  ***/
795
796 static inline
797 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
798 {
799   sb = silc_buffer_realloc(sb, newsize);
800   if (!sb)
801     return NULL;
802   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
803   return sb;
804 }
805
806
807 /* SilcStack aware SilcBuffer routines */
808
809 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
810  *
811  * SYNOPSIS
812  *
813  *    static inline
814  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
815  *
816  * DESCRIPTION
817  *
818  *    Allocates new SilcBuffer and returns it.
819  *
820  *    This routine use SilcStack are memory source.  If `stack' is NULL
821  *    reverts back to normal allocating routine.
822  *
823  ***/
824
825 static inline
826 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
827 {
828   SilcBuffer sb;
829
830   if (!stack)
831     return silc_buffer_alloc(len);
832
833   /* Allocate new SilcBuffer */
834   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
835   if (!sb)
836     return NULL;
837
838   /* Allocate the actual data area */
839   sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
840   if (!sb->head)
841     return NULL;
842
843   /* Set pointers to the new buffer */
844   sb->data = sb->head;
845   sb->tail = sb->head;
846   sb->end = sb->head + len;
847
848   return sb;
849 }
850
851 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
852  *
853  * SYNOPSIS
854  *
855  *    static inline
856  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
857  *
858  * DESCRIPTION
859  *
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.
863  *
864  *    This routine use SilcStack are memory source.  If `stack' is NULL
865  *    reverts back to normal allocating routine.
866  *
867  ***/
868
869 static inline
870 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
871 {
872   SilcBuffer sb = silc_buffer_salloc(stack, len);
873   if (!sb)
874     return NULL;
875   silc_buffer_pull_tail(sb, len);
876   return sb;
877 }
878
879 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
880  *
881  * SYNOPSIS
882  *
883  *    static inline
884  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
885  *                                    SilcBuffer sb, SilcUInt32 newsize);
886  *
887  * DESCRIPTION
888  *
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.
892  *
893  *    This routine use SilcStack are memory source.  If `stack' is NULL
894  *    reverts back to normal allocating routine.
895  *
896  ***/
897
898 static inline
899 SilcBuffer silc_buffer_srealloc(SilcStack stack,
900                                 SilcBuffer sb, SilcUInt32 newsize)
901 {
902   SilcUInt32 hlen, dlen;
903   unsigned char *h;
904
905   if (!stack)
906     return silc_buffer_realloc(sb, newsize);
907
908   if (!sb)
909     return silc_buffer_salloc(stack, newsize);
910
911   if (newsize <= silc_buffer_truelen(sb))
912     return sb;
913
914   hlen = silc_buffer_headlen(sb);
915   dlen = silc_buffer_len(sb);
916   h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
917                                         sb->head, newsize);
918   if (!h) {
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);
922     if (!h)
923       return NULL;
924     memcpy(h, sb->head, silc_buffer_truelen(sb));
925   }
926
927   sb->head = h;
928   sb->data = sb->head + hlen;
929   sb->tail = sb->data + dlen;
930   sb->end = sb->head + newsize;
931
932   return sb;
933 }
934
935 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
936  *
937  * SYNOPSIS
938  *
939  *    static inline
940  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
941  *                                         SilcBuffer sb, SilcUInt32 newsize);
942  *
943  * DESCRIPTION
944  *
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.
948  *
949  *    This routine use SilcStack are memory source.  If `stack' is NULL
950  *    reverts back to normal allocating routine.
951  *
952  ***/
953
954 static inline
955 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
956                                      SilcBuffer sb, SilcUInt32 newsize)
957 {
958   sb = silc_buffer_srealloc(stack, sb, newsize);
959   if (!sb)
960     return NULL;
961   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
962   return sb;
963 }
964
965 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
966  *
967  * SYNOPSIS
968  *
969  *    static inline
970  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
971  *
972  * DESCRIPTION
973  *
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.
977  *
978  *    This routine use SilcStack are memory source.  If `stack' is NULL
979  *    reverts back to normal allocating routine.
980  *
981  ***/
982
983 static inline
984 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
985 {
986   SilcBuffer sb_new;
987
988   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
989   if (!sb_new)
990     return NULL;
991   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
992
993   return sb_new;
994 }
995
996 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
997  *
998  * SYNOPSIS
999  *
1000  *    static inline
1001  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1002  *
1003  * DESCRIPTION
1004  *
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.
1008  *
1009  *    This routine use SilcStack are memory source.  If `stack' is NULL
1010  *    reverts back to normal allocating routine.
1011  *
1012  ***/
1013
1014 static inline
1015 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1016 {
1017   SilcBuffer sb_new;
1018
1019   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1020   if (!sb_new)
1021     return NULL;
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);
1025
1026   return sb_new;
1027 }
1028
1029 #endif /* SILCBUFFER_H */