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