Added silc_buffer_strchr.
[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
530 #ifdef SILC_DIST_INPLACE
531   SILC_ASSERT(len <= silc_buffer_len(sb));
532 #endif /* SILC_DIST_INPLACE */
533   if (silc_unlikely(len > silc_buffer_len(sb)))
534     return NULL;
535
536   sb->data += len;
537   return old_data;
538 }
539
540 /****f* silcutil/SilcBufferAPI/silc_buffer_push
541  *
542  * SYNOPSIS
543  *
544  *    static inline
545  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
546  *
547  * DESCRIPTION
548  *
549  *    Pushes current data area towards beginning. Length of the currently
550  *    valid data area is also incremented. Returns a pointer to the
551  *    data area before pushing. Returns NULL on error.
552  *
553  * EXAMPLE
554  *
555  *    ---------------------------------
556  *    | head     | data    | tail     |
557  *    ---------------------------------
558  *               ^
559  *               Pushes the start of the data area.
560  *
561  *    ---------------------------------
562  *    | head  | data       | tail     |
563  *    ---------------------------------
564  *               ^
565  *
566  *    silc_buffer_push(sb, 20);
567  *
568  ***/
569
570 static inline
571 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
572 {
573   unsigned char *old_data = sb->data;
574
575 #ifdef SILC_DIST_INPLACE
576   SILC_ASSERT((sb->data - len) >= sb->head);
577 #endif /* SILC_DIST_INPLACE */
578   if (silc_unlikely((sb->data - len) < sb->head))
579     return NULL;
580
581   sb->data -= len;
582   return old_data;
583 }
584
585 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
586  *
587  * SYNOPSIS
588  *
589  *    static inline
590  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
591  *
592  * DESCRIPTION
593  *
594  *    Pulls current tail section towards end. Length of the current valid
595  *    data area is also incremented. Returns a pointer to the data area
596  *    before pulling. Returns NULL on error.
597  *
598  * EXAMPLE
599  *
600  *    ---------------------------------
601  *    | head  | data       | tail     |
602  *    ---------------------------------
603  *                         ^
604  *                         Pulls the start of the tail section.
605  *
606  *    ---------------------------------
607  *    | head  | data           | tail |
608  *    ---------------------------------
609  *                         ^
610  *
611  *    silc_buffer_pull_tail(sb, 23);
612  *
613  ***/
614
615 static inline
616 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
617 {
618   unsigned char *old_tail = sb->tail;
619
620 #ifdef SILC_DIST_INPLACE
621   SILC_ASSERT(len <= silc_buffer_taillen(sb));
622 #endif /* SILC_DIST_INPLACE */
623   if (silc_unlikely(len > silc_buffer_taillen(sb)))
624     return NULL;
625
626   sb->tail += len;
627   return old_tail;
628 }
629
630 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
631  *
632  * SYNOPSIS
633  *
634  *    static inline
635  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
636  *
637  * DESCRIPTION
638  *
639  *    Pushes current tail section towards beginning. Length of the current
640  *    valid data area is also decremented. Returns a pointer to the
641  *    tail section before pushing. Returns NULL on error.
642  *
643  * EXAMPLE
644  *
645  *    ---------------------------------
646  *    | head  | data           | tail |
647  *    ---------------------------------
648  *                             ^
649  *                             Pushes the start of the tail section.
650  *
651  *    ---------------------------------
652  *    | head  | data       | tail     |
653  *    ---------------------------------
654  *                             ^
655  *
656  *    silc_buffer_push_tail(sb, 23);
657  *
658  ***/
659
660 static inline
661 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
662 {
663   unsigned char *old_tail = sb->tail;
664
665 #ifdef SILC_DIST_INPLACE
666   SILC_ASSERT((sb->tail - len) >= sb->data);
667 #endif /* SILC_DIST_INPLACE */
668   if (silc_unlikely((sb->tail - len) < sb->data))
669     return NULL;
670
671   sb->tail -= len;
672   return old_tail;
673 }
674
675 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
676  *
677  * SYNOPSIS
678  *
679  *    static inline
680  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
681  *                                        const unsigned char *data,
682  *                                        SilcUInt32 len);
683  *
684  * DESCRIPTION
685  *
686  *    Puts data at the head of the buffer. Returns pointer to the copied
687  *    data area. Returns NULL on error.
688  *
689  * EXAMPLE
690  *
691  *    ---------------------------------
692  *    | head  | data       | tail     |
693  *    ---------------------------------
694  *    ^
695  *    Puts data to the head section.
696  *
697  *    silc_buffer_put_head(sb, data, data_len);
698  *
699  ***/
700
701 static inline
702 unsigned char *silc_buffer_put_head(SilcBuffer sb,
703                                     const unsigned char *data,
704                                     SilcUInt32 len)
705 {
706 #ifdef SILC_DIST_INPLACE
707   SILC_ASSERT(len <= silc_buffer_headlen(sb));
708 #endif /* SILC_DIST_INPLACE */
709   if (silc_unlikely(len > silc_buffer_headlen(sb)))
710     return NULL;
711
712   return (unsigned char *)memcpy(sb->head, data, len);
713 }
714
715 /****f* silcutil/SilcBufferAPI/silc_buffer_put
716  *
717  * SYNOPSIS
718  *
719  *    static inline
720  *    unsigned char *silc_buffer_put(SilcBuffer sb,
721  *                                   const unsigned char *data,
722  *                                   SilcUInt32 len);
723  *
724  * DESCRIPTION
725  *
726  *    Puts data at the start of the valid data area. Returns a pointer
727  *    to the copied data area.  Returns NULL on error.
728  *
729  * EXAMPLE
730  *
731  *    ---------------------------------
732  *    | head  | data       | tail     |
733  *    ---------------------------------
734  *            ^
735  *            Puts data to the data section.
736  *
737  *    silc_buffer_put(sb, data, data_len);
738  *
739  ***/
740
741 static inline
742 unsigned char *silc_buffer_put(SilcBuffer sb,
743                                const unsigned char *data,
744                                SilcUInt32 len)
745 {
746 #ifdef SILC_DIST_INPLACE
747   SILC_ASSERT(len <= silc_buffer_len(sb));
748 #endif /* SILC_DIST_INPLACE */
749   if (silc_unlikely(len > silc_buffer_len(sb)))
750     return NULL;
751
752   return (unsigned char *)memcpy(sb->data, data, len);
753 }
754
755 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
756  *
757  * SYNOPSIS
758  *
759  *    static inline
760  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
761  *                                        const unsigned char *data,
762  *                                        SilcUInt32 len);
763  *
764  * DESCRIPTION
765  *
766  *    Puts data at the tail of the buffer. Returns pointer to the copied
767  *    data area.  Returns NULL on error.
768  *
769  * EXAMPLE
770  *
771  *    ---------------------------------
772  *    | head  | data           | tail |
773  *    ---------------------------------
774  *                             ^
775  *                             Puts data to the tail section.
776  *
777  *    silc_buffer_put_tail(sb, data, data_len);
778  *
779  ***/
780
781 static inline
782 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
783                                     const unsigned char *data,
784                                     SilcUInt32 len)
785 {
786 #ifdef SILC_DIST_INPLACE
787   SILC_ASSERT(len <= silc_buffer_taillen(sb));
788 #endif /* SILC_DIST_INPLACE */
789   if (silc_unlikely(len > silc_buffer_taillen(sb)))
790     return NULL;
791
792   return (unsigned char *)memcpy(sb->tail, data, len);
793 }
794
795 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
796  *
797  * SYNOPSIS
798  *
799  *    static inline
800  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
801  *
802  * DESCRIPTION
803  *
804  *    Allocates `len' bytes size buffer and moves the tail area automatically
805  *    `len' bytes so that the buffer is ready to use without calling the
806  *    silc_buffer_pull_tail.  Returns NULL on error.
807  *
808  ***/
809
810 static inline
811 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
812 {
813   SilcBuffer sb = silc_buffer_alloc(len);
814   if (silc_unlikely(!sb))
815     return NULL;
816   silc_buffer_pull_tail(sb, len);
817   return sb;
818 }
819
820 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
821  *
822  * SYNOPSIS
823  *
824  *    static inline
825  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
826  *
827  * DESCRIPTION
828  *
829  *    Allocates `len' bytes size buffer and moves the tail area automatically
830  *    `len' bytes so that the buffer is ready to use without calling the
831  *    silc_buffer_pull_tail.
832  *
833  *    This routine use SilcStack are memory source.  If `stack' is NULL
834  *    reverts back to normal allocating routine.
835  *
836  *    Note that this call consumes the `stack'.  The caller should push the
837  *    stack before calling the function and pop it later.
838  *
839  ***/
840
841 static inline
842 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
843 {
844   SilcBuffer sb = silc_buffer_salloc(stack, len);
845   if (silc_unlikely(!sb))
846     return NULL;
847   silc_buffer_pull_tail(sb, len);
848   return sb;
849 }
850
851 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
852  *
853  * SYNOPSIS
854  *
855  *    static inline
856  *    void silc_buffer_reset(SilcBuffer sb);
857  *
858  * DESCRIPTION
859  *
860  *    Resets the buffer to the state as if it was just allocated by
861  *    silc_buffer_alloc.  This does not clear the data area.  Use
862  *    silc_buffer_clear if you also want to clear the data area.
863  *
864  ***/
865
866 static inline
867 void silc_buffer_reset(SilcBuffer sb)
868 {
869   sb->data = sb->tail = sb->head;
870 }
871
872 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
873  *
874  * SYNOPSIS
875  *
876  *    static inline
877  *    void silc_buffer_clear(SilcBuffer sb);
878  *
879  * DESCRIPTION
880  *
881  *    Clears and initialiazes the buffer to the state as if it was just
882  *    allocated by silc_buffer_alloc.
883  *
884  ***/
885
886 static inline
887 void silc_buffer_clear(SilcBuffer sb)
888 {
889   memset(sb->head, 0, silc_buffer_truelen(sb));
890   silc_buffer_reset(sb);
891 }
892
893 /****f* silcutil/SilcBufferAPI/silc_buffer_start
894  *
895  * SYNOPSIS
896  *
897  *    static inline
898  *    void silc_buffer_start(SilcBuffer sb);
899  *
900  * DESCRIPTION
901  *
902  *    Moves the data area at the start of the buffer.  The tail area remains
903  *    as is.
904  *
905  ***/
906
907 static inline
908 void silc_buffer_start(SilcBuffer sb)
909 {
910   sb->data = sb->head;
911 }
912
913 /****f* silcutil/SilcBufferAPI/silc_buffer_end
914  *
915  * SYNOPSIS
916  *
917  *    static inline
918  *    void silc_buffer_end(SilcBuffer sb);
919  *
920  * DESCRIPTION
921  *
922  *    Moves the end of the data area to the end of the buffer.  The start
923  *    of the data area remains same.  If the start of data area is at the
924  *    start of the buffer, after this function returns the buffer's data
925  *    area length is the length of the entire buffer.
926  *
927  ***/
928
929 static inline
930 void silc_buffer_end(SilcBuffer sb)
931 {
932   sb->tail = sb->end;
933 }
934
935 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
936  *
937  * SYNOPSIS
938  *
939  *    static inline
940  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
941  *
942  * DESCRIPTION
943  *
944  *    Generates copy of a SilcBuffer. This copies everything inside the
945  *    currently valid data area, nothing more. Use silc_buffer_clone to
946  *    copy entire buffer.  Returns NULL on error.
947  *
948  ***/
949
950 static inline
951 SilcBuffer silc_buffer_copy(SilcBuffer sb)
952 {
953   SilcBuffer sb_new;
954
955   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
956   if (silc_unlikely(!sb_new))
957     return NULL;
958   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
959
960   return sb_new;
961 }
962
963 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
964  *
965  * SYNOPSIS
966  *
967  *    static inline
968  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
969  *
970  * DESCRIPTION
971  *
972  *    Generates copy of a SilcBuffer. This copies everything inside the
973  *    currently valid data area, nothing more. Use silc_buffer_clone to
974  *    copy entire buffer.
975  *
976  *    This routine use SilcStack are memory source.  If `stack' is NULL
977  *    reverts back to normal allocating routine.
978  *
979  *    Note that this call consumes the `stack'.  The caller should push the
980  *    stack before calling the function and pop it later.
981  *
982  ***/
983
984 static inline
985 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
986 {
987   SilcBuffer sb_new;
988
989   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
990   if (silc_unlikely(!sb_new))
991     return NULL;
992   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
993
994   return sb_new;
995 }
996
997 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
998  *
999  * SYNOPSIS
1000  *
1001  *    static inline
1002  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
1003  *
1004  * DESCRIPTION
1005  *
1006  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1007  *    everything from the source buffer. The result is exact clone of
1008  *    the original buffer.  Returns NULL on error.
1009  *
1010  ***/
1011
1012 static inline
1013 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1014 {
1015   SilcBuffer sb_new;
1016
1017   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1018   if (silc_unlikely(!sb_new))
1019     return NULL;
1020   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1021   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1022   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1023
1024   return sb_new;
1025 }
1026
1027 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1028  *
1029  * SYNOPSIS
1030  *
1031  *    static inline
1032  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1033  *
1034  * DESCRIPTION
1035  *
1036  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1037  *    everything from the source buffer. The result is exact clone of
1038  *    the original buffer.
1039  *
1040  *    This routine use SilcStack are memory source.  If `stack' is NULL
1041  *    reverts back to normal allocating routine.
1042  *
1043  *    Note that this call consumes the `stack'.  The caller should push the
1044  *    stack before calling the function and pop it later.
1045  *
1046  ***/
1047
1048 static inline
1049 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1050 {
1051   SilcBuffer sb_new;
1052
1053   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1054   if (silc_unlikely(!sb_new))
1055     return NULL;
1056   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1057   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1058   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1059
1060   return sb_new;
1061 }
1062
1063 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1064  *
1065  * SYNOPSIS
1066  *
1067  *    static inline
1068  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1069  *
1070  * DESCRIPTION
1071  *
1072  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1073  *    is exact clone of the old one except that there is now more space
1074  *    at the end of buffer.  This always returns the same `sb' unless `sb'
1075  *    was NULL. Returns NULL on error.
1076  *
1077  ***/
1078
1079 static inline
1080 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1081 {
1082   SilcUInt32 hlen, dlen;
1083   unsigned char *h;
1084
1085   if (!sb)
1086     return silc_buffer_alloc(newsize);
1087
1088   if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1089     return sb;
1090
1091   hlen = silc_buffer_headlen(sb);
1092   dlen = silc_buffer_len(sb);
1093   h = (unsigned char *)silc_realloc(sb->head, newsize);
1094   if (silc_unlikely(!h))
1095     return NULL;
1096   sb->head = h;
1097   sb->data = sb->head + hlen;
1098   sb->tail = sb->data + dlen;
1099   sb->end = sb->head + newsize;
1100
1101   return sb;
1102 }
1103
1104 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1105  *
1106  * SYNOPSIS
1107  *
1108  *    static inline
1109  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
1110  *                                    SilcBuffer sb, SilcUInt32 newsize);
1111  *
1112  * DESCRIPTION
1113  *
1114  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1115  *    is exact clone of the old one except that there is now more space
1116  *    at the end of buffer.
1117  *
1118  *    This routine use SilcStack are memory source.  If `stack' is NULL
1119  *    reverts back to normal allocating routine.
1120  *
1121  *    Note that this call consumes the `stack'.  The caller should push the
1122  *    stack before calling the function and pop it later.
1123  *
1124  ***/
1125
1126 static inline
1127 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1128                                 SilcBuffer sb, SilcUInt32 newsize)
1129 {
1130   SilcUInt32 hlen, dlen;
1131   unsigned char *h;
1132
1133   if (!stack)
1134     return silc_buffer_realloc(sb, newsize);
1135
1136   if (!sb)
1137     return silc_buffer_salloc(stack, newsize);
1138
1139   if (newsize <= silc_buffer_truelen(sb))
1140     return sb;
1141
1142   hlen = silc_buffer_headlen(sb);
1143   dlen = silc_buffer_len(sb);
1144   h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1145                                      sb->head, newsize);
1146   if (!h) {
1147     /* Do slow and stack wasting realloc.  The old sb->head is lost and
1148        is freed eventually. */
1149     h = (unsigned char *)silc_smalloc(stack, newsize);
1150     if (silc_unlikely(!h))
1151       return NULL;
1152     memcpy(h, sb->head, silc_buffer_truelen(sb));
1153   }
1154
1155   sb->head = h;
1156   sb->data = sb->head + hlen;
1157   sb->tail = sb->data + dlen;
1158   sb->end = sb->head + newsize;
1159
1160   return sb;
1161 }
1162
1163 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1164  *
1165  * SYNOPSIS
1166  *
1167  *    static inline
1168  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1169  *
1170  * DESCRIPTION
1171  *
1172  *    Same as silc_buffer_realloc but moves moves the tail area
1173  *    automatically so that the buffer is ready to use without calling the
1174  *    silc_buffer_pull_tail.  Returns NULL on error.
1175  *
1176  ***/
1177
1178 static inline
1179 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1180 {
1181   sb = silc_buffer_realloc(sb, newsize);
1182   if (silc_unlikely(!sb))
1183     return NULL;
1184   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1185   return sb;
1186 }
1187
1188 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1189  *
1190  * SYNOPSIS
1191  *
1192  *    static inline
1193  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1194  *                                         SilcBuffer sb, SilcUInt32 newsize);
1195  *
1196  * DESCRIPTION
1197  *
1198  *    Same as silc_buffer_srealloc but moves moves the tail area
1199  *    automatically so that the buffer is ready to use without calling the
1200  *    silc_buffer_pull_tail.
1201  *
1202  *    This routine use SilcStack are memory source.  If `stack' is NULL
1203  *    reverts back to normal allocating routine.
1204  *
1205  *    Note that this call consumes the `stack'.  The caller should push the
1206  *    stack before calling the function and pop it later.
1207  *
1208  ***/
1209
1210 static inline
1211 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1212                                      SilcBuffer sb, SilcUInt32 newsize)
1213 {
1214   sb = silc_buffer_srealloc(stack, sb, newsize);
1215   if (silc_unlikely(!sb))
1216     return NULL;
1217   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1218   return sb;
1219 }
1220
1221 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1222  *
1223  * SYNOPSIS
1224  *
1225  *    static inline
1226  *    SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1227  *
1228  * DESCRIPTION
1229  *
1230  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1231  *    must space in the data area and in the tail area.  Moves the tail
1232  *    area automatically after enlarging so that the current data area
1233  *    is at least the size of `size'.  If there is more space than `size'
1234  *    in the data area this does not do anything.  If there is enough
1235  *    space in the tail area this merely moves the tail area to reveal
1236  *    the extra space.  Returns FALSE on error.
1237  *
1238  ***/
1239
1240 static inline
1241 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1242 {
1243   if (size > silc_buffer_len(sb)) {
1244     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1245       if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1246                                              (size - silc_buffer_taillen(sb) -
1247                                               silc_buffer_len(sb)))))
1248         return FALSE;
1249     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1250   }
1251   return TRUE;
1252 }
1253
1254 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1255  *
1256  * SYNOPSIS
1257  *
1258  *    static inline
1259  *    SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1260  *                                    SilcUInt32 size);
1261  *
1262  * DESCRIPTION
1263  *
1264  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1265  *    must space in the data area and in the tail area.  Moves the tail
1266  *    area automatically after enlarging so that the current data area
1267  *    is at least the size of `size'.  If there is more space than `size'
1268  *    in the data area this does not do anything.  If there is enough
1269  *    space in the tail area this merely moves the tail area to reveal
1270  *    the extra space.  Returns FALSE on error.
1271  *
1272  *    This routine use SilcStack are memory source.  If `stack' is NULL
1273  *    reverts back to normal allocating routine.
1274  *
1275  *    Note that this call consumes the `stack'.  The caller should push the
1276  *    stack before calling the function and pop it later.
1277  *
1278  ***/
1279
1280 static inline
1281 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1282 {
1283   if (size > silc_buffer_len(sb)) {
1284     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1285       if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1286                                               silc_buffer_truelen(sb) +
1287                                               (size - silc_buffer_taillen(sb) -
1288                                                silc_buffer_len(sb)))))
1289         return FALSE;
1290     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1291   }
1292   return TRUE;
1293 }
1294
1295 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1296  *
1297  * SYNOPSIS
1298  *
1299  *    static inline
1300  *    unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1301  *
1302  * DESCRIPTION
1303  *
1304  *    Returns pointer to the occurence of the character `c' in the buffer
1305  *    `sb'.  If the `first' is TRUE this finds the first occurene of `c',
1306  *    if it is FALSE this finds the last occurence of `c'.  If the character
1307  *    is found the `sb' data area is moved to that location and its pointer
1308  *    is returned.  The silc_buffer_data call will return the same pointer.
1309  *    Returns NULL if such character could not be located and the buffer
1310  *    remains unmodified.
1311  *
1312  *    This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1313  *    except it works with SilcBuffer.
1314  *
1315  * NOTES
1316  *
1317  *    This searches only the data area of the buffer.  Head and tail area
1318  *    are not searched.
1319  *
1320  *    The `sb' data need not be NULL terminated.
1321  *
1322  ***/
1323
1324 static inline
1325 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1326 {
1327   int i;
1328
1329   if (first) {
1330     for (i = 0; i < silc_buffer_len(sb); i++) {
1331       if (sb->data[i] == (unsigned char)c) {
1332         sb->data = &sb->data[i];
1333         return sb->data;
1334       }
1335     }
1336   } else {
1337     for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1338       if (sb->data[i] == (unsigned char)c) {
1339         sb->data = &sb->data[i];
1340         return sb->data;
1341       }
1342     }
1343   }
1344
1345   return NULL;
1346 }
1347
1348 #endif /* SILCBUFFER_H */