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@530: #include universe@483: #include universe@483: universe@501: int cxBufferInit( universe@501: CxBuffer *buffer, universe@483: void *space, universe@483: size_t capacity, universe@529: CxAllocator const *allocator, universe@483: int flags universe@483: ) { universe@501: buffer->allocator = allocator; universe@501: buffer->flags = flags; universe@501: if (!space) { universe@501: buffer->bytes = cxMalloc(allocator, capacity); universe@501: if (buffer->bytes == NULL) { universe@501: return 1; universe@483: } universe@501: buffer->flags |= CX_BUFFER_FREE_CONTENTS; universe@501: } else { universe@501: buffer->bytes = space; universe@501: } universe@501: buffer->capacity = capacity; universe@501: buffer->size = 0; universe@483: universe@501: buffer->pos = 0; universe@483: universe@501: return 0; universe@483: } universe@483: universe@500: void cxBufferDestroy(CxBuffer *buffer) { universe@483: if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { universe@501: cxFree(buffer->allocator, buffer->bytes); universe@483: } universe@483: } universe@483: universe@483: int cxBufferSeek( universe@500: 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@529: void cxBufferClear(CxBuffer *buffer) { universe@529: memset(buffer->bytes, 0, buffer->size); universe@529: buffer->size = 0; universe@529: buffer->pos = 0; universe@529: } universe@529: universe@529: int cxBufferEof(CxBuffer const *buffer) { universe@483: return buffer->pos >= buffer->size; universe@483: } universe@483: universe@483: int cxBufferMinimumCapacity( universe@500: CxBuffer *buffer, universe@532: size_t newcap universe@483: ) { universe@532: if (newcap <= buffer->capacity) { universe@532: return 0; universe@483: } universe@483: universe@536: if (cxReallocate(buffer->allocator, universe@536: (void **) &buffer->bytes, newcap) == 0) { universe@483: buffer->capacity = newcap; universe@533: return 0; universe@483: } else { universe@483: return -1; universe@483: } 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@500: 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@538: int cxBufferPut( universe@538: CxBuffer *buffer, universe@538: int c universe@538: ) { universe@538: c &= 0xFF; universe@538: unsigned char const ch = c; universe@538: if (cxBufferWrite(&ch, 1, 1, buffer) == 1) { universe@538: return c; universe@538: } else { universe@538: return EOF; universe@538: } universe@538: } universe@538: universe@538: size_t cxBufferPutString( universe@538: CxBuffer *buffer, universe@538: const char *str universe@538: ) { universe@538: return cxBufferWrite(str, 1, strlen(str), buffer); universe@538: } universe@538: universe@483: size_t cxBufferRead( universe@483: void *ptr, universe@483: size_t size, universe@483: size_t nitems, universe@500: 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@500: 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: int cxBufferShiftLeft( universe@500: 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@500: 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@500: 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: }