Mercurial > hg > dmlib
view src/dmgrowbuf.c @ 1785:86d10d5d4915
Fix case where DMGrowBuf is growing backwards and needs to be reallocated in
dmGrowBufRealloc() and the data is moved to the "end" of the newly grown
buffer. Previously we used clrsize as data size, but that is (in retrospect)
obviously incorrect. Use old buffer size instead.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 13 Jun 2018 01:39:06 +0300 |
parents | a29d38862037 |
children | 0801fd0e26cb |
line wrap: on
line source
/* * DMLib * -- Growable buffer implementation * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2018 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; dmFreeR(&buf->data); } } 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, 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 * 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); } 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; } static void dmGrowBufUpdate(DMGrowBuf *buf) { if (buf->offs < buf->min_offs) buf->min_offs = buf->offs; if (buf->offs > buf->max_offs) buf->max_offs = buf->offs; } 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) { buf->offs -= len; memcpy(buf->data + buf->offs, data, len); } 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; } dmGrowBufUpdate(buf); return TRUE; } BOOL dmGrowBufPutU8(DMGrowBuf *buf, const Uint8 value) { if (!dmGrowBufGrow(buf, sizeof(Uint8))) return FALSE; buf->data[buf->offs] = value; if (buf->backwards) buf->offs--; else buf->offs++; dmGrowBufUpdate(buf); 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; }