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