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