Mercurial > hg > dmlib
diff tools/lib64gfx.c @ 1707:a0986cfd6f9d
More consistently use DMGrowBuf in the lib64gfx APIs, and implement
"backwards" RLE decoding and encoding (optionally regards input/output).
Not tested very much yet, there may be bugs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 05 Jun 2018 21:58:10 +0300 |
parents | 1036b0dcccb5 |
children | 1f0fac3af8e3 |
line wrap: on
line diff
--- a/tools/lib64gfx.c Tue Jun 05 19:57:08 2018 +0300 +++ b/tools/lib64gfx.c Tue Jun 05 21:58:10 2018 +0300 @@ -282,7 +282,7 @@ } -void dmGenericRLEAnalyze(const Uint8 *buf, const size_t len, DMCompParams *cfg) +void dmGenericRLEAnalyze(const DMGrowBuf *buf, DMCompParams *cfg) { #define DM_STAT_MAX 256 size_t *stats; @@ -292,8 +292,8 @@ return; // Get statistics on the data - for (size_t offs = 0; offs < len; offs++) - stats[buf[offs]]++; + for (size_t offs = 0; offs < buf->len; offs++) + stats[buf->data[offs]]++; // According to compression type .. switch (cfg->type) @@ -301,7 +301,7 @@ case DM_COMP_RLE_MARKER: { size_t selected = 0, - smallest = len; + smallest = buf->len; // Find least used byte value for (size_t n = 0; n < DM_STAT_MAX; n++) @@ -327,63 +327,83 @@ } -int dmDecodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) +static void dmSetupRLEBuffers(DMGrowBuf *dst, DMGrowBuf *src, const DMCompParams *cfg) +{ + if (cfg->flags & DM_RLE_BACKWARDS_INPUT) + { + src->offs = src->len - 1; + src->backwards = TRUE; + } + + if (cfg->flags & DM_RLE_BACKWARDS_OUTPUT) + { + dst->backwards = TRUE; + dst->offs = dst->size - 1; + } +} + + +int dmDecodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg) { int res; + Uint8 tmp1, tmp2, tmp3, data; + DMGrowBuf src; - // Perform RLE decode - while (src < srcEnd) + // As we need to modify the offs, etc. but not the data, + // we will just make a shallow copy of the DMGrowBuf struct + dmGrowBufConstCopy(&src, psrc); + dmSetupRLEBuffers(dst, &src, cfg); + + while (dmGrowBufGetU8(&src, &data)) { - Uint8 data = *src++; - int count = 1; + unsigned int count = 1; if (cfg->type == DM_COMP_RLE_MARKER) { // A simple marker byte RLE variant: [Marker] [count] [data] if (data == cfg->rleMarkerB && (cfg->flags & DM_RLE_BYTE_RUNS)) { - if (srcEnd - src + 1 < 2) + if (!dmGrowBufGetU8(&src, &tmp1) || + !dmGrowBufGetU8(&src, &tmp2)) { res = DMERR_INVALID_DATA; - goto err; + goto out; } - switch (cfg->flags & DM_RLE_ORDER_MASK) { case DM_RLE_ORDER_1: - count = src[0]; - data = src[1]; + count = tmp1; + data = tmp2; break; case DM_RLE_ORDER_2: - data = src[0]; - count = src[1]; + data = tmp1; + count = tmp2; break; } - src += 2; } else if (data == cfg->rleMarkerW && (cfg->flags & DM_RLE_WORD_RUNS)) { - if (srcEnd - src + 1 < 3) + if (!dmGrowBufGetU8(&src, &tmp1) || + !dmGrowBufGetU8(&src, &tmp2) || + !dmGrowBufGetU8(&src, &tmp3)) { res = DMERR_INVALID_DATA; - goto err; + goto out; } - switch (cfg->flags & DM_RLE_ORDER_MASK) { case DM_RLE_ORDER_1: - count = (src[1] << 8) | src[0]; - data = src[2]; + count = (tmp2 << 8) | tmp1; + data = tmp3; break; case DM_RLE_ORDER_2: - data = src[0]; - count = (src[2] << 8) | src[1]; + data = tmp1; + count = (tmp3 << 8) | tmp2; break; } - src += 3; } } else @@ -393,14 +413,14 @@ // and the lower bits contain the count: [Mask + count] [data] if ((data & cfg->rleMarkerMask) == cfg->rleMarkerBits) { - if (srcEnd - src + 1 < 1) + if (!dmGrowBufGetU8(&src, &tmp1)) { res = DMERR_INVALID_DATA; - goto err; + goto out; } count = data & cfg->rleCountMask; - data = *src++; + data = tmp1; } } @@ -409,29 +429,29 @@ if (!dmGrowBufPutU8(dst, data)) { res = DMERR_MALLOC; - goto err; + goto out; } } } res = DMERR_OK; -err: +out: return res; } -int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) +int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg) { int res; if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) return res; - return dmDecodeGenericRLE(dst, src, srcEnd, cfg); + return dmDecodeGenericRLE(dst, src, cfg); } -static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, int count, const DMCompParams *cfg) +static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, unsigned int count, const DMCompParams *cfg) { BOOL copyOnly = FALSE; @@ -514,14 +534,20 @@ } -int dmEncodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) +int dmEncodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg) { - // Perform RLE encoding - int count = 0, prev = -1; - while (src < srcEnd) + DMGrowBuf src; + unsigned int count = 0; + int prev = -1; + Uint8 data; + + // As we need to modify the offs, etc. but not the data, + // we will just make a shallow copy of the DMGrowBuf struct + dmGrowBufConstCopy(&src, psrc); + dmSetupRLEBuffers(dst, &src, cfg); + + while (dmGrowBufGetU8(&src, &data)) { - Uint8 data = *src++; - // If new data byte is different, or we exceed the rleMaxCount // for the active runs mode(s) .. then encode the run. if (data != prev || @@ -546,17 +572,17 @@ err: return dmError(DMERR_MALLOC, - "Could reallocate memory for RLE encoding buffer.\n"); + "Could not reallocate memory for RLE encoding buffer.\n"); } -int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) +int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg) { int res; if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) return res; - return dmEncodeGenericRLE(dst, src, srcEnd, cfg); + return dmEncodeGenericRLE(dst, src, cfg); } @@ -707,12 +733,11 @@ } -int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, - const size_t len, const DMC64ImageFormat *fmt) +int dmC64DecodeGenericBMP(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res = DMERR_OK; - if (buf == NULL || img == NULL || fmt == NULL) + if (buf == NULL || buf->data == NULL || img == NULL || fmt == NULL) return DMERR_NULLPTR; // Clear the image structure, set basics @@ -751,15 +776,16 @@ } // Is the operation inside the bounds? - if (op->offs + size > len + 1) + if (op->offs + size > buf->len + 1) { return dmError(DMERR_INVALID_DATA, "Decode DATA out of bounds, op #%d type=%d, subj=%d, offs=%d ($%04x), " "bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - i, op->type, op->subject, op->offs, op->offs, op->bank, size, size, len, len); + i, op->type, op->subject, op->offs, op->offs, op->bank, + size, size, buf->len, buf->len); } - src = buf + op->offs; + src = buf->data + op->offs; // Perform operation switch (op->type) @@ -781,7 +807,7 @@ return dmError(DMERR_MALLOC, "Could not allocate '%s' block! " "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - blkname, i, op->offs, op->offs, op->bank, size, size, len, len); + blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); } switch (op->type) { @@ -832,7 +858,7 @@ return dmError(DMERR_INTERNAL, "Unhandled subject %d in " "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - op->subject, i, op->offs, op->offs, op->bank, size, size, len, len); + op->subject, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); } break; @@ -854,7 +880,7 @@ return dmError(DMERR_INTERNAL, "Unhandled DO_CHAR_CFG mode %d in ", "op #%d, bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - op->subject, i, op->bank, size, size, len, len); + op->subject, i, op->bank, size, size, buf->len, buf->len); } break; @@ -864,14 +890,14 @@ return dmError(DMERR_INTERNAL, "Decode op is a function, but function ptr is NULL: " "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - i, op->offs, op->offs, op->bank, size, size, len, len); + i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); } - if (!op->decFunction(img, op, buf, len, fmt)) + if (!op->decFunction(img, op, buf, fmt)) { return dmError(DMERR_INTERNAL, "Decode op custom function failed: op #%d, " "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - i, op->offs, op->offs, op->bank, size, size, len, len); + i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); } break; } @@ -935,7 +961,7 @@ res = dmError(DMERR_INVALID_DATA, "Encode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), " "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n", - i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size); + i, op->type, op->offs, op->offs, op->bank, size, size, buf->size, buf->size); goto err; } @@ -949,9 +975,6 @@ goto err; } - if (chksize > buf->len) - buf->len = chksize; - // Perform operation Uint8 *dst = buf->data + buf->offs + op->offs; switch (op->type) @@ -967,35 +990,31 @@ case DS_CHAR_DATA: case DS_EXTRA_DATA: dmC64GetOpMemBlockAndName(img, op->subject, op->bank, &blk, &blkname); - if (blk->data == NULL) - { - res = dmError(DMERR_NULLPTR, - "'%s' block is NULL in " - "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); - goto err; - } - if (size > blk->size) - { - res = dmError(DMERR_INTERNAL, - "'%s' size mismatch %d <> %d in " - "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); - goto err; - } switch (op->type) { case DO_COPY: + if (blk->data == NULL) + { + res = dmError(DMERR_NULLPTR, + "'%s' block is NULL in " + "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", + blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); + goto err; + } + if (size > blk->size) + { + res = dmError(DMERR_INTERNAL, + "'%s' size mismatch %d <> %d in " + "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", + blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); + goto err; + } memcpy(dst, blk->data, size); break; case DO_SET_MEM: - // This operation makes no sense - res = dmError(DMERR_INTERNAL, - "'%s' block DO_SET_MEM (which makes no sense) in " - "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); - goto err; + // This operation makes no sense, so do nothing + break; case DO_SET_OP: memset(dst, op->offs, size); @@ -1026,12 +1045,8 @@ break; case DO_SET_OP: - // This operation makes no sense - res = dmError(DMERR_INTERNAL, - "'%s' block DO_SET_OP (which makes no sense) in " - "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", - blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); - goto err; + // Do nothing in this case + break; } break; @@ -1234,11 +1249,13 @@ } -int dmC64DecodeBMP(DMC64Image **img, const Uint8 *buf, const size_t len, +int dmC64DecodeBMP(DMC64Image **img, const DMGrowBuf *buf, const size_t probeOffs, const size_t loadOffs, const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced) { - if (img == NULL) + DMGrowBuf tmp; + + if (img == NULL || buf == NULL) return DMERR_NULLPTR; // Check for forced format @@ -1247,19 +1264,21 @@ else { // Nope, perform a generic probe - if (probeOffs >= len) + if (probeOffs >= buf->len) return DMERR_OUT_OF_DATA; - if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE) + dmGrowBufCreateFromOffs(&tmp, buf, probeOffs); + if (dmC64ProbeBMP(tmp.data, tmp.len, fmt) == DM_PROBE_SCORE_FALSE) return DMERR_NOT_SUPPORTED; } - if (loadOffs >= len) + if (loadOffs >= tmp.len) return DMERR_INVALID_ARGS; if (*fmt == NULL) return DMERR_NOT_SUPPORTED; + // Format supports only reading? if (((*fmt)->flags & DM_FMT_RD) == 0) return DMERR_NOT_SUPPORTED; @@ -1267,11 +1286,13 @@ if ((*img = dmC64ImageAlloc(*fmt)) == NULL) return DMERR_MALLOC; + dmGrowBufCreateFromOffs(&tmp, buf, loadOffs); + // Decode the bitmap to memory layout if ((*fmt)->decode != NULL) - return (*fmt)->decode(*img, buf + loadOffs, len - loadOffs, *fmt); + return (*fmt)->decode(*img, &tmp, *fmt); else - return dmC64DecodeGenericBMP(*img, buf + loadOffs, len - loadOffs, *fmt); + return dmC64DecodeGenericBMP(*img, &tmp, *fmt); }