view src/dmgrowbuf.c @ 2576:812b16ee49db

I had been living under apparent false impression that "realfft.c" on which the FFT implementation in DMLIB was basically copied from was released in public domain at some point, but it could very well be that it never was. Correct license is (or seems to be) GNU GPL. Thus I removing the code from DMLIB, and profusely apologize to the author, Philip Van Baren. It was never my intention to distribute code based on his original work under a more liberal license than originally intended.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 11 Mar 2022 16:32:50 +0200
parents c6ee41fd98dd
children 9807ae37ad69
line wrap: on
line source

/*
 * DMLib
 * -- Growable buffer implementation
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2018-2021 Tecnic Software productions (TNSP)
 */
#include "dmgrowbuf.h"

//#define DM_GROWBUF_DEBUG 1

#ifdef DM_GROWBUF_DEBUG
#    define DM_DBG(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
#else
#    define DM_DBG(...) do { } while (0)
#endif


int dmGrowBufInit(DMGrowBuf *buf)
{
    DM_DBG("dmGrowBufInit(%p)\n", buf);

    if (buf == NULL)
        return DMERR_NULLPTR;

    memset(buf, 0, sizeof(DMGrowBuf));

    return DMERR_OK;
}


int dmGrowBufAlloc(DMGrowBuf *buf, const size_t initial, const size_t mingrow)
{
    int res;

    DM_DBG("dmGrowBufAlloc(%p, %" DM_PRIu_SIZE_T ", %" DM_PRIu_SIZE_T ")\n",
        buf, initial, mingrow);

    if ((res = dmGrowBufInit(buf)) != DMERR_OK)
        return res;

    buf->len  = 0;
    buf->offs = 0;
    buf->size = initial;
    buf->mingrow = mingrow;
    buf->backwards = FALSE;
    buf->is_const  = FALSE;

    // Allocate the data
    if ((buf->data = dmMalloc0(initial)) == NULL)
        return DMERR_MALLOC;

    return DMERR_OK;
}


void dmGrowBufFree(DMGrowBuf *buf)
{
    DM_DBG("dmGrowBufFree(%p)\n", buf);
    if (buf != NULL)
    {
        DM_DBG(
            "      buf->data       = %p\n"
            "      buf->is_const   = %s\n",
            buf->data,
            buf->is_const ? "YES" : "NO");

        if (buf->is_const)
            return;

        dmFree(buf->data);
        memset(buf, 0, sizeof(DMGrowBuf));
    }
}


DMGrowBuf * dmGrowBufCopy(DMGrowBuf *dst, const DMGrowBuf *src, const size_t enlarge)
{
    if (dst == NULL)
        return NULL;

    DM_DBG("dmGrowBufCopy(dst=%p, src=%p, enlarge=%" DM_PRIu_SIZE_T "):\n"
        "    data=%p, size=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T ", offs=%" DM_PRIu_SIZE_T "\n",
        dst, src, enlarge, src->data, src->size, src->len, src->offs);

    // Copy the struct here
    memcpy(dst, src, sizeof(DMGrowBuf));
    dst->size += enlarge;

    // Allocate new memory for the data
    if ((dst->data = dmMalloc(dst->size)) == NULL)
    {
        // If that fails, clear the struct
        memset(dst, 0, sizeof(DMGrowBuf));
        return NULL;
    }

    // Copy data
    memcpy(dst->data, src->data, src->size);
    if (enlarge > 0)
        memset(dst->data + src->size, 0, enlarge);

    // And reset some struct information
    dst->is_const = FALSE;

    return dst;
}


DMGrowBuf * dmGrowBufConstCopy(DMGrowBuf *dst, const DMGrowBuf *src)
{
    if (dst == NULL)
        return NULL;

    DM_DBG("dmGrowBufConstCopy(dst=%p, src=%p):\n"
        "    data=%p, size=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T ", offs=%" DM_PRIu_SIZE_T "\n",
        dst, src, src->data, src->size, src->len, src->offs);

    memcpy(dst, src, sizeof(DMGrowBuf));
    dst->is_const = TRUE;

    return dst;
}


DMGrowBuf * dmGrowBufConstCreateFrom(DMGrowBuf *dst, Uint8 *data, const size_t len)
{
    if (dmGrowBufInit(dst) != DMERR_OK)
        return NULL;

    DM_DBG("dmGrowBufConstCreateFrom(dst=%p, data=%p, len=%" DM_PRIu_SIZE_T ")\n",
        dst, data, len);

    dst->data = data;
    dst->len = dst->size = len;
    dst->is_const = TRUE;

    return dst;
}


DMGrowBuf * dmGrowBufConstCopyOffs(DMGrowBuf *dst, const DMGrowBuf *src, const size_t offs)
{
    return dmGrowBufConstCreateFrom(dst, src->data + offs, src->len - offs);
}


DMGrowBuf * dmGrowBufConstCopyOffsSize(DMGrowBuf *dst, const DMGrowBuf *src, const size_t offs, const size_t len)
{
    if (src->len < offs + len)
        return NULL;

    return dmGrowBufConstCreateFrom(dst, src->data + offs, len);
}


DMGrowBuf * dmGrowBufCopyOffs(DMGrowBuf *dst, const DMGrowBuf *src, const size_t offs, const size_t enlarge)
{
    DMGrowBuf tmp;
    return dmGrowBufCopy(dst,
        dmGrowBufConstCreateFrom(&tmp, src->data + offs, src->len - offs), enlarge);
}


DMGrowBuf * dmGrowBufCopyOffsSize(DMGrowBuf *dst, const DMGrowBuf *src, const size_t offs, const size_t len, const size_t enlarge)
{
    DMGrowBuf tmp;

    if (src->len < offs + len)
        return NULL;

    return dmGrowBufCopy(dst,
        dmGrowBufConstCreateFrom(&tmp, src->data + offs, len), enlarge);
}


