A LOT updates. Cannot separate. :)
[crypto.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1998 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20
21 #ifndef SILCBUFFER_H
22 #define SILCBUFFER_H
23
24 /* 
25    SILC Buffer object.
26
27    SilcBuffer is very simple and easy to use, yet you can do to the
28    buffer almost anything you want with its method functions. The buffer
29    is constructed of four different data sections that in whole creates
30    the allocated data area. Following short description of the fields
31    of the buffer.
32
33    unsigned int truelen;
34
35        True length of the buffer. This is set at the allocation of the
36        buffer and it should not be touched after that. This field should
37        be considered read-only.
38
39    unsigned int len;
40
41        Length of the currently valid data area. Tells the length of the 
42        data at the buffer. This is set to zero at the allocation of the
43        buffer and should not be updated by hand. Method functions of the
44        buffer automatically updates this field. However, it is not
45        read-only field and can be updated manually if necessary.
46
47    unsiged char *head;
48
49        Head of the allocated buffer. This is the start of the allocated
50        data area and remains as same throughout the lifetime of the buffer.
51        However, the end of the head area or the start of the currently valid
52        data area is variable.
53
54        --------------------------------
55        | head  | data         | tail  |
56        --------------------------------
57        ^       ^
58
59        Current head section in the buffer is sb->data - sb->head.
60
61    unsigned char *data;
62
63        Currently valid data area. This is the start of the currently valid
64        main data area. The data area is variable in all directions.
65
66        --------------------------------
67        | head  | data         | tail  |
68        --------------------------------
69                ^              ^
70  
71        Current valid data area in the buffer is sb->tail - sb->data.
72
73     unsigned char *tail;
74
75        Tail of the buffer. This is the end of the currently valid data area
76        or start of the tail area. The start of the tail area is variable.
77
78        --------------------------------
79        | head  | data         | tail  |
80        --------------------------------
81                               ^       ^
82
83        Current tail section in the buffer is sb->end - sb->tail.
84
85    unsigned char *end;
86
87        End of the allocated buffer. This is the end of the allocated data
88        area and remains as same throughout the lifetime of the buffer.
89        Usually this field is not needed except when checking the size
90        of the buffer.
91
92        --------------------------------
93        | head  | data         | tail  |
94        --------------------------------
95                                       ^
96
97        Length of the entire buffer is (ie. truelen) sb->end - sb->head.
98
99     Currently valid data area is considered to be the main data area in
100     the buffer. However, the entire buffer is of course valid data and can
101     be used as such. Usually head section of the buffer includes different
102     kind of headers or similiar. Data section includes the main data of
103     the buffer. Tail section can be seen as a reserve space of the data
104     section. Tail section can be pulled towards end thus the data section
105     becomes larger.
106
107     This buffer scheme is based on Linux kernel's Socket Buffer, the 
108     idea were taken directly from there and credits should go there.
109
110 */
111
112 typedef struct SilcBufferStruct {
113   unsigned int truelen;
114   unsigned int len;
115   unsigned char *head;
116   unsigned char *data;
117   unsigned char *tail;
118   unsigned char *end;
119 } SilcBufferObject;
120
121 typedef SilcBufferObject *SilcBuffer;
122
123 /* Macros */
124
125 /* Returns the true length of the buffer. This is used to pull
126    the buffer area to the end of the buffer. */
127 #define SILC_BUFFER_END(x) ((x)->end - (x)->head)
128
129 #ifndef SILC_DEBUG              /* When we are not doing debugging we use
130                                    optimized inline buffer functions. */
131 /* 
132  * Optimized buffer managing routines.  These are short inline
133  * functions.
134  */
135
136 extern inline
137 SilcBuffer silc_buffer_alloc(unsigned int len)
138 {
139   SilcBuffer sb;
140   unsigned char *data;
141
142   /* Allocate new SilcBuffer */
143   sb = silc_calloc(1, sizeof(*sb));
144
145   /* Allocate the actual data area */
146   data = silc_calloc(len, sizeof(*data));
147   memset(data, 0, len);
148
149   /* Set pointers to the new buffer */
150   sb->truelen = len;
151   sb->len = 0;
152   sb->head = data;
153   sb->data = data;
154   sb->tail = data;
155   sb->end = data + sb->truelen;
156
157   return sb;
158 }
159
160 /* Free's a SilcBuffer */
161
162 extern inline
163 void silc_buffer_free(SilcBuffer sb)
164 {
165   if (sb) {
166     memset(sb->head, 'F', sb->truelen);
167     silc_free(sb->head);
168     silc_free(sb);
169   }
170 }
171
172 /* Pulls current data area towards end. The length of the currently
173    valid data area is also decremented. Returns pointer to the data
174    area before pulling. 
175
176    Example:
177    ---------------------------------
178    | head  | data       | tail     |
179    ---------------------------------
180            ^
181            Pulls the start of the data area.
182
183    ---------------------------------
184    | head     | data    | tail     |
185    ---------------------------------
186            ^
187 */
188
189 extern inline 
190 unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
191 {
192   unsigned char *old_data = sb->data;
193
194   assert(len <= (sb->tail - sb->data));
195
196   sb->data += len;
197   sb->len -= len;
198
199   return old_data;
200 }
201
202 /* Pushes current data area towards beginning. Length of the currently
203    valid data area is also incremented. Returns a pointer to the 
204    data area before pushing. 
205
206    Example:
207    ---------------------------------
208    | head     | data    | tail     |
209    ---------------------------------
210               ^
211               Pushes the start of the data area.
212
213    ---------------------------------
214    | head  | data       | tail     |
215    ---------------------------------
216               ^
217 */
218
219 extern inline 
220 unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
221 {
222   unsigned char *old_data = sb->data;
223
224   assert((sb->data - len) >= sb->head);
225
226   sb->data -= len;
227   sb->len += len;
228
229   return old_data;
230 }
231
232 /* Pulls current tail section towards end. Length of the current valid
233    data area is also incremented. Returns a pointer to the data area 
234    before pulling.
235
236    Example:
237    ---------------------------------
238    | head  | data       | tail     |
239    ---------------------------------
240                         ^
241                         Pulls the start of the tail section.
242
243    ---------------------------------
244    | head  | data           | tail |
245    ---------------------------------
246                         ^
247 */
248
249 extern inline 
250 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
251 {
252   unsigned char *old_tail = sb->tail;
253
254   assert((sb->end - sb->tail) >= len);
255
256   sb->tail += len;
257   sb->len += len;
258
259   return old_tail;
260 }
261
262 /* Pushes current tail section towards beginning. Length of the current
263    valid data area is also decremented. Returns a pointer to the 
264    tail section before pushing. 
265
266    Example:
267    ---------------------------------
268    | head  | data           | tail |
269    ---------------------------------
270                             ^
271                             Pushes the start of the tail section.
272
273    ---------------------------------
274    | head  | data       | tail     |
275    ---------------------------------
276                             ^
277 */
278
279 extern inline
280 unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
281 {
282   unsigned char *old_tail = sb->tail;
283
284   assert((sb->tail - len) >= sb->data);
285
286   sb->tail -= len;
287   sb->len -= len;
288
289   return old_tail;
290 }
291
292 /* Puts data at the head of the buffer. Returns pointer to the copied
293    data area. 
294    
295    Example:
296    ---------------------------------
297    | head  | data       | tail     |
298    ---------------------------------
299    ^
300    Puts data to the head section. 
301 */
302
303 extern inline
304 unsigned char *silc_buffer_put_head(SilcBuffer sb, 
305                                     unsigned char *data,
306                                     unsigned int len)
307 {
308   assert((sb->data - sb->head) >= len);
309   return memcpy(sb->head, data, len);
310 }
311
312 /* Puts data at the start of the valid data area. Returns a pointer 
313    to the copied data area. 
314
315    Example:
316    ---------------------------------
317    | head  | data       | tail     |
318    ---------------------------------
319            ^
320            Puts data to the data section.
321 */
322
323 extern inline
324 unsigned char *silc_buffer_put(SilcBuffer sb, 
325                                unsigned char *data,
326                                unsigned int len)
327 {
328   assert((sb->tail - sb->data) >= len);
329   return memcpy(sb->data, data, len);
330 }
331
332 /* Puts data at the tail of the buffer. Returns pointer to the copied
333    data area. 
334
335    Example:
336    ---------------------------------
337    | head  | data           | tail |
338    ---------------------------------
339                             ^
340                             Puts data to the tail section.
341 */
342
343 extern inline
344 unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
345                                     unsigned char *data,
346                                     unsigned int len)
347 {
348   assert((sb->end - sb->tail) >= len);
349   return memcpy(sb->tail, data, len);
350 }
351
352 #endif /* !SILC_DEBUG */
353
354 /* Prototypes */
355 #ifdef SILC_DEBUG
356 SilcBuffer silc_buffer_alloc(unsigned int len);
357 void silc_buffer_free(SilcBuffer sb);
358 unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
359 unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
360 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
361 unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len);
362 unsigned char *silc_buffer_put_head(SilcBuffer sb, 
363                                     unsigned char *data,
364                                     unsigned int len);
365 unsigned char *silc_buffer_put(SilcBuffer sb, 
366                                unsigned char *data,
367                                unsigned int len);
368 unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
369                                     unsigned char *data,
370                                     unsigned int len);
371 #endif
372
373 #endif