1 /* $OpenBSD: bytebuf.c,v 1.8 2015/12/05 18:43:36 mmcc Exp $ */
2 /*-
3 * Copyright (c) 2009 Internet Initiative Japan Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 /**@file
28 * bytebuffer provides 'byte buffer' helper methods.
29 *
30 * Example:<pre>
31 * bytebuffer *buf = bytebuffer_create(BUFSIZ);
32 * int sz = read(STDIN_FILENO, bytebuffer_pointer(buf),
33 * bytebuffer_remaining(buf));
34 * if (sz > 0) {
35 * bytebuffer_put(buf, BYTEBUFFER_PUT_DIRECT, sz);
36 * bytebuffer_flip(buf);
37 *
38 * sz = write(STDOUT_FILENO, bytebuffer_pointer(buf),
39 * bytebuffer_remaining(buf));
40 * bytebuffer_compact(buf);
41 * }</pre>
42 *
43 * @author Yasuoka Masahiko
44 * $Id: bytebuf.c,v 1.8 2015/12/05 18:43:36 mmcc Exp $
45 */
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49
50 #ifdef BYTEBUF_DEBUG
51 #include <stdio.h>
52 #endif
53
54 #ifndef BYTEBUF_ASSERT
55 #ifdef BYTEBUF_DEBUG
56 #define BYTEBUF_ASSERT(cond) \
57 if (!(cond)) { \
58 fprintf(stderr, \
59 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
60 , __func__, __FILE__, __LINE__); \
61 abort(); \
62 }
63 #else
64 #define BYTEBUF_ASSERT(cond)
65 #endif
66 #endif
67
68 #include "bytebuf.h"
69
70 struct _bytebuffer {
71 /** current position */
72 int position;
73 /** current limit */
74 int limit;
75 /** position mark*/
76 int mark;
77 /** capacity of buffer */
78 size_t capacity;
79 /** allocated memory area */
80 void *data;
81 };
82
83 /**
84 * Create a bytebuffer and allocate memory area.
85 *
86 * @param capacity Capacity of allocating memory. If zero or
87 * negative value is specified, this function don't allocate
88 * memory.
89 */
90 bytebuffer *
bytebuffer_create(size_t capacity)91 bytebuffer_create(size_t capacity)
92 {
93 bytebuffer *_this = NULL;
94
95 if ((_this = calloc(1, sizeof(bytebuffer))) == NULL)
96 return NULL;
97
98 if (capacity > 0) {
99 if ((_this->data = calloc(1, capacity)) == NULL)
100 goto fail;
101 _this->capacity = capacity;
102 } else
103 _this->capacity = 0;
104
105 _this->limit = _this->capacity;
106 _this->mark = -1;
107 return _this;
108 fail:
109 free(_this);
110 return NULL;
111 }
112
113 /**
114 * Create a bytebuffer using existing memory area. This memory area will
115 * be freed by bytebuffer's destructor.
116 *
117 * @data the pointer to existing memory area
118 * @param capacity capacity of 'data'.
119 */
120 bytebuffer *
bytebuffer_wrap(void * data,size_t capacity)121 bytebuffer_wrap(void *data, size_t capacity)
122 {
123 bytebuffer *_this;
124
125 if ((_this = bytebuffer_create(0)) == NULL)
126 return NULL;
127
128 _this->data = data;
129 _this->capacity = capacity;
130 _this->mark = -1;
131
132 return _this;
133 }
134
135 /**
136 * Unwrap memory from bytebuffer.
137 *
138 * @param _this the bytebuffer object.
139 */
140 void *
bytebuffer_unwrap(bytebuffer * _this)141 bytebuffer_unwrap(bytebuffer *_this)
142 {
143 void *rval;
144
145 rval = _this->data;
146 _this->data = NULL;
147 _this->capacity = 0;
148 _this->position = 0;
149 _this->limit = 0;
150 _this->mark = -1;
151
152 return rval;
153 }
154
155 /**
156 * Change capacity of this buffer.
157 *
158 * @param _this the bytebuffer object.
159 * @param capacity new capacity.
160 */
161 int
bytebuffer_realloc(bytebuffer * _this,size_t capacity)162 bytebuffer_realloc(bytebuffer *_this, size_t capacity)
163 {
164 void *new_data;
165
166 BYTEBUF_ASSERT(_this->limit <= capacity);
167
168 if (_this->limit > capacity) {
169 errno = EINVAL;
170 return -1;
171 }
172
173 if ((new_data = realloc(_this->data, capacity)) == NULL)
174 return -1;
175
176 _this->data = new_data;
177 if (_this->limit == _this->capacity)
178 _this->limit = capacity;
179 _this->capacity = capacity;
180
181 return 0;
182 }
183
184 /**
185 * Compact this buffer. the bytes between position and limit are copied
186 * to the beginning of the buffer.
187 *
188 * @param _this the bytebuffer object.
189 */
190 void
bytebuffer_compact(bytebuffer * _this)191 bytebuffer_compact(bytebuffer *_this)
192 {
193 int len;
194
195 len = bytebuffer_remaining(_this);
196
197 if (len <= 0)
198 len = 0;
199 else if (_this->position != 0)
200 memmove(_this->data,
201 (const char *)_this->data + _this->position, (size_t)len);
202
203 _this->position = len;
204 _this->limit = _this->capacity;
205 _this->mark = -1;
206 }
207
208 static int bytebuffer_direct0;
209 /**
210 * BYTEBUFFER_PUT_DIRECT specifies the data that has been written already by
211 * direct access.
212 */
213 const void * BYTEBUFFER_PUT_DIRECT = &bytebuffer_direct0;
214
215 /**
216 * BYTEBUFFER_GET_DIRECT specifies the data that has been read already by
217 * direct access.
218 */
219 void * BYTEBUFFER_GET_DIRECT = &bytebuffer_direct0;
220
221 /**
222 * Write the given data to the buffer.
223 * If buffer is too small, this function returns <code>NULL</code> and
224 * <code>errno</code> is <code>ENOBUFS</code>
225 *
226 * @param _this the bytebuffer object.
227 * @param src source data. To specify the data that has been
228 * written already by direct access, use
229 * {@link ::BYTEBUFFER_PUT_DIRECT} for putting the data.
230 * NULL is the same {@link ::BYTEBUFFER_PUT_DIRECT}
231 * at least on this version, but using NULL is deprecated.
232 * @param srclen length of the source data.
233 * @see ::BYTEBUFFER_PUT_DIRECT
234 */
235 void *
bytebuffer_put(bytebuffer * _this,const void * src,size_t srclen)236 bytebuffer_put(bytebuffer *_this, const void *src, size_t srclen)
237 {
238 void *rval;
239
240 BYTEBUF_ASSERT(_this != NULL);
241 BYTEBUF_ASSERT(srclen > 0);
242
243 if (srclen > bytebuffer_remaining(_this)) {
244 errno = ENOBUFS;
245 return NULL;
246 }
247 rval = (char *)_this->data + _this->position;
248
249 if (src != NULL && src != BYTEBUFFER_PUT_DIRECT)
250 memcpy(rval, src, srclen);
251
252 _this->position += srclen;
253
254 return rval;
255 }
256
257 /*
258 * Transfer data from this buffer to the given destination memory.
259 * If the given buffer is too small, this function returns <code>NULL</code>
260 * and <code>errno</code> is <code>ENOBUFS</code>
261 *
262 * @param dst pointer of the destination memory. Specify NULL
263 * to skip transferring the data.
264 * @param dstlne memory size of the destination.
265 */
266 void *
bytebuffer_get(bytebuffer * _this,void * dst,size_t dstlen)267 bytebuffer_get(bytebuffer *_this, void *dst, size_t dstlen)
268 {
269 BYTEBUF_ASSERT(_this != NULL);
270 BYTEBUF_ASSERT(dstlen > 0);
271
272 if (dstlen > bytebuffer_remaining(_this)) {
273 errno = ENOBUFS;
274 return NULL;
275 }
276 if (dst != NULL && dst != BYTEBUFFER_GET_DIRECT)
277 memcpy(dst, (char *)_this->data + _this->position, dstlen);
278
279 _this->position += dstlen;
280
281 return dst;
282 }
283
284 /** Returns this buffer's position */
285 int
bytebuffer_position(bytebuffer * _this)286 bytebuffer_position(bytebuffer *_this)
287 {
288 BYTEBUF_ASSERT(_this != NULL);
289
290 return _this->position;
291 }
292
293 /** Returns this buffer's limit */
294 int
bytebuffer_limit(bytebuffer * _this)295 bytebuffer_limit(bytebuffer *_this)
296 {
297 BYTEBUF_ASSERT(_this != NULL);
298
299 return _this->limit;
300 }
301
302 /** Returns this buffer's capacity */
303 int
bytebuffer_capacity(bytebuffer * _this)304 bytebuffer_capacity(bytebuffer *_this)
305 {
306 BYTEBUF_ASSERT(_this != NULL);
307
308 return _this->capacity;
309 }
310
311 /** Returns a pointer to current position */
312 void *
bytebuffer_pointer(bytebuffer * _this)313 bytebuffer_pointer(bytebuffer *_this)
314 {
315 BYTEBUF_ASSERT(_this != NULL);
316
317 return (char *)_this->data + _this->position;
318 }
319
320 /** Returns the number of byte between current position and the limit*/
321 size_t
bytebuffer_remaining(bytebuffer * _this)322 bytebuffer_remaining(bytebuffer *_this)
323 {
324 BYTEBUF_ASSERT(_this != NULL);
325 BYTEBUF_ASSERT(_this->limit >= _this->position);
326
327 return _this->limit - _this->position;
328 }
329
330 /** Returns whether there are data between current position and the limit */
331 int
bytebuffer_has_remaining(bytebuffer * _this)332 bytebuffer_has_remaining(bytebuffer *_this)
333 {
334 BYTEBUF_ASSERT(_this != NULL);
335
336 return bytebuffer_remaining(_this) > 0;
337 }
338
339 /**
340 * Flip this buffer.
341 * The limit is set to the position and the position is set zero.
342 */
343 void
bytebuffer_flip(bytebuffer * _this)344 bytebuffer_flip(bytebuffer *_this)
345 {
346 BYTEBUF_ASSERT(_this != NULL);
347
348 _this->limit = _this->position;
349 _this->position = 0;
350 _this->mark = -1;
351 }
352
353 /**
354 * Rewind this buffer.
355 * The position is set to zero.
356 */
357 void
bytebuffer_rewind(bytebuffer * _this)358 bytebuffer_rewind(bytebuffer *_this)
359 {
360 BYTEBUF_ASSERT(_this != NULL);
361
362 _this->position = 0;
363 _this->mark = -1;
364 }
365
366 /**
367 * Clear this buffer.
368 * The position is set to zero.
369 */
370 void
bytebuffer_clear(bytebuffer * _this)371 bytebuffer_clear(bytebuffer *_this)
372 {
373 BYTEBUF_ASSERT(_this != NULL);
374
375 _this->limit = _this->capacity;
376 _this->position = 0;
377 _this->mark = -1;
378 }
379
380 /** mark the current position. */
381 void
bytebuffer_mark(bytebuffer * _this)382 bytebuffer_mark(bytebuffer *_this)
383 {
384 BYTEBUF_ASSERT(_this != NULL);
385
386 _this->mark = _this->position;
387 }
388
389 /** reset the position to the mark. */
390 void
bytebuffer_reset(bytebuffer * _this)391 bytebuffer_reset(bytebuffer *_this)
392 {
393 BYTEBUF_ASSERT(_this != NULL);
394 BYTEBUF_ASSERT(_this->mark >= 0);
395
396 if (_this->mark >= 0)
397 _this->position = _this->mark;
398 }
399
400 /**
401 * Destroy bytebuffer object.
402 */
403 void
bytebuffer_destroy(bytebuffer * _this)404 bytebuffer_destroy(bytebuffer *_this)
405 {
406 BYTEBUF_ASSERT(_this != NULL);
407
408 if (_this != NULL) {
409 free(_this->data);
410 free(_this);
411 }
412 }
413