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