changeset 2605:f5f03c5d9fd5

Implement EXON VHI Editor 0.1 packed format support.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 25 Nov 2023 06:06:18 +0200
parents 1c80099fe47e
children 92909caccc9e
files tools/lib64fmts.c
diffstat 1 files changed, 128 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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]);