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