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