1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/buffer.c Mon Dec 27 16:51:10 2021 +0100 1.3 @@ -0,0 +1,328 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "cx/buffer.h" 1.33 +#include "cx/utils.h" 1.34 + 1.35 +#include <stdlib.h> 1.36 +#include <string.h> 1.37 + 1.38 +CxBuffer cxBufferCreate( 1.39 + void *space, 1.40 + size_t capacity, 1.41 + int flags 1.42 +) { 1.43 + CxBuffer buffer = (CxBuffer) malloc(sizeof(cx_buffer_s)); 1.44 + if (buffer) { 1.45 + buffer->flags = flags; 1.46 + if (!space) { 1.47 + buffer->bytes = malloc(capacity); 1.48 + if (!buffer->bytes) { 1.49 + free(buffer); 1.50 + return NULL; 1.51 + } 1.52 + memset(buffer->bytes, 0, capacity); 1.53 + buffer->flags |= CX_BUFFER_FREE_CONTENTS; 1.54 + } else { 1.55 + buffer->bytes = space; 1.56 + } 1.57 + buffer->capacity = capacity; 1.58 + buffer->size = 0; 1.59 + 1.60 + buffer->pos = 0; 1.61 + } 1.62 + 1.63 + return buffer; 1.64 +} 1.65 + 1.66 +void cxBufferDestroy(CxBuffer buffer) { 1.67 + if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { 1.68 + free(buffer->bytes); 1.69 + } 1.70 + free(buffer); 1.71 +} 1.72 + 1.73 +CxBuffer cxBufferExtract( 1.74 + CxBuffer src, 1.75 + size_t start, 1.76 + size_t length, 1.77 + int flags 1.78 +) { 1.79 + if (src->size == 0 || length == 0 || 1.80 + ((size_t) -1) - start < length || start + length > src->capacity) { 1.81 + return NULL; 1.82 + } 1.83 + 1.84 + CxBuffer dst = (CxBuffer) malloc(sizeof(cx_buffer_s)); 1.85 + if (dst) { 1.86 + dst->bytes = malloc(length); 1.87 + if (!dst->bytes) { 1.88 + free(dst); 1.89 + return NULL; 1.90 + } 1.91 + dst->capacity = length; 1.92 + dst->size = length; 1.93 + dst->flags = flags | CX_BUFFER_FREE_CONTENTS; 1.94 + dst->pos = 0; 1.95 + memcpy(dst->bytes, src->bytes + start, length); 1.96 + } 1.97 + return dst; 1.98 +} 1.99 + 1.100 +int cxBufferSeek( 1.101 + CxBuffer buffer, 1.102 + off_t offset, 1.103 + int whence 1.104 +) { 1.105 + size_t npos; 1.106 + switch (whence) { 1.107 + case SEEK_CUR: 1.108 + npos = buffer->pos; 1.109 + break; 1.110 + case SEEK_END: 1.111 + npos = buffer->size; 1.112 + break; 1.113 + case SEEK_SET: 1.114 + npos = 0; 1.115 + break; 1.116 + default: 1.117 + return -1; 1.118 + } 1.119 + 1.120 + size_t opos = npos; 1.121 + npos += offset; 1.122 + 1.123 + if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { 1.124 + return -1; 1.125 + } 1.126 + 1.127 + if (npos >= buffer->size) { 1.128 + return -1; 1.129 + } else { 1.130 + buffer->pos = npos; 1.131 + return 0; 1.132 + } 1.133 + 1.134 +} 1.135 + 1.136 +int cxBufferEof(CxBuffer buffer) { 1.137 + return buffer->pos >= buffer->size; 1.138 +} 1.139 + 1.140 +int cxBufferMinimumCapacity( 1.141 + CxBuffer buffer, 1.142 + size_t additional_bytes 1.143 +) { 1.144 + size_t newcap = buffer->capacity + additional_bytes; 1.145 + 1.146 + // overflow protection 1.147 + if (newcap < buffer->capacity) { 1.148 + return -1; 1.149 + } 1.150 + 1.151 + unsigned char *newspace = realloc(buffer->bytes, newcap); 1.152 + if (newspace) { 1.153 + memset(newspace + buffer->size, 0, newcap - buffer->size); 1.154 + buffer->bytes = newspace; 1.155 + buffer->capacity = newcap; 1.156 + } else { 1.157 + return -1; 1.158 + } 1.159 + 1.160 + return 0; 1.161 +} 1.162 + 1.163 +size_t cxBufferWrite( 1.164 + const void *ptr, 1.165 + size_t size, 1.166 + size_t nitems, 1.167 + CxBuffer buffer 1.168 +) { 1.169 + size_t len; 1.170 + if (cx_szmul(size, nitems, &len)) { 1.171 + return 0; 1.172 + } 1.173 + size_t required = buffer->pos + len; 1.174 + if (buffer->pos > required) { 1.175 + return 0; 1.176 + } 1.177 + 1.178 + if (required > buffer->capacity) { 1.179 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 1.180 + if (cxBufferMinimumCapacity(buffer, required)) { 1.181 + return 0; 1.182 + } 1.183 + } else { 1.184 + len = buffer->capacity - buffer->pos; 1.185 + if (size > 1) { 1.186 + len -= len % size; 1.187 + } 1.188 + } 1.189 + } 1.190 + 1.191 + if (len == 0) { 1.192 + return len; 1.193 + } 1.194 + 1.195 + memcpy(buffer->bytes + buffer->pos, ptr, len); 1.196 + buffer->pos += len; 1.197 + if (buffer->pos > buffer->size) { 1.198 + buffer->size = buffer->pos; 1.199 + } 1.200 + 1.201 + return len / size; 1.202 +} 1.203 + 1.204 +size_t cxBufferRead( 1.205 + void *ptr, 1.206 + size_t size, 1.207 + size_t nitems, 1.208 + CxBuffer buffer 1.209 +) { 1.210 + size_t len; 1.211 + if (cx_szmul(size, nitems, &len)) { 1.212 + return 0; 1.213 + } 1.214 + if (buffer->pos + len > buffer->size) { 1.215 + len = buffer->size - buffer->pos; 1.216 + if (size > 1) len -= len % size; 1.217 + } 1.218 + 1.219 + if (len <= 0) { 1.220 + return len; 1.221 + } 1.222 + 1.223 + memcpy(ptr, buffer->bytes + buffer->pos, len); 1.224 + buffer->pos += len; 1.225 + 1.226 + return len / size; 1.227 +} 1.228 + 1.229 +int cxBufferPut( 1.230 + CxBuffer buffer, 1.231 + int c 1.232 +) { 1.233 + if (buffer->pos >= buffer->capacity) { 1.234 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 1.235 + if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) { 1.236 + return EOF; 1.237 + } 1.238 + } else { 1.239 + return EOF; 1.240 + } 1.241 + } 1.242 + 1.243 + c &= 0xFF; 1.244 + buffer->bytes[buffer->pos] = (unsigned char) c; 1.245 + buffer->pos++; 1.246 + if (buffer->pos > buffer->size) { 1.247 + buffer->size = buffer->pos; 1.248 + } 1.249 + return c; 1.250 +} 1.251 + 1.252 +int cxBufferGet(CxBuffer buffer) { 1.253 + if (cxBufferEof(buffer)) { 1.254 + return EOF; 1.255 + } else { 1.256 + int c = buffer->bytes[buffer->pos]; 1.257 + buffer->pos++; 1.258 + return c; 1.259 + } 1.260 +} 1.261 + 1.262 +size_t cxBufferPutString( 1.263 + CxBuffer buffer, 1.264 + const char *str 1.265 +) { 1.266 + return cxBufferWrite(str, 1, strlen(str), buffer); 1.267 +} 1.268 + 1.269 +int cxBufferShiftLeft( 1.270 + CxBuffer buffer, 1.271 + size_t shift 1.272 +) { 1.273 + if (shift >= buffer->size) { 1.274 + buffer->pos = buffer->size = 0; 1.275 + } else { 1.276 + memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); 1.277 + buffer->size -= shift; 1.278 + 1.279 + if (buffer->pos >= shift) { 1.280 + buffer->pos -= shift; 1.281 + } else { 1.282 + buffer->pos = 0; 1.283 + } 1.284 + } 1.285 + return 0; 1.286 +} 1.287 + 1.288 +int cxBufferShiftRight( 1.289 + CxBuffer buffer, 1.290 + size_t shift 1.291 +) { 1.292 + size_t req_capacity = buffer->size + shift; 1.293 + size_t movebytes; 1.294 + 1.295 + // auto extend buffer, if required and enabled 1.296 + if (buffer->capacity < req_capacity) { 1.297 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 1.298 + if (cxBufferMinimumCapacity(buffer, req_capacity)) { 1.299 + return 1; 1.300 + } 1.301 + movebytes = buffer->size; 1.302 + } else { 1.303 + movebytes = buffer->capacity - shift; 1.304 + } 1.305 + } else { 1.306 + movebytes = buffer->size; 1.307 + } 1.308 + 1.309 + memmove(buffer->bytes + shift, buffer->bytes, movebytes); 1.310 + buffer->size = shift + movebytes; 1.311 + 1.312 + buffer->pos += shift; 1.313 + if (buffer->pos > buffer->size) { 1.314 + buffer->pos = buffer->size; 1.315 + } 1.316 + 1.317 + return 0; 1.318 +} 1.319 + 1.320 +int cxBufferShift( 1.321 + CxBuffer buffer, 1.322 + off_t shift 1.323 +) { 1.324 + if (shift < 0) { 1.325 + return cxBufferShiftLeft(buffer, (size_t) (-shift)); 1.326 + } else if (shift > 0) { 1.327 + return cxBufferShiftRight(buffer, (size_t) shift); 1.328 + } else { 1.329 + return 0; 1.330 + } 1.331 +}