1*90023272Smmcc /* $OpenBSD: bytebuf.c,v 1.8 2015/12/05 18:43:36 mmcc Exp $ */
20fbf3537Syasuoka /*-
30fbf3537Syasuoka * Copyright (c) 2009 Internet Initiative Japan Inc.
40fbf3537Syasuoka * All rights reserved.
50fbf3537Syasuoka *
60fbf3537Syasuoka * Redistribution and use in source and binary forms, with or without
70fbf3537Syasuoka * modification, are permitted provided that the following conditions
80fbf3537Syasuoka * are met:
90fbf3537Syasuoka * 1. Redistributions of source code must retain the above copyright
100fbf3537Syasuoka * notice, this list of conditions and the following disclaimer.
110fbf3537Syasuoka * 2. Redistributions in binary form must reproduce the above copyright
120fbf3537Syasuoka * notice, this list of conditions and the following disclaimer in the
130fbf3537Syasuoka * documentation and/or other materials provided with the distribution.
140fbf3537Syasuoka *
150fbf3537Syasuoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
160fbf3537Syasuoka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170fbf3537Syasuoka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
180fbf3537Syasuoka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
190fbf3537Syasuoka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
200fbf3537Syasuoka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210fbf3537Syasuoka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220fbf3537Syasuoka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
230fbf3537Syasuoka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240fbf3537Syasuoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250fbf3537Syasuoka * SUCH DAMAGE.
260fbf3537Syasuoka */
270fbf3537Syasuoka /**@file
280fbf3537Syasuoka * bytebuffer provides 'byte buffer' helper methods.
290fbf3537Syasuoka *
300fbf3537Syasuoka * Example:<pre>
310fbf3537Syasuoka * bytebuffer *buf = bytebuffer_create(BUFSIZ);
320fbf3537Syasuoka * int sz = read(STDIN_FILENO, bytebuffer_pointer(buf),
330fbf3537Syasuoka * bytebuffer_remaining(buf));
340fbf3537Syasuoka * if (sz > 0) {
350fbf3537Syasuoka * bytebuffer_put(buf, BYTEBUFFER_PUT_DIRECT, sz);
360fbf3537Syasuoka * bytebuffer_flip(buf);
370fbf3537Syasuoka *
380fbf3537Syasuoka * sz = write(STDOUT_FILENO, bytebuffer_pointer(buf),
390fbf3537Syasuoka * bytebuffer_remaining(buf));
400fbf3537Syasuoka * bytebuffer_compact(buf);
410fbf3537Syasuoka * }</pre>
420fbf3537Syasuoka *
430fbf3537Syasuoka * @author Yasuoka Masahiko
44*90023272Smmcc * $Id: bytebuf.c,v 1.8 2015/12/05 18:43:36 mmcc Exp $
450fbf3537Syasuoka */
460fbf3537Syasuoka #include <stdlib.h>
470fbf3537Syasuoka #include <string.h>
480fbf3537Syasuoka #include <errno.h>
490fbf3537Syasuoka
500fbf3537Syasuoka #ifdef BYTEBUF_DEBUG
510fbf3537Syasuoka #include <stdio.h>
520fbf3537Syasuoka #endif
530fbf3537Syasuoka
540fbf3537Syasuoka #ifndef BYTEBUF_ASSERT
550fbf3537Syasuoka #ifdef BYTEBUF_DEBUG
560fbf3537Syasuoka #define BYTEBUF_ASSERT(cond) \
570fbf3537Syasuoka if (!(cond)) { \
580fbf3537Syasuoka fprintf(stderr, \
590fbf3537Syasuoka "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
600fbf3537Syasuoka , __func__, __FILE__, __LINE__); \
610fbf3537Syasuoka abort(); \
620fbf3537Syasuoka }
630fbf3537Syasuoka #else
640fbf3537Syasuoka #define BYTEBUF_ASSERT(cond)
650fbf3537Syasuoka #endif
660fbf3537Syasuoka #endif
670fbf3537Syasuoka
680fbf3537Syasuoka #include "bytebuf.h"
690fbf3537Syasuoka
700fbf3537Syasuoka struct _bytebuffer {
710fbf3537Syasuoka /** current position */
720fbf3537Syasuoka int position;
730fbf3537Syasuoka /** current limit */
740fbf3537Syasuoka int limit;
750fbf3537Syasuoka /** position mark*/
760fbf3537Syasuoka int mark;
770fbf3537Syasuoka /** capacity of buffer */
780fbf3537Syasuoka size_t capacity;
790fbf3537Syasuoka /** allocated memory area */
800fbf3537Syasuoka void *data;
810fbf3537Syasuoka };
820fbf3537Syasuoka
830fbf3537Syasuoka /**
840fbf3537Syasuoka * Create a bytebuffer and allocate memory area.
850fbf3537Syasuoka *
860fbf3537Syasuoka * @param capacity Capacity of allocating memory. If zero or
870fbf3537Syasuoka * negative value is specified, this function don't allocate
880fbf3537Syasuoka * memory.
890fbf3537Syasuoka */
900fbf3537Syasuoka bytebuffer *
bytebuffer_create(size_t capacity)910fbf3537Syasuoka bytebuffer_create(size_t capacity)
920fbf3537Syasuoka {
930fbf3537Syasuoka bytebuffer *_this = NULL;
940fbf3537Syasuoka
951f03f1b3Syasuoka if ((_this = calloc(1, sizeof(bytebuffer))) == NULL)
960fbf3537Syasuoka return NULL;
970fbf3537Syasuoka
980fbf3537Syasuoka if (capacity > 0) {
991f03f1b3Syasuoka if ((_this->data = calloc(1, capacity)) == NULL)
100f0a4e295Syasuoka goto fail;
1010fbf3537Syasuoka _this->capacity = capacity;
1020fbf3537Syasuoka } else
1030fbf3537Syasuoka _this->capacity = 0;
1040fbf3537Syasuoka
1050fbf3537Syasuoka _this->limit = _this->capacity;
1060fbf3537Syasuoka _this->mark = -1;
1070fbf3537Syasuoka return _this;
108f0a4e295Syasuoka fail:
1090fbf3537Syasuoka free(_this);
1100fbf3537Syasuoka return NULL;
1110fbf3537Syasuoka }
1120fbf3537Syasuoka
1130fbf3537Syasuoka /**
1140fbf3537Syasuoka * Create a bytebuffer using existing memory area. This memory area will
1150fbf3537Syasuoka * be freed by bytebuffer's destructor.
1160fbf3537Syasuoka *
1170fbf3537Syasuoka * @data the pointer to existing memory area
1180fbf3537Syasuoka * @param capacity capacity of 'data'.
1190fbf3537Syasuoka */
1200fbf3537Syasuoka bytebuffer *
bytebuffer_wrap(void * data,size_t capacity)1210fbf3537Syasuoka bytebuffer_wrap(void *data, size_t capacity)
1220fbf3537Syasuoka {
1230fbf3537Syasuoka bytebuffer *_this;
1240fbf3537Syasuoka
1250fbf3537Syasuoka if ((_this = bytebuffer_create(0)) == NULL)
1260fbf3537Syasuoka return NULL;
1270fbf3537Syasuoka
1280fbf3537Syasuoka _this->data = data;
1290fbf3537Syasuoka _this->capacity = capacity;
1300fbf3537Syasuoka _this->mark = -1;
1310fbf3537Syasuoka
1320fbf3537Syasuoka return _this;
1330fbf3537Syasuoka }
1340fbf3537Syasuoka
1350fbf3537Syasuoka /**
1360fbf3537Syasuoka * Unwrap memory from bytebuffer.
1370fbf3537Syasuoka *
1380fbf3537Syasuoka * @param _this the bytebuffer object.
1390fbf3537Syasuoka */
1400fbf3537Syasuoka void *
bytebuffer_unwrap(bytebuffer * _this)1410fbf3537Syasuoka bytebuffer_unwrap(bytebuffer *_this)
1420fbf3537Syasuoka {
1430fbf3537Syasuoka void *rval;
1440fbf3537Syasuoka
1450fbf3537Syasuoka rval = _this->data;
1460fbf3537Syasuoka _this->data = NULL;
1470fbf3537Syasuoka _this->capacity = 0;
1480fbf3537Syasuoka _this->position = 0;
1490fbf3537Syasuoka _this->limit = 0;
1500fbf3537Syasuoka _this->mark = -1;
1510fbf3537Syasuoka
1520fbf3537Syasuoka return rval;
1530fbf3537Syasuoka }
1540fbf3537Syasuoka
1550fbf3537Syasuoka /**
1560fbf3537Syasuoka * Change capacity of this buffer.
1570fbf3537Syasuoka *
1580fbf3537Syasuoka * @param _this the bytebuffer object.
1590fbf3537Syasuoka * @param capacity new capacity.
1600fbf3537Syasuoka */
1610fbf3537Syasuoka int
bytebuffer_realloc(bytebuffer * _this,size_t capacity)1620fbf3537Syasuoka bytebuffer_realloc(bytebuffer *_this, size_t capacity)
1630fbf3537Syasuoka {
1640fbf3537Syasuoka void *new_data;
1650fbf3537Syasuoka
1660fbf3537Syasuoka BYTEBUF_ASSERT(_this->limit <= capacity);
1670fbf3537Syasuoka
1680fbf3537Syasuoka if (_this->limit > capacity) {
1690fbf3537Syasuoka errno = EINVAL;
1700fbf3537Syasuoka return -1;
1710fbf3537Syasuoka }
1720fbf3537Syasuoka
1730fbf3537Syasuoka if ((new_data = realloc(_this->data, capacity)) == NULL)
1740fbf3537Syasuoka return -1;
1750fbf3537Syasuoka
1760fbf3537Syasuoka _this->data = new_data;
1770fbf3537Syasuoka if (_this->limit == _this->capacity)
1780fbf3537Syasuoka _this->limit = capacity;
1790fbf3537Syasuoka _this->capacity = capacity;
1800fbf3537Syasuoka
1810fbf3537Syasuoka return 0;
1820fbf3537Syasuoka }
1830fbf3537Syasuoka
1840fbf3537Syasuoka /**
1850fbf3537Syasuoka * Compact this buffer. the bytes between position and limit are copied
1860fbf3537Syasuoka * to the beginning of the buffer.
1870fbf3537Syasuoka *
1880fbf3537Syasuoka * @param _this the bytebuffer object.
1890fbf3537Syasuoka */
1900fbf3537Syasuoka void
bytebuffer_compact(bytebuffer * _this)1910fbf3537Syasuoka bytebuffer_compact(bytebuffer *_this)
1920fbf3537Syasuoka {
1930fbf3537Syasuoka int len;
1940fbf3537Syasuoka
1950fbf3537Syasuoka len = bytebuffer_remaining(_this);
1960fbf3537Syasuoka
1970fbf3537Syasuoka if (len <= 0)
1980fbf3537Syasuoka len = 0;
1990fbf3537Syasuoka else if (_this->position != 0)
2000fbf3537Syasuoka memmove(_this->data,
2010fbf3537Syasuoka (const char *)_this->data + _this->position, (size_t)len);
2020fbf3537Syasuoka
2030fbf3537Syasuoka _this->position = len;
2040fbf3537Syasuoka _this->limit = _this->capacity;
2050fbf3537Syasuoka _this->mark = -1;
2060fbf3537Syasuoka }
2070fbf3537Syasuoka
2080fbf3537Syasuoka static int bytebuffer_direct0;
2090fbf3537Syasuoka /**
2100fbf3537Syasuoka * BYTEBUFFER_PUT_DIRECT specifies the data that has been written already by
2110fbf3537Syasuoka * direct access.
2120fbf3537Syasuoka */
2130fbf3537Syasuoka const void * BYTEBUFFER_PUT_DIRECT = &bytebuffer_direct0;
2140fbf3537Syasuoka
2150fbf3537Syasuoka /**
2160fbf3537Syasuoka * BYTEBUFFER_GET_DIRECT specifies the data that has been read already by
2170fbf3537Syasuoka * direct access.
2180fbf3537Syasuoka */
2190fbf3537Syasuoka void * BYTEBUFFER_GET_DIRECT = &bytebuffer_direct0;
2200fbf3537Syasuoka
2210fbf3537Syasuoka /**
2220fbf3537Syasuoka * Write the given data to the buffer.
2230fbf3537Syasuoka * If buffer is too small, this function returns <code>NULL</code> and
2240fbf3537Syasuoka * <code>errno</code> is <code>ENOBUFS</code>
2250fbf3537Syasuoka *
2260fbf3537Syasuoka * @param _this the bytebuffer object.
2270fbf3537Syasuoka * @param src source data. To specify the data that has been
2280fbf3537Syasuoka * written already by direct access, use
2290fbf3537Syasuoka * {@link ::BYTEBUFFER_PUT_DIRECT} for putting the data.
2300fbf3537Syasuoka * NULL is the same {@link ::BYTEBUFFER_PUT_DIRECT}
2310fbf3537Syasuoka * at least on this version, but using NULL is deprecated.
2320fbf3537Syasuoka * @param srclen length of the source data.
2330fbf3537Syasuoka * @see ::BYTEBUFFER_PUT_DIRECT
2340fbf3537Syasuoka */
2350fbf3537Syasuoka void *
bytebuffer_put(bytebuffer * _this,const void * src,size_t srclen)2360fbf3537Syasuoka bytebuffer_put(bytebuffer *_this, const void *src, size_t srclen)
2370fbf3537Syasuoka {
2380fbf3537Syasuoka void *rval;
2390fbf3537Syasuoka
2400fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
2410fbf3537Syasuoka BYTEBUF_ASSERT(srclen > 0);
2420fbf3537Syasuoka
2430fbf3537Syasuoka if (srclen > bytebuffer_remaining(_this)) {
2440fbf3537Syasuoka errno = ENOBUFS;
2450fbf3537Syasuoka return NULL;
2460fbf3537Syasuoka }
2470fbf3537Syasuoka rval = (char *)_this->data + _this->position;
2480fbf3537Syasuoka
2490fbf3537Syasuoka if (src != NULL && src != BYTEBUFFER_PUT_DIRECT)
2500fbf3537Syasuoka memcpy(rval, src, srclen);
2510fbf3537Syasuoka
2520fbf3537Syasuoka _this->position += srclen;
2530fbf3537Syasuoka
2540fbf3537Syasuoka return rval;
2550fbf3537Syasuoka }
2560fbf3537Syasuoka
2570fbf3537Syasuoka /*
2580fbf3537Syasuoka * Transfer data from this buffer to the given destination memory.
2590fbf3537Syasuoka * If the given buffer is too small, this function returns <code>NULL</code>
2600fbf3537Syasuoka * and <code>errno</code> is <code>ENOBUFS</code>
2610fbf3537Syasuoka *
2620fbf3537Syasuoka * @param dst pointer of the destination memory. Specify NULL
26398c26657Sguenther * to skip transferring the data.
2640fbf3537Syasuoka * @param dstlne memory size of the destination.
2650fbf3537Syasuoka */
2660fbf3537Syasuoka void *
bytebuffer_get(bytebuffer * _this,void * dst,size_t dstlen)2670fbf3537Syasuoka bytebuffer_get(bytebuffer *_this, void *dst, size_t dstlen)
2680fbf3537Syasuoka {
2690fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
2700fbf3537Syasuoka BYTEBUF_ASSERT(dstlen > 0);
2710fbf3537Syasuoka
2720fbf3537Syasuoka if (dstlen > bytebuffer_remaining(_this)) {
2730fbf3537Syasuoka errno = ENOBUFS;
2740fbf3537Syasuoka return NULL;
2750fbf3537Syasuoka }
2760fbf3537Syasuoka if (dst != NULL && dst != BYTEBUFFER_GET_DIRECT)
2770fbf3537Syasuoka memcpy(dst, (char *)_this->data + _this->position, dstlen);
2780fbf3537Syasuoka
2790fbf3537Syasuoka _this->position += dstlen;
2800fbf3537Syasuoka
2810fbf3537Syasuoka return dst;
2820fbf3537Syasuoka }
2830fbf3537Syasuoka
2840fbf3537Syasuoka /** Returns this buffer's position */
2850fbf3537Syasuoka int
bytebuffer_position(bytebuffer * _this)2860fbf3537Syasuoka bytebuffer_position(bytebuffer *_this)
2870fbf3537Syasuoka {
2880fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
2890fbf3537Syasuoka
2900fbf3537Syasuoka return _this->position;
2910fbf3537Syasuoka }
2920fbf3537Syasuoka
2930fbf3537Syasuoka /** Returns this buffer's limit */
2940fbf3537Syasuoka int
bytebuffer_limit(bytebuffer * _this)2950fbf3537Syasuoka bytebuffer_limit(bytebuffer *_this)
2960fbf3537Syasuoka {
2970fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
2980fbf3537Syasuoka
2990fbf3537Syasuoka return _this->limit;
3000fbf3537Syasuoka }
3010fbf3537Syasuoka
3020fbf3537Syasuoka /** Returns this buffer's capacity */
3030fbf3537Syasuoka int
bytebuffer_capacity(bytebuffer * _this)3040fbf3537Syasuoka bytebuffer_capacity(bytebuffer *_this)
3050fbf3537Syasuoka {
3060fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3070fbf3537Syasuoka
3080fbf3537Syasuoka return _this->capacity;
3090fbf3537Syasuoka }
3100fbf3537Syasuoka
3110fbf3537Syasuoka /** Returns a pointer to current position */
3120fbf3537Syasuoka void *
bytebuffer_pointer(bytebuffer * _this)3130fbf3537Syasuoka bytebuffer_pointer(bytebuffer *_this)
3140fbf3537Syasuoka {
3150fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3160fbf3537Syasuoka
3170fbf3537Syasuoka return (char *)_this->data + _this->position;
3180fbf3537Syasuoka }
3190fbf3537Syasuoka
3200fbf3537Syasuoka /** Returns the number of byte between current position and the limit*/
3210fbf3537Syasuoka size_t
bytebuffer_remaining(bytebuffer * _this)3220fbf3537Syasuoka bytebuffer_remaining(bytebuffer *_this)
3230fbf3537Syasuoka {
3240fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3250fbf3537Syasuoka BYTEBUF_ASSERT(_this->limit >= _this->position);
3260fbf3537Syasuoka
3270fbf3537Syasuoka return _this->limit - _this->position;
3280fbf3537Syasuoka }
3290fbf3537Syasuoka
3300fbf3537Syasuoka /** Returns whether there are data between current position and the limit */
3310fbf3537Syasuoka int
bytebuffer_has_remaining(bytebuffer * _this)3320fbf3537Syasuoka bytebuffer_has_remaining(bytebuffer *_this)
3330fbf3537Syasuoka {
3340fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3350fbf3537Syasuoka
3360fbf3537Syasuoka return bytebuffer_remaining(_this) > 0;
3370fbf3537Syasuoka }
3380fbf3537Syasuoka
3390fbf3537Syasuoka /**
3400fbf3537Syasuoka * Flip this buffer.
3410fbf3537Syasuoka * The limit is set to the position and the position is set zero.
3420fbf3537Syasuoka */
3430fbf3537Syasuoka void
bytebuffer_flip(bytebuffer * _this)3440fbf3537Syasuoka bytebuffer_flip(bytebuffer *_this)
3450fbf3537Syasuoka {
3460fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3470fbf3537Syasuoka
3480fbf3537Syasuoka _this->limit = _this->position;
3490fbf3537Syasuoka _this->position = 0;
3500fbf3537Syasuoka _this->mark = -1;
3510fbf3537Syasuoka }
3520fbf3537Syasuoka
3530fbf3537Syasuoka /**
3540fbf3537Syasuoka * Rewind this buffer.
3550fbf3537Syasuoka * The position is set to zero.
3560fbf3537Syasuoka */
3570fbf3537Syasuoka void
bytebuffer_rewind(bytebuffer * _this)3580fbf3537Syasuoka bytebuffer_rewind(bytebuffer *_this)
3590fbf3537Syasuoka {
3600fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3610fbf3537Syasuoka
3620fbf3537Syasuoka _this->position = 0;
3630fbf3537Syasuoka _this->mark = -1;
3640fbf3537Syasuoka }
3650fbf3537Syasuoka
3660fbf3537Syasuoka /**
3670fbf3537Syasuoka * Clear this buffer.
3680fbf3537Syasuoka * The position is set to zero.
3690fbf3537Syasuoka */
3700fbf3537Syasuoka void
bytebuffer_clear(bytebuffer * _this)3710fbf3537Syasuoka bytebuffer_clear(bytebuffer *_this)
3720fbf3537Syasuoka {
3730fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3740fbf3537Syasuoka
3750fbf3537Syasuoka _this->limit = _this->capacity;
3760fbf3537Syasuoka _this->position = 0;
3770fbf3537Syasuoka _this->mark = -1;
3780fbf3537Syasuoka }
3790fbf3537Syasuoka
3800fbf3537Syasuoka /** mark the current position. */
3810fbf3537Syasuoka void
bytebuffer_mark(bytebuffer * _this)3820fbf3537Syasuoka bytebuffer_mark(bytebuffer *_this)
3830fbf3537Syasuoka {
3840fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3850fbf3537Syasuoka
3860fbf3537Syasuoka _this->mark = _this->position;
3870fbf3537Syasuoka }
3880fbf3537Syasuoka
3890fbf3537Syasuoka /** reset the position to the mark. */
3900fbf3537Syasuoka void
bytebuffer_reset(bytebuffer * _this)3910fbf3537Syasuoka bytebuffer_reset(bytebuffer *_this)
3920fbf3537Syasuoka {
3930fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
3940fbf3537Syasuoka BYTEBUF_ASSERT(_this->mark >= 0);
3950fbf3537Syasuoka
3960fbf3537Syasuoka if (_this->mark >= 0)
3970fbf3537Syasuoka _this->position = _this->mark;
3980fbf3537Syasuoka }
3990fbf3537Syasuoka
4000fbf3537Syasuoka /**
4010fbf3537Syasuoka * Destroy bytebuffer object.
4020fbf3537Syasuoka */
4030fbf3537Syasuoka void
bytebuffer_destroy(bytebuffer * _this)4040fbf3537Syasuoka bytebuffer_destroy(bytebuffer *_this)
4050fbf3537Syasuoka {
4060fbf3537Syasuoka BYTEBUF_ASSERT(_this != NULL);
4070fbf3537Syasuoka
4080fbf3537Syasuoka if (_this != NULL) {
4090fbf3537Syasuoka free(_this->data);
4100fbf3537Syasuoka free(_this);
4110fbf3537Syasuoka }
4120fbf3537Syasuoka }
413