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