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