Comment changes.
[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 (!sb)
245     return NULL;
246
247   if (len) {
248     /* Allocate the actual data area */
249     sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
250     if (!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   assert(len <= silc_buffer_len(sb));
413 #else
414   if (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   assert((sb->data - len) >= sb->head);
457 #else
458   if ((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   assert(len <= silc_buffer_taillen(sb));
501 #else
502   if (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   assert((sb->tail - len) >= sb->data);
545 #else
546   if ((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   assert(len <= silc_buffer_headlen(sb));
586 #else
587   if (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   assert(len <= silc_buffer_len(sb));
626 #else
627   if (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   assert(len <= silc_buffer_taillen(sb));
666 #else
667   if (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 (!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_copy
741  *
742  * SYNOPSIS
743  *
744  *    static inline
745  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
746  *
747  * DESCRIPTION
748  *
749  *    Generates copy of a SilcBuffer. This copies everything inside the
750  *    currently valid data area, nothing more. Use silc_buffer_clone to
751  *    copy entire buffer.  Returns NULL on error.
752  *
753  ***/
754
755 static inline
756 SilcBuffer silc_buffer_copy(SilcBuffer sb)
757 {
758   SilcBuffer sb_new;
759
760   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
761   if (!sb_new)
762     return NULL;
763   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
764
765   return sb_new;
766 }
767
768 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
769  *
770  * SYNOPSIS
771  *
772  *    static inline
773  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
774  *
775  * DESCRIPTION
776  *
777  *    Clones SilcBuffer. This generates new SilcBuffer and copies
778  *    everything from the source buffer. The result is exact clone of
779  *    the original buffer.  Returns NULL on error.
780  *
781  ***/
782
783 static inline
784 SilcBuffer silc_buffer_clone(SilcBuffer sb)
785 {
786   SilcBuffer sb_new;
787
788   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
789   if (!sb_new)
790     return NULL;
791   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
792   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
793   sb_new->tail = sb_new->data + silc_buffer_len(sb);
794
795   return sb_new;
796 }
797
798 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
799  *
800  * SYNOPSIS
801  *
802  *    static inline
803  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
804  *
805  * DESCRIPTION
806  *
807  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
808  *    is exact clone of the old one except that there is now more space
809  *    at the end of buffer.  This always returns the same `sb' unless `sb'
810  *    was NULL. Returns NULL on error.
811  *
812  ***/
813
814 static inline
815 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
816 {
817   SilcUInt32 hlen, dlen;
818   unsigned char *h;
819
820   if (!sb)
821     return silc_buffer_alloc(newsize);
822
823   if (newsize <= silc_buffer_truelen(sb))
824     return sb;
825
826   hlen = silc_buffer_headlen(sb);
827   dlen = silc_buffer_len(sb);
828   h = (unsigned char *)silc_realloc(sb->head, newsize);
829   if (!h)
830     return NULL;
831   sb->head = h;
832   sb->data = sb->head + hlen;
833   sb->tail = sb->data + dlen;
834   sb->end = sb->head + newsize;
835
836   return sb;
837 }
838
839 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
840  *
841  * SYNOPSIS
842  *
843  *    static inline
844  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
845  *
846  * DESCRIPTION
847  *
848  *    Same as silc_buffer_realloc but moves moves the tail area
849  *    automatically so that the buffer is ready to use without calling the
850  *    silc_buffer_pull_tail.  Returns NULL on error.
851  *
852  ***/
853
854 static inline
855 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
856 {
857   sb = silc_buffer_realloc(sb, newsize);
858   if (!sb)
859     return NULL;
860   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
861   return sb;
862 }
863
864
865 /* SilcStack aware SilcBuffer routines */
866
867 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
868  *
869  * SYNOPSIS
870  *
871  *    static inline
872  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
873  *
874  * DESCRIPTION
875  *
876  *    Allocates new SilcBuffer and returns it.
877  *
878  *    This routine use SilcStack are memory source.  If `stack' is NULL
879  *    reverts back to normal allocating routine.
880  *
881  ***/
882
883 static inline
884 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
885 {
886   SilcBuffer sb;
887
888   if (!stack)
889     return silc_buffer_alloc(len);
890
891   /* Allocate new SilcBuffer */
892   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
893   if (!sb)
894     return NULL;
895
896   /* Allocate the actual data area */
897   sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
898   if (!sb->head)
899     return NULL;
900
901   /* Set pointers to the new buffer */
902   sb->data = sb->head;
903   sb->tail = sb->head;
904   sb->end = sb->head + len;
905
906   return sb;
907 }
908
909 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
910  *
911  * SYNOPSIS
912  *
913  *    static inline
914  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
915  *
916  * DESCRIPTION
917  *
918  *    Allocates `len' bytes size buffer and moves the tail area automatically
919  *    `len' bytes so that the buffer is ready to use without calling the
920  *    silc_buffer_pull_tail.
921  *
922  *    This routine use SilcStack are memory source.  If `stack' is NULL
923  *    reverts back to normal allocating routine.
924  *
925  ***/
926
927 static inline
928 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
929 {
930   SilcBuffer sb = silc_buffer_salloc(stack, len);
931   if (!sb)
932     return NULL;
933   silc_buffer_pull_tail(sb, len);
934   return sb;
935 }
936
937 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
938  *
939  * SYNOPSIS
940  *
941  *    static inline
942  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
943  *                                    SilcBuffer sb, SilcUInt32 newsize);
944  *
945  * DESCRIPTION
946  *
947  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
948  *    is exact clone of the old one except that there is now more space
949  *    at the end of buffer.
950  *
951  *    This routine use SilcStack are memory source.  If `stack' is NULL
952  *    reverts back to normal allocating routine.
953  *
954  ***/
955
956 static inline
957 SilcBuffer silc_buffer_srealloc(SilcStack stack,
958                                 SilcBuffer sb, SilcUInt32 newsize)
959 {
960   SilcUInt32 hlen, dlen;
961   unsigned char *h;
962
963   if (!stack)
964     return silc_buffer_realloc(sb, newsize);
965
966   if (!sb)
967     return silc_buffer_salloc(stack, newsize);
968
969   if (newsize <= silc_buffer_truelen(sb))
970     return sb;
971
972   hlen = silc_buffer_headlen(sb);
973   dlen = silc_buffer_len(sb);
974   h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
975                                         sb->head, newsize);
976   if (!h) {
977     /* Do slow and stack wasting realloc.  The old sb->head is lost and
978        is freed eventually. */
979     h = silc_smalloc_ua(stack, newsize);
980     if (!h)
981       return NULL;
982     memcpy(h, sb->head, silc_buffer_truelen(sb));
983   }
984
985   sb->head = h;
986   sb->data = sb->head + hlen;
987   sb->tail = sb->data + dlen;
988   sb->end = sb->head + newsize;
989
990   return sb;
991 }
992
993 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
994  *
995  * SYNOPSIS
996  *
997  *    static inline
998  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
999  *                                         SilcBuffer sb, SilcUInt32 newsize);
1000  *
1001  * DESCRIPTION
1002  *
1003  *    Same as silc_buffer_srealloc but moves moves the tail area
1004  *    automatically so that the buffer is ready to use without calling the
1005  *    silc_buffer_pull_tail.
1006  *
1007  *    This routine use SilcStack are memory source.  If `stack' is NULL
1008  *    reverts back to normal allocating routine.
1009  *
1010  ***/
1011
1012 static inline
1013 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1014                                      SilcBuffer sb, SilcUInt32 newsize)
1015 {
1016   sb = silc_buffer_srealloc(stack, sb, newsize);
1017   if (!sb)
1018     return NULL;
1019   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1020   return sb;
1021 }
1022
1023 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1024  *
1025  * SYNOPSIS
1026  *
1027  *    static inline
1028  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1029  *
1030  * DESCRIPTION
1031  *
1032  *    Generates copy of a SilcBuffer. This copies everything inside the
1033  *    currently valid data area, nothing more. Use silc_buffer_clone to
1034  *    copy entire buffer.
1035  *
1036  *    This routine use SilcStack are memory source.  If `stack' is NULL
1037  *    reverts back to normal allocating routine.
1038  *
1039  ***/
1040
1041 static inline
1042 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1043 {
1044   SilcBuffer sb_new;
1045
1046   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1047   if (!sb_new)
1048     return NULL;
1049   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1050
1051   return sb_new;
1052 }
1053
1054 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1055  *
1056  * SYNOPSIS
1057  *
1058  *    static inline
1059  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1060  *
1061  * DESCRIPTION
1062  *
1063  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1064  *    everything from the source buffer. The result is exact clone of
1065  *    the original buffer.
1066  *
1067  *    This routine use SilcStack are memory source.  If `stack' is NULL
1068  *    reverts back to normal allocating routine.
1069  *
1070  ***/
1071
1072 static inline
1073 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1074 {
1075   SilcBuffer sb_new;
1076
1077   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1078   if (!sb_new)
1079     return NULL;
1080   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1081   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1082   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1083
1084   return sb_new;
1085 }
1086
1087 #endif /* SILCBUFFER_H */