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