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