changeset 2141:009ee261704c

Add somewhat broken support for decoding packed Cosmos Designs Hires Manager files. This format has a particularly buggy RLE+literal encoder.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 01 Jun 2019 03:56:05 +0300
parents b8491ee3cf24
children 894781b7310a
files tools/lib64fmts.c
diffstat 1 files changed, 88 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/tools/lib64fmts.c	Sat Jun 01 03:18:01 2019 +0300
+++ b/tools/lib64fmts.c	Sat Jun 01 03:56:05 2019 +0300
@@ -978,6 +978,87 @@
 }
 
 
+static int fmtDecodeCosmosDesignsHiresManagerPacked(DMC64Image *img, const DMGrowBuf *psrc, const DMC64ImageFormat *fmt)
+{
+    int res;
+    DMGrowBuf src, tmp;
+    DMCompParams cfg;
+    Uint8 data, count;
+    const size_t dstSize = 0x7ff2 - 0x4000;
+    size_t dstOffs;
+    Uint8 *dstBuf;
+    BOOL getByte = TRUE;
+
+    if ((dstBuf = dmMalloc0(dstSize)) == NULL)
+    {
+        return dmError(DMERR_MALLOC,
+            "Could not allocate memory for RLE decoding buffer.\n");
+    }
+
+    cfg.func         = fmt->name;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BACKWARDS_INPUT;
+
+    dmGrowBufConstCopy(&src, psrc);
+    dmSetupRLEBuffers(NULL, &src, &cfg);
+    dstOffs = dstSize;
+
+    while (dstOffs > 0 && src.offs > 0)
+    {
+        if (getByte && !dmGrowBufGetU8(&src, &data))
+        {
+            res = dmError(DMERR_INVALID_DATA,
+                "%s: RLE: Invalid data/out of data for literal sequence.\n",
+                cfg.func);
+            goto out;
+        }
+
+        // A simple marker byte RLE variant: [Marker] [count] [data]
+        if (data == 0)
+        {
+            if (!dmGrowBufGetU8(&src, &count) ||
+                !dmGrowBufGetU8(&src, &data))
+            {
+                res = dmError(DMERR_INVALID_DATA,
+                    "%s: RLE: Invalid data/out of data for run sequence.\n",
+                    cfg.func);
+                goto out;
+            }
+
+            int ncount = (int) count;
+            for (int n = 1; n < ncount && dstOffs > 0; n++)
+                dstBuf[--dstOffs] = data;
+
+            getByte = TRUE;
+        }
+        else
+        // Literal run of data bytes
+        {
+            int ncount = (int) data;
+            for (int n = 0; n < ncount; n++)
+            {
+                if (!dmGrowBufGetU8(&src, &data))
+                    break;
+
+                if (dstOffs > 0)
+                    dstBuf[--dstOffs] = data;
+                else
+                    break;
+            }
+            getByte = FALSE;
+        }
+    }
+
+    dmGrowBufConstCreateFrom(&tmp, dstBuf, 0x3fff);
+    res = dmC64DecodeGenericBMP(img, &tmp, fmt);
+
+out:
+    dmGrowBufFree(&src);
+    dmFree(dstBuf);
+    return res;
+}
+
+
 #define FUNPAINT2_HEADER_SIZE (0x10)
 static const char *fmtFunPaint2MagicID = "FUNPAINT (MT) ";
 
@@ -2184,6 +2265,13 @@
     },
 
     {
+        "cdhp", "Cosmos Designs Hires Manager (packed)", 0x4000, 0, DM_FMT_RD | DM_FMT_BROKEN,
+        fmtProbeCosmosDesignsHiresManager,
+        fmtDecodeCosmosDesignsHiresManagerPacked, NULL,
+        { }, &dmC64CommonFormats[8]
+    },
+
+    {
         "mrqp", "Marq's PETSCII editor (unpacked)", 0x0801, 0, DM_FMT_RD,
         fmtProbeMarqPETSCII,
         NULL, NULL,