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