1 /*
2 * Copyright (c) 2010-2012, Anthony Minessale II
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of the original author; nor the names of any contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35 #include "esl_buffer.h"
36
37 static unsigned buffer_id = 0;
38
39 struct esl_buffer {
40 unsigned char *data;
41 unsigned char *head;
42 esl_size_t used;
43 esl_size_t actually_used;
44 esl_size_t datalen;
45 esl_size_t max_len;
46 esl_size_t blocksize;
47 unsigned id;
48 int loops;
49 };
50
51
esl_buffer_create(esl_buffer_t ** buffer,esl_size_t blocksize,esl_size_t start_len,esl_size_t max_len)52 ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len)
53 {
54 esl_buffer_t *new_buffer;
55
56 new_buffer = malloc(sizeof(*new_buffer));
57
58 if (new_buffer) {
59 memset(new_buffer, 0, sizeof(*new_buffer));
60
61 if (!start_len) {
62 start_len = 250;
63 }
64
65 if (!blocksize) {
66 blocksize = start_len;
67 }
68
69 new_buffer->data = malloc(start_len);
70 if (!new_buffer->data) {
71 free(new_buffer);
72 return ESL_FAIL;
73 }
74 memset(new_buffer->data, 0, start_len);
75
76 new_buffer->max_len = max_len;
77 new_buffer->datalen = start_len;
78 new_buffer->id = buffer_id++;
79 new_buffer->blocksize = blocksize;
80 new_buffer->head = new_buffer->data;
81
82 *buffer = new_buffer;
83 return ESL_SUCCESS;
84 }
85
86 return ESL_FAIL;
87 }
88
esl_buffer_len(esl_buffer_t * buffer)89 ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer)
90 {
91
92 esl_assert(buffer != NULL);
93
94 return buffer->datalen;
95
96 }
97
98
esl_buffer_freespace(esl_buffer_t * buffer)99 ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer)
100 {
101 esl_assert(buffer != NULL);
102
103 if (buffer->max_len) {
104 return (esl_size_t) (buffer->max_len - buffer->used);
105 }
106 return 1000000;
107
108 }
109
esl_buffer_inuse(esl_buffer_t * buffer)110 ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer)
111 {
112 esl_assert(buffer != NULL);
113
114 return buffer->used;
115 }
116
esl_buffer_seek(esl_buffer_t * buffer,esl_size_t datalen)117 ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen)
118 {
119 esl_size_t reading = 0;
120
121 esl_assert(buffer != NULL);
122
123 if (buffer->used < 1) {
124 buffer->used = 0;
125 return 0;
126 } else if (buffer->used >= datalen) {
127 reading = datalen;
128 } else {
129 reading = buffer->used;
130 }
131
132 buffer->used = buffer->actually_used - reading;
133 buffer->head = buffer->data + reading;
134
135 return reading;
136 }
137
esl_buffer_toss(esl_buffer_t * buffer,esl_size_t datalen)138 ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen)
139 {
140 esl_size_t reading = 0;
141
142 esl_assert(buffer != NULL);
143
144 if (buffer->used < 1) {
145 buffer->used = 0;
146 return 0;
147 } else if (buffer->used >= datalen) {
148 reading = datalen;
149 } else {
150 reading = buffer->used;
151 }
152
153 buffer->used -= reading;
154 buffer->head += reading;
155
156 return buffer->used;
157 }
158
esl_buffer_set_loops(esl_buffer_t * buffer,int loops)159 ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int loops)
160 {
161 buffer->loops = loops;
162 }
163
esl_buffer_read_loop(esl_buffer_t * buffer,void * data,esl_size_t datalen)164 ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen)
165 {
166 esl_size_t len;
167 if ((len = esl_buffer_read(buffer, data, datalen)) < datalen) {
168 if (buffer->loops == 0) {
169 return len;
170 }
171 buffer->head = buffer->data;
172 buffer->used = buffer->actually_used;
173 len = esl_buffer_read(buffer, (char*)data + len, datalen - len);
174 buffer->loops--;
175 }
176 return len;
177 }
178
esl_buffer_read(esl_buffer_t * buffer,void * data,esl_size_t datalen)179 ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen)
180 {
181 esl_size_t reading = 0;
182
183 esl_assert(buffer != NULL);
184 esl_assert(data != NULL);
185 esl_assert(buffer->head != NULL);
186
187
188 if (buffer->used < 1) {
189 buffer->used = 0;
190 return 0;
191 } else if (buffer->used >= datalen) {
192 reading = datalen;
193 } else {
194 reading = buffer->used;
195 }
196
197 memcpy(data, buffer->head, reading);
198 buffer->used -= reading;
199 buffer->head += reading;
200
201 /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
202 return reading;
203 }
204
205
esl_buffer_packet_count(esl_buffer_t * buffer)206 ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer)
207 {
208 char *pe, *p, *e, *head;
209 esl_size_t x = 0;
210
211 esl_assert(buffer != NULL);
212
213 head = (char *) buffer->head;
214
215 e = (head + buffer->used);
216
217 for (p = head; p && *p && p < e; p++) {
218 if (*p == '\n') {
219 pe = p+1;
220 if (*pe == '\r') pe++;
221 if (pe <= e && *pe == '\n') {
222 p = pe++;
223 x++;
224 }
225 }
226 }
227
228 return x;
229 }
230
esl_buffer_read_packet(esl_buffer_t * buffer,void * data,esl_size_t maxlen)231 ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen)
232 {
233 char *pe, *p, *e, *head;
234 esl_size_t datalen = 0;
235
236 esl_assert(buffer != NULL);
237 esl_assert(data != NULL);
238
239 head = (char *) buffer->head;
240
241 e = (head + buffer->used);
242
243 for (p = head; p && *p && p < e; p++) {
244 if (*p == '\n') {
245 pe = p+1;
246 if (*pe == '\r') pe++;
247 if (pe <= e && *pe == '\n') {
248 pe++;
249 datalen = pe - head;
250 if (datalen > maxlen) {
251 datalen = maxlen;
252 }
253 break;
254 }
255 }
256 }
257
258 return esl_buffer_read(buffer, data, datalen);
259 }
260
esl_buffer_write(esl_buffer_t * buffer,const void * data,esl_size_t datalen)261 ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen)
262 {
263 esl_size_t freespace, actual_freespace;
264
265 esl_assert(buffer != NULL);
266 esl_assert(data != NULL);
267 esl_assert(buffer->data != NULL);
268
269 if (!datalen) {
270 return buffer->used;
271 }
272
273 actual_freespace = buffer->datalen - buffer->actually_used;
274 if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
275 memmove(buffer->data, buffer->head, buffer->used);
276 buffer->head = buffer->data;
277 buffer->actually_used = buffer->used;
278 }
279
280 freespace = buffer->datalen - buffer->used;
281
282 /*
283 if (buffer->data != buffer->head) {
284 memmove(buffer->data, buffer->head, buffer->used);
285 buffer->head = buffer->data;
286 }
287 */
288
289 if (freespace < datalen) {
290 esl_size_t new_size, new_block_size;
291 void *data1;
292
293 new_size = buffer->datalen + datalen;
294 new_block_size = buffer->datalen + buffer->blocksize;
295
296 if (new_block_size > new_size) {
297 new_size = new_block_size;
298 }
299 buffer->head = buffer->data;
300 data1 = realloc(buffer->data, new_size);
301 if (!data1) {
302 return 0;
303 }
304 buffer->data = data1;
305 buffer->head = buffer->data;
306 buffer->datalen = new_size;
307 }
308
309
310 freespace = buffer->datalen - buffer->used;
311
312 if (freespace < datalen) {
313 return 0;
314 } else {
315 memcpy(buffer->head + buffer->used, data, datalen);
316 buffer->used += datalen;
317 buffer->actually_used += datalen;
318 }
319 /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
320
321 return buffer->used;
322 }
323
esl_buffer_zero(esl_buffer_t * buffer)324 ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer)
325 {
326 esl_assert(buffer != NULL);
327 esl_assert(buffer->data != NULL);
328
329 buffer->used = 0;
330 buffer->actually_used = 0;
331 buffer->head = buffer->data;
332 }
333
esl_buffer_zwrite(esl_buffer_t * buffer,const void * data,esl_size_t datalen)334 ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen)
335 {
336 esl_size_t w;
337
338 if (!(w = esl_buffer_write(buffer, data, datalen))) {
339 esl_buffer_zero(buffer);
340 return esl_buffer_write(buffer, data, datalen);
341 }
342
343 return w;
344 }
345
esl_buffer_destroy(esl_buffer_t ** buffer)346 ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer)
347 {
348 if (*buffer) {
349 free((*buffer)->data);
350 (*buffer)->data = NULL;
351 free(*buffer);
352 }
353
354 *buffer = NULL;
355 }
356
357 /* For Emacs:
358 * Local Variables:
359 * mode:c
360 * indent-tabs-mode:t
361 * tab-width:4
362 * c-basic-offset:4
363 * End:
364 * For VIM:
365 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
366 */
367