ucx/buffer.c

changeset 0
804d8803eade
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/buffer.c	Wed Dec 09 11:32:01 2020 +0100
@@ -0,0 +1,297 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ucx/buffer.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) {
+    UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer));
+    if (buffer) {
+        buffer->flags = flags;
+        if (!space) {
+            buffer->space = (char*)malloc(capacity);
+            if (!buffer->space) {
+                free(buffer);
+                return NULL;
+            }
+            memset(buffer->space, 0, capacity);
+            buffer->flags |= UCX_BUFFER_AUTOFREE;
+        } else {
+            buffer->space = (char*)space;
+        }
+        buffer->capacity = capacity;
+        buffer->size = 0;
+
+        buffer->pos = 0;
+    }
+
+    return buffer;
+}
+
+void ucx_buffer_free(UcxBuffer *buffer) {
+    if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) {
+        free(buffer->space);
+    }
+    free(buffer);
+}
+
+UcxBuffer* ucx_buffer_extract(
+        UcxBuffer *src, size_t start, size_t length, int flags) {
+    if (src->size == 0 || length == 0 ||
+        ((size_t)-1) - start < length || start+length > src->capacity)
+    {
+        return NULL;
+    }
+
+    UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer));
+    if (dst) {
+        dst->space = (char*)malloc(length);
+        if (!dst->space) {
+            free(dst);
+            return NULL;
+        }
+        dst->capacity = length;
+        dst->size = length;
+        dst->flags = flags | UCX_BUFFER_AUTOFREE;
+        dst->pos = 0;
+        memcpy(dst->space, src->space+start, length);
+    }
+    return dst;
+}
+
+int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) {
+    size_t npos;
+    switch (whence) {
+    case SEEK_CUR:
+        npos = buffer->pos;
+        break;
+    case SEEK_END:
+        npos = buffer->size;
+        break;
+    case SEEK_SET:
+        npos = 0;
+        break;
+    default:
+        return -1;
+    }
+
+    size_t opos = npos;
+    npos += offset;
+    
+    if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
+        return -1;
+    }
+    
+    if (npos >= buffer->size) {
+        return -1;
+    } else {
+        buffer->pos = npos;
+        return 0;
+    }
+
+}
+
+int ucx_buffer_eof(UcxBuffer *buffer) {
+    return buffer->pos >= buffer->size;
+}
+
+int ucx_buffer_extend(UcxBuffer *buffer, size_t len) {
+    size_t newcap = buffer->capacity;
+    
+    if (buffer->capacity + len < buffer->capacity) {
+        return -1;
+    }
+    
+    while (buffer->capacity + len > newcap) {
+        newcap <<= 1;
+        if (newcap < buffer->capacity) {
+            return -1;
+        }
+    }
+    
+    char *newspace = (char*)realloc(buffer->space, newcap);
+    if (newspace) {
+        memset(newspace+buffer->size, 0, newcap-buffer->size);
+        buffer->space = newspace;
+        buffer->capacity = newcap;
+    } else {
+        return -1;
+    }
+    
+    return 0;
+}
+
+size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer) {
+    size_t len;
+    if(ucx_szmul(size, nitems, &len)) {
+        return 0;
+    }
+    size_t required = buffer->pos + len;
+    if (buffer->pos > required) {
+        return 0;
+    }
+    
+    if (required > buffer->capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if (ucx_buffer_extend(buffer, required - buffer->capacity)) {
+                return 0;
+            }
+        } else {
+            len = buffer->capacity - buffer->pos;
+            if (size > 1) {
+                len -= len%size;
+            }
+        }
+    }
+    
+    if (len == 0) {
+        return len;
+    }
+    
+    memcpy(buffer->space + buffer->pos, ptr, len);
+    buffer->pos += len;
+    if(buffer->pos > buffer->size) {
+        buffer->size = buffer->pos;
+    }
+    
+    return len / size;
+}
+
+size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer) {
+    size_t len;
+    if(ucx_szmul(size, nitems, &len)) {
+        return 0;
+    }
+    if (buffer->pos + len > buffer->size) {
+        len = buffer->size - buffer->pos;
+        if (size > 1) len -= len%size;
+    }
+    
+    if (len <= 0) {
+        return len;
+    }
+    
+    memcpy(ptr, buffer->space + buffer->pos, len);
+    buffer->pos += len;
+    
+    return len / size;
+}
+
+int ucx_buffer_putc(UcxBuffer *buffer, int c) {
+    if(buffer->pos >= buffer->capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if(ucx_buffer_extend(buffer, 1)) {
+                return EOF;
+            }
+        } else {
+            return EOF;
+        }
+    }
+    
+    c &= 0xFF;
+    buffer->space[buffer->pos] = (char) c;
+    buffer->pos++;
+    if(buffer->pos > buffer->size) {
+        buffer->size = buffer->pos;
+    }
+    return c;
+}
+
+int ucx_buffer_getc(UcxBuffer *buffer) {
+    if (ucx_buffer_eof(buffer)) {
+        return EOF;
+    } else {
+        int c = ((unsigned char*)buffer->space)[buffer->pos];
+        buffer->pos++;
+        return c;
+    }
+}
+
+size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str) {
+    return ucx_buffer_write((const void*)str, 1, strlen(str), buffer);
+}
+
+int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift) {
+    if (shift >= buffer->size) {
+        buffer->pos = buffer->size = 0;
+    } else {
+        memmove(buffer->space, buffer->space + shift, buffer->size - shift);
+        buffer->size -= shift;
+        
+        if (buffer->pos >= shift) {
+            buffer->pos -= shift;
+        } else {
+            buffer->pos = 0;
+        }
+    }
+    return 0;
+}
+
+int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift) {
+    size_t req_capacity = buffer->size + shift;
+    size_t movebytes;
+    
+    // auto extend buffer, if required and enabled
+    if (buffer->capacity < req_capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if (ucx_buffer_extend(buffer, req_capacity - buffer->capacity)) {
+                return 1;
+            }
+            movebytes = buffer->size;
+        } else {
+            movebytes = buffer->capacity - shift;
+        }
+    } else {
+        movebytes = buffer->size;
+    }
+    
+    memmove(buffer->space + shift, buffer->space, movebytes);
+    buffer->size = shift+movebytes;
+    
+    buffer->pos += shift;
+    if (buffer->pos > buffer->size) {
+        buffer->pos = buffer->size;
+    }
+    
+    return 0;
+}
+
+int ucx_buffer_shift(UcxBuffer* buffer, off_t shift) {
+    if (shift < 0) {
+        return ucx_buffer_shift_left(buffer, (size_t) (-shift));
+    } else if (shift > 0) {
+        return ucx_buffer_shift_right(buffer, (size_t) shift);
+    } else {
+        return 0;
+    }
+}

mercurial