static BOOL dmGrowBufRealloc(DMGrowBuf *buf, const size_t nsize, const BOOL clear)
{
    DM_DBG("dmGrowBufRealloc(%p):\n"
        "    size=%" DM_PRIu_SIZE_T ", nsize=%" DM_PRIu_SIZE_T
        ", offs=%" DM_PRIu_SIZE_T "\n",
        buf, buf->size, nsize, buf->offs);

    if (buf->is_const)
        return FALSE;

    // Can't be smaller than current size!
    if (nsize < buf->size)
        return FALSE;

    if ((buf->data = dmRealloc(buf->data, nsize)) == NULL)
        return FALSE;

    // For buffers growing backwards, we must move the
    // current data to the end of the buffer ..
    size_t clrsize = nsize - buf->size;
    DM_DBG("    clrsize=%" DM_PRIu_SIZE_T "\n", clrsize);
    if (buf->backwards)
    {
        memmove(buf->data + clrsize, buf->data, buf->size);
        buf->offs += clrsize;
    }

    // Check if we need to clear the newly allocated area?
    if (clear)
    {
        if (buf->backwards)
            memset(buf->data, 0, clrsize);
        else
            memset(buf->data + buf->size, 0, clrsize);
    }

    buf->size = nsize;

    return TRUE;
}


//
// Grow the buffer by "amount" bytes, but at least by buf->mingrow,
// if there is not enough space for at least that amount compared to
// current buffer "len".
//
BOOL dmGrowBufGrow(DMGrowBuf *buf, const size_t amount)
{
    size_t grow = (amount > buf->mingrow) ? amount : buf->mingrow;

    if (buf->is_const)
        return FALSE;

    if (buf->data == NULL ||
        (buf->backwards && amount >= buf->offs) ||
        (!buf->backwards && buf->offs + amount >= buf->size))
    {
        DM_DBG("dmGrowBufGrow(%p, amount=%" DM_PRIu_SIZE_T "): grow=%" DM_PRIu_SIZE_T "\n",
            buf, amount, grow);

        if (!dmGrowBufRealloc(buf, buf->size + grow, TRUE))
            return FALSE;
    }

    buf->len += amount;
    return TRUE;
}


//
// Grow the buffer if "nsize" is larger than the current buffer size.
// Buffer is enlarged to nsize + mingrow.
//
BOOL dmGrowBufCheckGrow(DMGrowBuf *buf, const size_t nsize)
{
    if (buf->is_const)
        return FALSE;

    if (buf->data == NULL || nsize > buf->size)
    {
        if (!dmGrowBufRealloc(buf, nsize + buf->mingrow, TRUE))
            return FALSE;
    }

    if (nsize > buf->len)
        buf->len = nsize;

    return TRUE;
}


BOOL dmGrowBufPut(DMGrowBuf *buf, const Uint8 *data, const size_t len)
{
    if (data == NULL)
        return FALSE;

    if (!dmGrowBufGrow(buf, len))
        return FALSE;

    if (buf->backwards)
    {
        if (buf->literal)
        {
            for (size_t n = 0; n < len; n++)
                buf->data[--buf->offs] = data[len - n];
        }
        else
        {
            for (size_t n = 0; n < len; n++)
                buf->data[--buf->offs] = data[n];
        }
    }
    else
    {
        memcpy(buf->data + buf->offs, data, len);
        buf->offs += len;
    }

    return TRUE;
}


BOOL dmGrowBufPutU8(DMGrowBuf *buf, const Uint8 value)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint8)))
        return FALSE;

    if (buf->backwards)
        buf->data[--buf->offs] = value;
    else
        buf->data[buf->offs++] = value;

    return TRUE;
}


BOOL dmGrowBufPutU16BE(DMGrowBuf *buf, const Uint16 val)
{
    if (buf->literal && buf->backwards)
    {
        return
            dmGrowBufPutU8(buf, val & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff);
    }
    else
    {
        return
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, val & 0xff);
    }
}


BOOL dmGrowBufPutU16LE(DMGrowBuf *buf, const Uint16 val)
{
    if (buf->literal && buf->backwards)
    {
        return
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, val & 0xff);
    }
    else
    {
        return
            dmGrowBufPutU8(buf, val & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff);
    }
}


BOOL dmGrowBufPutU32BE(DMGrowBuf *buf, const Uint32 val)
{
    if (buf->literal && buf->backwards)
    {
        return
            dmGrowBufPutU8(buf, (val >> 24) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 16) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, val & 0xff);
    }
    else
    {
        return
            dmGrowBufPutU8(buf, val & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 16) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 24) & 0xff);
    }
}


BOOL dmGrowBufPutU32LE(DMGrowBuf *buf, const Uint32 val)
{
    if (buf->literal && buf->backwards)
    {
        return
            dmGrowBufPutU8(buf, val & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 16) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 24) & 0xff);
    }
    else
    {
        return
            dmGrowBufPutU8(buf, (val >> 24) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 16) & 0xff) &&
            dmGrowBufPutU8(buf, (val >> 8) & 0xff) &&
            dmGrowBufPutU8(buf, val & 0xff);
    }
}


BOOL dmGrowBufGetU8(DMGrowBuf *buf, Uint8 *value)
{
    if (buf->backwards)
    {
        if (buf->offs > 0)
            *value = buf->data[--buf->offs];
        else
            return FALSE;
    }
    else
    {
        if (buf->offs < buf->len)
            *value = buf->data[buf->offs++];
        else
            return FALSE;
    }

    return TRUE;
}