1 /*
2  * Copyright (c) 2007-2014, 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 #include "private/ftdm_core.h"
35 #include "ftdm_buffer.h"
36 
37 static unsigned buffer_id = 0;
38 
39 struct ftdm_buffer {
40 	unsigned char *data;
41 	unsigned char *head;
42 	ftdm_size_t used;
43 	ftdm_size_t actually_used;
44 	ftdm_size_t datalen;
45 	ftdm_size_t max_len;
46 	ftdm_size_t blocksize;
47 	unsigned id;
48 	int loops;
49 };
50 
51 
ftdm_buffer_create(ftdm_buffer_t ** buffer,ftdm_size_t blocksize,ftdm_size_t start_len,ftdm_size_t max_len)52 FT_DECLARE(ftdm_status_t) ftdm_buffer_create(ftdm_buffer_t **buffer, ftdm_size_t blocksize, ftdm_size_t start_len, ftdm_size_t max_len)
53 {
54 	ftdm_buffer_t *new_buffer;
55 
56 	new_buffer = ftdm_malloc(sizeof(*new_buffer));
57 	if (new_buffer) {
58 		memset(new_buffer, 0, sizeof(*new_buffer));
59 
60 		if (!start_len) {
61 			start_len = 250;
62 		}
63 
64 		if (!blocksize) {
65 			blocksize = start_len;
66 		}
67 
68 		new_buffer->data = ftdm_malloc(start_len);
69 		if (!new_buffer->data) {
70 			ftdm_safe_free(new_buffer);
71 			return FTDM_MEMERR;
72 		}
73 		memset(new_buffer->data, 0, start_len);
74 
75 		new_buffer->max_len = max_len;
76 		new_buffer->datalen = start_len;
77 		new_buffer->id = buffer_id++;
78 		new_buffer->blocksize = blocksize;
79 		new_buffer->head = new_buffer->data;
80 
81 		*buffer = new_buffer;
82 		return FTDM_SUCCESS;
83 	}
84 
85 	return FTDM_MEMERR;
86 }
87 
ftdm_buffer_len(ftdm_buffer_t * buffer)88 FT_DECLARE(ftdm_size_t) ftdm_buffer_len(ftdm_buffer_t *buffer)
89 {
90 
91 	assert(buffer != NULL);
92 
93 	return buffer->datalen;
94 
95 }
96 
97 
ftdm_buffer_freespace(ftdm_buffer_t * buffer)98 FT_DECLARE(ftdm_size_t) ftdm_buffer_freespace(ftdm_buffer_t *buffer)
99 {
100 	assert(buffer != NULL);
101 
102 
103 	if (buffer->max_len) {
104 		return (ftdm_size_t) (buffer->max_len - buffer->used);
105 	}
106 	return 1000000;
107 
108 }
109 
ftdm_buffer_inuse(ftdm_buffer_t * buffer)110 FT_DECLARE(ftdm_size_t) ftdm_buffer_inuse(ftdm_buffer_t *buffer)
111 {
112 	assert(buffer != NULL);
113 
114 	return buffer->used;
115 }
116 
ftdm_buffer_seek(ftdm_buffer_t * buffer,ftdm_size_t datalen)117 FT_DECLARE(ftdm_size_t) ftdm_buffer_seek(ftdm_buffer_t *buffer, ftdm_size_t datalen)
118 {
119 	ftdm_size_t reading = 0;
120 
121 	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 
ftdm_buffer_toss(ftdm_buffer_t * buffer,ftdm_size_t datalen)138 FT_DECLARE(ftdm_size_t) ftdm_buffer_toss(ftdm_buffer_t *buffer, ftdm_size_t datalen)
139 {
140 	ftdm_size_t reading = 0;
141 
142 	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 
ftdm_buffer_set_loops(ftdm_buffer_t * buffer,int loops)159 FT_DECLARE(void) ftdm_buffer_set_loops(ftdm_buffer_t *buffer, int loops)
160 {
161 	buffer->loops = loops;
162 }
163 
ftdm_buffer_read_loop(ftdm_buffer_t * buffer,void * data,ftdm_size_t datalen)164 FT_DECLARE(ftdm_size_t) ftdm_buffer_read_loop(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
165 {
166 	ftdm_size_t len;
167 	if ((len = ftdm_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 = ftdm_buffer_read(buffer, (char*)data + len, datalen - len);
174 		buffer->loops--;
175 	}
176 	return len;
177 }
178 
ftdm_buffer_read(ftdm_buffer_t * buffer,void * data,ftdm_size_t datalen)179 FT_DECLARE(ftdm_size_t) ftdm_buffer_read(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
180 {
181 	ftdm_size_t reading = 0;
182 
183 	assert(buffer != NULL);
184 	assert(data != NULL);
185 
186 
187 	if (buffer->used < 1) {
188 		buffer->used = 0;
189 		return 0;
190 	} else if (buffer->used >= datalen) {
191 		reading = datalen;
192 	} else {
193 		reading = buffer->used;
194 	}
195 
196 	memcpy(data, buffer->head, reading);
197 	buffer->used -= reading;
198 	buffer->head += reading;
199 
200 	/* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
201 	return reading;
202 }
203 
ftdm_buffer_write(ftdm_buffer_t * buffer,const void * data,ftdm_size_t datalen)204 FT_DECLARE(ftdm_size_t) ftdm_buffer_write(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
205 {
206 	ftdm_size_t freespace, actual_freespace;
207 
208 	assert(buffer != NULL);
209 	assert(data != NULL);
210 	assert(buffer->data != NULL);
211 
212 	if (!datalen) {
213 		return buffer->used;
214 	}
215 
216 	actual_freespace = buffer->datalen - buffer->actually_used;
217 	if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
218 		memmove(buffer->data, buffer->head, buffer->used);
219 		buffer->head = buffer->data;
220 		buffer->actually_used = buffer->used;
221 	}
222 
223 	freespace = buffer->datalen - buffer->used;
224 
225 	/*
226 	  if (buffer->data != buffer->head) {
227 	  memmove(buffer->data, buffer->head, buffer->used);
228 	  buffer->head = buffer->data;
229 	  }
230 	*/
231 
232 	if (freespace < datalen) {
233 		ftdm_size_t new_size, new_block_size;
234 		void *data;
235 
236 		new_size = buffer->datalen + datalen;
237 		new_block_size = buffer->datalen + buffer->blocksize;
238 
239 		if (new_block_size > new_size) {
240 			new_size = new_block_size;
241 		}
242 		buffer->head = buffer->data;
243 		data = realloc(buffer->data, new_size);
244 		if (!data) {
245 			return 0;
246 		}
247 		buffer->data = data;
248 		buffer->head = buffer->data;
249 		buffer->datalen = new_size;
250 	}
251 
252 
253 	freespace = buffer->datalen - buffer->used;
254 
255 	if (freespace < datalen) {
256 		return 0;
257 	} else {
258 		memcpy(buffer->head + buffer->used, data, datalen);
259 		buffer->used += datalen;
260 		buffer->actually_used += datalen;
261 	}
262 	/* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
263 
264 	return buffer->used;
265 }
266 
ftdm_buffer_zero(ftdm_buffer_t * buffer)267 FT_DECLARE(void) ftdm_buffer_zero(ftdm_buffer_t *buffer)
268 {
269 	assert(buffer != NULL);
270 	assert(buffer->data != NULL);
271 
272 	buffer->used = 0;
273 	buffer->actually_used = 0;
274 	buffer->head = buffer->data;
275 }
276 
ftdm_buffer_zwrite(ftdm_buffer_t * buffer,const void * data,ftdm_size_t datalen)277 FT_DECLARE(ftdm_size_t) ftdm_buffer_zwrite(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
278 {
279 	ftdm_size_t w;
280 
281 	if (!(w = ftdm_buffer_write(buffer, data, datalen))) {
282 		ftdm_buffer_zero(buffer);
283 		return ftdm_buffer_write(buffer, data, datalen);
284 	}
285 
286 	return w;
287 }
288 
ftdm_buffer_destroy(ftdm_buffer_t ** buffer)289 FT_DECLARE(void) ftdm_buffer_destroy(ftdm_buffer_t **buffer)
290 {
291 	if (*buffer) {
292 		ftdm_safe_free((*buffer)->data);
293 		ftdm_safe_free(*buffer);
294 	}
295 
296 	*buffer = NULL;
297 }
298 
299 /* For Emacs:
300  * Local Variables:
301  * mode:c
302  * indent-tabs-mode:t
303  * tab-width:4
304  * c-basic-offset:4
305  * End:
306  * For VIM:
307  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
308  */
309