1 /* $OpenBSD: bytebuf.c,v 1.7 2015/01/19 01:48:59 deraadt 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.7 2015/01/19 01:48:59 deraadt 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 if (_this != NULL)
110 free(_this);
111 return NULL;
112 }
113
114 /**
115 * Create a bytebuffer using existing memory area. This memory area will
116 * be freed by bytebuffer's destructor.
117 *
118 * @data the pointer to existing memory area
119 * @param capacity capacity of 'data'.
120 */
121 bytebuffer *
bytebuffer_wrap(void * data,size_t capacity)122 bytebuffer_wrap(void *data, size_t capacity)
123 {
124 bytebuffer *_this;
125
126 if ((_this = bytebuffer_create(0)) == NULL)
127 return NULL;
128
129 _this->data = data;
130 _this->capacity = capacity;
131 _this->mark = -1;
132
133 return _this;
134 }
135
136 /**
137 * Unwrap memory from bytebuffer.
138 *
139 * @param _this the bytebuffer object.
140 */
141 void *
bytebuffer_unwrap(bytebuffer * _this)142 bytebuffer_unwrap(bytebuffer *_this)
143 {
144 void *rval;
145
146 rval = _this->data;
147 _this->data = NULL;
148 _this->capacity = 0;
149 _this->position = 0;
150 _this->limit = 0;
151 _this->mark = -1;
152
153 return rval;
154 }
155
156 /**
157 * Change capacity of this buffer.
158 *
159 * @param _this the bytebuffer object.
160 * @param capacity new capacity.
161 */
162 int
bytebuffer_realloc(bytebuffer * _this,size_t capacity)163 bytebuffer_realloc(bytebuffer *_this, size_t capacity)
164 {
165 void *new_data;
166
167 BYTEBUF_ASSERT(_this->limit <= capacity);
168
169 if ((size_t)_this->limit > capacity) {
170 errno = EINVAL;
171 return -1;
172 }
173
174 if ((new_data = realloc(_this->data, capacity)) == NULL)
175 return -1;
176
177 _this->data = new_data;
178 if ((size_t)_this->limit == _this->capacity)
179 _this->limit = capacity;
180 _this->capacity = capacity;
181
182 return 0;
183 }
184
185 /**
186 * Compact this buffer. the bytes between position and limit are copied
187 * to the beginning of the buffer.
188 *
189 * @param _this the bytebuffer object.
190 */
191 void
bytebuffer_compact(bytebuffer * _this)192 bytebuffer_compact(bytebuffer *_this)
193 {
194 int len;
195
196 len = bytebuffer_remaining(_this);
197
198 if (len <= 0)
199 len = 0;
200 else if (_this->position != 0)
201 memmove(_this->data,
202 (const char *)_this->data + _this->position, (size_t)len);
203
204 _this->position = len;
205 _this->limit = _this->capacity;
206 _this->mark = -1;
207 }
208
209 static int bytebuffer_direct0;
210 /**
211 * BYTEBUFFER_PUT_DIRECT specifies the data that has been written already by
212 * direct access.
213 */
214 const void * BYTEBUFFER_PUT_DIRECT = &bytebuffer_direct0;
215
216 /**
217 * BYTEBUFFER_GET_DIRECT specifies the data that has been read already by
218 * direct access.
219 */
220 void * BYTEBUFFER_GET_DIRECT = &bytebuffer_direct0;
221
222 /**
223 * Write the given data to the buffer.
224 * If buffer is too small, this function returns <code>NULL</code> and
225 * <code>errno</code> is <code>ENOBUFS</code>
226 *
227 * @param _this the bytebuffer object.
228 * @param src source data. To specify the data that has been
229 * written already by direct access, use
230 * {@link ::BYTEBUFFER_PUT_DIRECT} for putting the data.
231 * NULL is the same {@link ::BYTEBUFFER_PUT_DIRECT}
232 * at least on this version, but using NULL is deprecated.
233 * @param srclen length of the source data.
234 * @see ::BYTEBUFFER_PUT_DIRECT
235 */
236 void *
bytebuffer_put(bytebuffer * _this,const void * src,size_t srclen)237 bytebuffer_put(bytebuffer *_this, const void *src, size_t srclen)
238 {
239 void *rval;
240
241 BYTEBUF_ASSERT(_this != NULL);
242 BYTEBUF_ASSERT(srclen > 0);
243
244 if (srclen > bytebuffer_remaining(_this)) {
245 errno = ENOBUFS;
246 return NULL;
247 }
248 rval = (char *)_this->data + _this->position;
249
250 if (src != NULL && src != BYTEBUFFER_PUT_DIRECT)
251 memcpy(rval, src, srclen);
252
253 _this->position += srclen;
254
255 return rval;
256 }
257
258 /*
259 * Transfer data from this buffer to the given destination memory.
260 * If the given buffer is too small, this function returns <code>NULL</code>
261 * and <code>errno</code> is <code>ENOBUFS</code>
262 *
263 * @param dst pointer of the destination memory. Specify NULL
264 * to skip transferring the data.
265 * @param dstlen memory size of the destination.
266 */
267 void *
bytebuffer_get(bytebuffer * _this,void * dst,size_t dstlen)268 bytebuffer_get(bytebuffer *_this, void *dst, size_t dstlen)
269 {
270 BYTEBUF_ASSERT(_this != NULL);
271 BYTEBUF_ASSERT(dstlen > 0);
272
273 if (dstlen > bytebuffer_remaining(_this)) {
274 errno = ENOBUFS;
275 return NULL;
276 }
277 if (dst != NULL && dst != BYTEBUFFER_GET_DIRECT)
278 memcpy(dst, (char *)_this->data + _this->position, dstlen);
279
280 _this->position += dstlen;
281
282 return dst;
283 }
284
285 /** Returns this buffer's position */
286 int
bytebuffer_position(bytebuffer * _this)287 bytebuffer_position(bytebuffer *_this)
288 {
289 BYTEBUF_ASSERT(_this != NULL);
290
291 return _this->position;
292 }
293
294 /** Returns this buffer's limit */
295 int
bytebuffer_limit(bytebuffer * _this)296 bytebuffer_limit(bytebuffer *_this)
297 {
298 BYTEBUF_ASSERT(_this != NULL);
299
300 return _this->limit;
301 }
302
303 /** Returns this buffer's capacity */
304 int
bytebuffer_capacity(bytebuffer * _this)305 bytebuffer_capacity(bytebuffer *_this)
306 {
307 BYTEBUF_ASSERT(_this != NULL);
308
309 return _this->capacity;
310 }
311
312 /** Returns a pointer to current position */
313 void *
bytebuffer_pointer(bytebuffer * _this)314 bytebuffer_pointer(bytebuffer *_this)
315 {
316 BYTEBUF_ASSERT(_this != NULL);
317
318 return (char *)_this->data + _this->position;
319 }
320
321 /** Returns the number of byte between current position and the limit*/
322 size_t
bytebuffer_remaining(bytebuffer * _this)323 bytebuffer_remaining(bytebuffer *_this)
324 {
325 BYTEBUF_ASSERT(_this != NULL);
326 BYTEBUF_ASSERT(_this->limit >= _this->position);
327
328 return _this->limit - _this->position;
329 }
330
331 /** Returns whether there are data between current position and the limit */
332 int
bytebuffer_has_remaining(bytebuffer * _this)333 bytebuffer_has_remaining(bytebuffer *_this)
334 {
335 BYTEBUF_ASSERT(_this != NULL);
336
337 return bytebuffer_remaining(_this) > 0;
338 }
339
340 /**
341 * Flip this buffer.
342 * The limit is set to the position and the position is set zero.
343 */
344 void
bytebuffer_flip(bytebuffer * _this)345 bytebuffer_flip(bytebuffer *_this)
346 {
347 BYTEBUF_ASSERT(_this != NULL);
348
349 _this->limit = _this->position;
350 _this->position = 0;
351 _this->mark = -1;
352 }
353
354 /**
355 * Rewind this buffer.
356 * The position is set to zero.
357 */
358 void
bytebuffer_rewind(bytebuffer * _this)359 bytebuffer_rewind(bytebuffer *_this)
360 {
361 BYTEBUF_ASSERT(_this != NULL);
362
363 _this->position = 0;
364 _this->mark = -1;
365 }
366
367 /**
368 * Clear this buffer.
369 * The position is set to zero.
370 */
371 void
bytebuffer_clear(bytebuffer * _this)372 bytebuffer_clear(bytebuffer *_this)
373 {
374 BYTEBUF_ASSERT(_this != NULL);
375
376 _this->limit = _this->capacity;
377 _this->position = 0;
378 _this->mark = -1;
379 }
380
381 /** mark the current position. */
382 void
bytebuffer_mark(bytebuffer * _this)383 bytebuffer_mark(bytebuffer *_this)
384 {
385 BYTEBUF_ASSERT(_this != NULL);
386
387 _this->mark = _this->position;
388 }
389
390 /** reset the position to the mark. */
391 void
bytebuffer_reset(bytebuffer * _this)392 bytebuffer_reset(bytebuffer *_this)
393 {
394 BYTEBUF_ASSERT(_this != NULL);
395 BYTEBUF_ASSERT(_this->mark >= 0);
396
397 if (_this->mark >= 0)
398 _this->position = _this->mark;
399 }
400
401 /**
402 * Destroy bytebuffer object.
403 */
404 void
bytebuffer_destroy(bytebuffer * _this)405 bytebuffer_destroy(bytebuffer *_this)
406 {
407 BYTEBUF_ASSERT(_this != NULL);
408
409 if (_this != NULL) {
410 if (_this->data != NULL)
411 free(_this->data);
412 free(_this);
413 }
414 }
415