# HG changeset patch # User Matti Hamalainen # Date 1700885178 -7200 # Node ID f5f03c5d9fd57b44f492ca481fe572b103737560 # Parent 1c80099fe47edb8e2da2cd4dc051d816f3ee4f21 Implement EXON VHI Editor 0.1 packed format support. diff -r 1c80099fe47e -r f5f03c5d9fd5 tools/lib64fmts.c --- a/tools/lib64fmts.c Sat Nov 25 06:04:23 2023 +0200 +++ b/tools/lib64fmts.c Sat Nov 25 06:06:18 2023 +0200 @@ -2202,6 +2202,126 @@ } +static const Uint8 fmtEXON_VHI_Packed_MagicID[] = +{ + 0x00, 0x00, 0x20, 0x16, 0x08, 0x09, 0x20, 0x05, + 0x04, 0x09, 0x14, 0x0f, 0x12, 0x20, 0x16, 0x30, + 0x2e, 0x31, 0x20, 0x20, 0x02, 0x19, 0x20, 0x16, + 0x0f, 0x0c, 0x03, 0x01, 0x0e, 0x0f, 0x2f, 0x05, + 0x18, 0x0f, 0x0e, 0x01, +}; + + +static int fmtProbeEXON_VHI_Packed(const DMGrowBuf *buf, const DMC64ImageFormat *fmt) +{ + if (buf->len > 200 && + dmCompareAddr16(buf, 0, fmt->addr)) + { + // This is a bit heavy-handed, but what can one do + for (size_t offs = 2; offs < buf->len - sizeof(fmtEXON_VHI_Packed_MagicID); offs++) + { + if (DM_MEMCMP_SIZE(buf->data + offs, fmtEXON_VHI_Packed_MagicID) == 0) + return DM_PROBE_SCORE_MAX; + } + } + + return DM_PROBE_SCORE_FALSE; +} + + +static int fmtDecodeEXON_VHI_Packed(DMC64Image *img, const DMGrowBuf *psrc, const DMC64ImageFormat *fmt) +{ + DMGrowBuf tmp; + Uint8 *dstBuf; + const size_t dstSize = fmt->size - 2; + size_t dstOffs = 0, srcOffs = 0; + int res; + + // Allocate output buffer + if ((dstBuf = dmMalloc0(dstSize)) == NULL) + { + return dmError(DMERR_MALLOC, + "EXON_VHI: Could not allocate memory for decoding buffer.\n"); + } + + while (srcOffs < psrc->len && dstOffs < dstSize) + { + // Get one byte of data + Uint8 data = psrc->data[srcOffs++]; + size_t ncount; + + if (data & 0x80) + { + // High bit means end of stream + break; + } + else + if (data == 0) + { + // Zero means literal run + if (srcOffs > psrc->len) + { + res = dmError(DMERR_INVALID_DATA, + "EXON_VHI: Literal sequence out of data.\n"); + goto out; + } + + ncount = psrc->data[srcOffs++]; + if (ncount == 0) + ncount = 256; + + if (srcOffs + ncount > psrc->len) + { + res = dmError(DMERR_INVALID_DATA, + "EXON_VHI: Literal sequence too long for source data.\n"); + goto out; + } + + if (dstOffs + ncount > dstSize) + { + res = dmError(DMERR_INVALID_DATA, + "EXON_VHI: Literal sequence too long for destination data.\n"); + goto out; + } + + for (size_t n = 0; n < ncount; n++) + dstBuf[dstOffs++] = psrc->data[srcOffs++]; + } + else + { + // RLE run + if (srcOffs + 2 > psrc->len) + { + res = dmError(DMERR_INVALID_DATA, + "EXON_VHI: Invalid data/out of data for RLE sequence.\n"); + goto out; + } + + ncount = psrc->data[srcOffs++]; + data = psrc->data[srcOffs++]; + if (ncount == 0) + ncount = 256; + + if (dstOffs + ncount > dstSize) + { + res = dmError(DMERR_INVALID_DATA, + "EXON_VHI: Invalid data/out of data for RLE sequence.\n"); + goto out; + } + + for (size_t n = 0; n < ncount; n++) + dstBuf[dstOffs++] = data; + } + } + + res = dmC64DecodeGenericBMP(img, dmGrowBufConstCreateFrom(&tmp, dstBuf, dstSize), fmt); + +out: + dmFree(dstBuf); + return res; +} + + static int fmtGetPixelEXON_VHI(DMC64ScanLine *scan, const DMC64Image *img, const int rasterX, const int rasterY) { @@ -3512,12 +3632,19 @@ }, { - "vhi", "EXON VHI Editor 0.1 (unpacked)", 0x2000, 17389, 0, DM_FMT_RD, + "vhi", "EXON VHI Editor 0.1 (unpacked)", 0x2000, 17389, 0, DM_FMT_RDWR, NULL, NULL, NULL, { 0 }, &dmC64CommonFormats[12] }, + { + "vhip", "EXON VHI Editor 0.1 (packed)", 0x2000, 17389, 0, DM_FMT_RD, + fmtProbeEXON_VHI_Packed, + fmtDecodeEXON_VHI_Packed, NULL, + { 0 }, &dmC64CommonFormats[12] + }, + }; const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);