universe@483: /* universe@483: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@483: * universe@483: * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. universe@483: * universe@483: * Redistribution and use in source and binary forms, with or without universe@483: * modification, are permitted provided that the following conditions are met: universe@483: * universe@483: * 1. Redistributions of source code must retain the above copyright universe@483: * notice, this list of conditions and the following disclaimer. universe@483: * universe@483: * 2. Redistributions in binary form must reproduce the above copyright universe@483: * notice, this list of conditions and the following disclaimer in the universe@483: * documentation and/or other materials provided with the distribution. universe@483: * universe@483: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@483: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@483: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@483: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@483: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@483: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@483: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@483: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@483: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@483: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@483: * POSSIBILITY OF SUCH DAMAGE. universe@483: */ universe@483: universe@483: #include "cx/buffer.h" universe@483: #include "cx/utils.h" universe@483: universe@483: #include universe@483: #include universe@483: universe@483: CxBuffer cxBufferCreate( universe@483: void *space, universe@483: size_t capacity, universe@483: int flags universe@483: ) { universe@483: CxBuffer buffer = (CxBuffer) malloc(sizeof(cx_buffer_s)); universe@483: if (buffer) { universe@483: buffer->flags = flags; universe@483: if (!space) { universe@483: buffer->bytes = malloc(capacity); universe@483: if (!buffer->bytes) { universe@483: free(buffer); universe@483: return NULL; universe@483: } universe@483: memset(buffer->bytes, 0, capacity); universe@483: buffer->flags |= CX_BUFFER_FREE_CONTENTS; universe@483: } else { universe@483: buffer->bytes = space; universe@483: } universe@483: buffer->capacity = capacity; universe@483: buffer->size = 0; universe@483: universe@483: buffer->pos = 0; universe@483: } universe@483: universe@483: return buffer; universe@483: } universe@483: universe@483: void cxBufferDestroy(CxBuffer buffer) { universe@483: if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { universe@483: free(buffer->bytes); universe@483: } universe@483: free(buffer); universe@483: } universe@483: universe@483: CxBuffer cxBufferExtract( universe@483: CxBuffer src, universe@483: size_t start, universe@483: size_t length, universe@483: int flags universe@483: ) { universe@483: if (src->size == 0 || length == 0 || universe@483: ((size_t) -1) - start < length || start + length > src->capacity) { universe@483: return NULL; universe@483: } universe@483: universe@483: CxBuffer dst = (CxBuffer) malloc(sizeof(cx_buffer_s)); universe@483: if (dst) { universe@483: dst->bytes = malloc(length); universe@483: if (!dst->bytes) { universe@483: free(dst); universe@483: return NULL; universe@483: } universe@483: dst->capacity = length; universe@483: dst->size = length; universe@483: dst->flags = flags | CX_BUFFER_FREE_CONTENTS; universe@483: dst->pos = 0; universe@483: memcpy(dst->bytes, src->bytes + start, length); universe@483: } universe@483: return dst; universe@483: } universe@483: universe@483: int cxBufferSeek( universe@483: CxBuffer buffer, universe@483: off_t offset, universe@483: int whence universe@483: ) { universe@483: size_t npos; universe@483: switch (whence) { universe@483: case SEEK_CUR: universe@483: npos = buffer->pos; universe@483: break; universe@483: case SEEK_END: universe@483: npos = buffer->size; universe@483: break; universe@483: case SEEK_SET: universe@483: npos = 0; universe@483: break; universe@483: default: universe@483: return -1; universe@483: } universe@483: universe@483: size_t opos = npos; universe@483: npos += offset; universe@483: universe@483: if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { universe@483: return -1; universe@483: } universe@483: universe@483: if (npos >= buffer->size) { universe@483: return -1; universe@483: } else { universe@483: buffer->pos = npos; universe@483: return 0; universe@483: } universe@483: universe@483: } universe@483: universe@483: int cxBufferEof(CxBuffer buffer) { universe@483: return buffer->pos >= buffer->size; universe@483: } universe@483: universe@483: int cxBufferMinimumCapacity( universe@483: CxBuffer buffer, universe@483: size_t additional_bytes universe@483: ) { universe@483: size_t newcap = buffer->capacity + additional_bytes; universe@483: universe@483: // overflow protection universe@483: if (newcap < buffer->capacity) { universe@483: return -1; universe@483: } universe@483: universe@483: unsigned char *newspace = realloc(buffer->bytes, newcap); universe@483: if (newspace) { universe@483: memset(newspace + buffer->size, 0, newcap - buffer->size); universe@483: buffer->bytes = newspace; universe@483: buffer->capacity = newcap; universe@483: } else { universe@483: return -1; universe@483: } universe@483: universe@483: return 0; universe@483: } universe@483: universe@483: size_t cxBufferWrite( universe@489: void const *ptr, universe@483: size_t size, universe@483: size_t nitems, universe@483: CxBuffer buffer universe@483: ) { universe@483: size_t len; universe@483: if (cx_szmul(size, nitems, &len)) { universe@483: return 0; universe@483: } universe@483: size_t required = buffer->pos + len; universe@483: if (buffer->pos > required) { universe@483: return 0; universe@483: } universe@483: universe@483: if (required > buffer->capacity) { universe@483: if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { universe@483: if (cxBufferMinimumCapacity(buffer, required)) { universe@483: return 0; universe@483: } universe@483: } else { universe@483: len = buffer->capacity - buffer->pos; universe@483: if (size > 1) { universe@483: len -= len % size; universe@483: } universe@483: } universe@483: } universe@483: universe@483: if (len == 0) { universe@483: return len; universe@483: } universe@483: universe@483: memcpy(buffer->bytes + buffer->pos, ptr, len); universe@483: buffer->pos += len; universe@483: if (buffer->pos > buffer->size) { universe@483: buffer->size = buffer->pos; universe@483: } universe@483: universe@483: return len / size; universe@483: } universe@483: universe@483: size_t cxBufferRead( universe@483: void *ptr, universe@483: size_t size, universe@483: size_t nitems, universe@483: CxBuffer buffer universe@483: ) { universe@483: size_t len; universe@483: if (cx_szmul(size, nitems, &len)) { universe@483: return 0; universe@483: } universe@483: if (buffer->pos + len > buffer->size) { universe@483: len = buffer->size - buffer->pos; universe@483: if (size > 1) len -= len % size; universe@483: } universe@483: universe@483: if (len <= 0) { universe@483: return len; universe@483: } universe@483: universe@483: memcpy(ptr, buffer->bytes + buffer->pos, len); universe@483: buffer->pos += len; universe@483: universe@483: return len / size; universe@483: } universe@483: universe@483: int cxBufferPut( universe@483: CxBuffer buffer, universe@483: int c universe@483: ) { universe@483: if (buffer->pos >= buffer->capacity) { universe@483: if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { universe@483: if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) { universe@483: return EOF; universe@483: } universe@483: } else { universe@483: return EOF; universe@483: } universe@483: } universe@483: universe@483: c &= 0xFF; universe@483: buffer->bytes[buffer->pos] = (unsigned char) c; universe@483: buffer->pos++; universe@483: if (buffer->pos > buffer->size) { universe@483: buffer->size = buffer->pos; universe@483: } universe@483: return c; universe@483: } universe@483: universe@483: int cxBufferGet(CxBuffer buffer) { universe@483: if (cxBufferEof(buffer)) { universe@483: return EOF; universe@483: } else { universe@483: int c = buffer->bytes[buffer->pos]; universe@483: buffer->pos++; universe@483: return c; universe@483: } universe@483: } universe@483: universe@483: size_t cxBufferPutString( universe@483: CxBuffer buffer, universe@483: const char *str universe@483: ) { universe@483: return cxBufferWrite(str, 1, strlen(str), buffer); universe@483: } universe@483: universe@483: int cxBufferShiftLeft( universe@483: CxBuffer buffer, universe@483: size_t shift universe@483: ) { universe@483: if (shift >= buffer->size) { universe@483: buffer->pos = buffer->size = 0; universe@483: } else { universe@483: memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); universe@483: buffer->size -= shift; universe@483: universe@483: if (buffer->pos >= shift) { universe@483: buffer->pos -= shift; universe@483: } else { universe@483: buffer->pos = 0; universe@483: } universe@483: } universe@483: return 0; universe@483: } universe@483: universe@483: int cxBufferShiftRight( universe@483: CxBuffer buffer, universe@483: size_t shift universe@483: ) { universe@483: size_t req_capacity = buffer->size + shift; universe@483: size_t movebytes; universe@483: universe@483: // auto extend buffer, if required and enabled universe@483: if (buffer->capacity < req_capacity) { universe@483: if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { universe@483: if (cxBufferMinimumCapacity(buffer, req_capacity)) { universe@483: return 1; universe@483: } universe@483: movebytes = buffer->size; universe@483: } else { universe@483: movebytes = buffer->capacity - shift; universe@483: } universe@483: } else { universe@483: movebytes = buffer->size; universe@483: } universe@483: universe@483: memmove(buffer->bytes + shift, buffer->bytes, movebytes); universe@483: buffer->size = shift + movebytes; universe@483: universe@483: buffer->pos += shift; universe@483: if (buffer->pos > buffer->size) { universe@483: buffer->pos = buffer->size; universe@483: } universe@483: universe@483: return 0; universe@483: } universe@483: universe@483: int cxBufferShift( universe@483: CxBuffer buffer, universe@483: off_t shift universe@483: ) { universe@483: if (shift < 0) { universe@483: return cxBufferShiftLeft(buffer, (size_t) (-shift)); universe@483: } else if (shift > 0) { universe@483: return cxBufferShiftRight(buffer, (size_t) shift); universe@483: } else { universe@483: return 0; universe@483: } universe@483: }