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