changeset 2519:4dbb6572622d

Add preliminary decoder for SupeRes hires and multicolor files. The decoder is pretty horrible at the moment, should be cleaned up.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 15 May 2020 02:46:53 +0300
parents 470631c00c97
children 4e7d9fd9b7e4
files tools/lib64fmts.c
diffstat 1 files changed, 234 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/tools/lib64fmts.c	Tue May 12 20:49:12 2020 +0300
+++ b/tools/lib64fmts.c	Fri May 15 02:46:53 2020 +0300
@@ -63,6 +63,213 @@
 }
 
 
+static const Uint8 fmtSupeRes_MagicID_1[] =
+{
+    0x40, 0x5c, 0x2a,
+};
+
+
+static int fmtProbeSupeRes(const DMGrowBuf *buf, const DMC64ImageFormat *fmt)
+{
+    if (buf->len > 12 &&
+        DM_MEMCMP_SIZE(buf->data, fmtSupeRes_MagicID_1) == 0)
+    {
+        if (buf->data[3] == fmt->size)
+            return DM_PROBE_SCORE_MAX;
+    }
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+typedef struct
+{
+    DMGrowBuf src;
+    Uint8 *dstBuf;
+    size_t dstSize;
+
+    Uint8 dbyte, repcount;
+
+    size_t offs, end_offs;
+} DMSupeResCtx;
+
+
+static int fmtSupeResGetByte(DMSupeResCtx *ctx, Uint8 *data, const int mode)
+{
+    if (!dmGrowBufGetU8(&ctx->src, data))
+    {
+        return dmError(DMERR_INVALID_DATA,
+            "SupeRes: Out of input data (N=%d).\n",
+            mode);
+    }
+    else
+    {
+        return DMERR_OK;
+    }
+}
+
+
+static int fmtDecodeSupeResByte(DMSupeResCtx *ctx)
+{
+    Uint8 tmp;
+    int res;
+
+lcont:
+
+    if ((res = fmtSupeResGetByte(ctx, &tmp, 1)) != DMERR_OK)
+        goto out;
+
+    if (tmp == 0x21)
+    {
+        // ????
+        ctx->offs = 0xffff;
+        return DMERR_OK;
+    }
+    else
+    if (tmp == 0x24)
+    {
+        ctx->dbyte = 0xff;
+        return DMERR_OK;
+    }
+    else
+    if (tmp == 0x20)
+    {
+        if ((res = fmtSupeResGetByte(ctx, &tmp, 2)) != DMERR_OK)
+            goto out;
+
+        ctx->repcount = tmp - 0x26;
+
+        if ((res = fmtSupeResGetByte(ctx, &tmp, 3)) != DMERR_OK)
+            goto out;
+
+        if (tmp == 0x24)
+        {
+            ctx->dbyte = 0xff;
+        }
+        else
+        {
+            if (tmp == 0x25)
+            {
+                if ((res = fmtSupeResGetByte(ctx, &tmp, 4)) != DMERR_OK)
+                    goto out;
+
+                tmp = (0x26 + tmp) & 0xff;
+            }
+
+            ctx->dbyte = tmp - 0x26;
+        }
+
+        for (int cnt = 0; cnt < ctx->repcount; cnt++)
+        {
+            ctx->dstBuf[ctx->offs++] = ctx->dbyte;
+            if (ctx->offs >= ctx->end_offs)
+                goto out;
+        }
+
+        if (ctx->offs < ctx->end_offs)
+            goto lcont;
+
+        ctx->offs--;
+
+        goto out;
+    }
+    else
+    {
+        if (tmp == 0x25)
+        {
+            if ((res = fmtSupeResGetByte(ctx, &tmp, 9)) != DMERR_OK)
+                goto out;
+
+            tmp = (0x26 + tmp) & 0xff;
+        }
+
+        ctx->dbyte = tmp - 0x26;
+
+        return DMERR_OK;
+    }
+
+    goto lcont;
+
+out:
+    return res;
+}
+
+
+static int fmtDecodeSupeResSection(DMSupeResCtx *ctx, const size_t offs, const size_t size)
+{
+    int res = DMERR_OK;
+
+    ctx->offs = offs;
+    ctx->end_offs = offs + size;
+
+    do
+    {
+        if ((res = fmtDecodeSupeResByte(ctx)) != DMERR_OK)
+            goto out;
+
+        if (ctx->offs < ctx->end_offs)
+            ctx->dstBuf[ctx->offs++] = ctx->dbyte;
+
+    } while (ctx->offs < ctx->end_offs);
+
+out:
+    return res;
+}
+
+
+static int fmtDecodeSupeRes(DMC64Image *img, const DMGrowBuf *psrc, const DMC64ImageFormat *fmt)
+{
+    DMSupeResCtx ctx;
+    DMGrowBuf tmp;
+    int res;
+
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.dstSize = 0x4000;
+
+    // As we need to modify the offs, etc. but not the data,
+    // we will just make a shallow copy of the DMGrowBuf struct
+    dmGrowBufConstCopyOffs(&ctx.src, psrc, 4);
+
+    // Allocate output buffer
+    if ((ctx.dstBuf = dmMalloc0(ctx.dstSize)) == NULL)
+    {
+        return dmError(DMERR_MALLOC,
+            "Could not allocate memory for decoding buffer.\n");
+    }
+
+    switch (fmt->size)
+    {
+        case 0x23:
+        case 0x25:
+            if ((res = fmtDecodeSupeResSection(&ctx, 0x0000, 0x03e8)) != DMERR_OK ||
+                (res = fmtDecodeSupeResSection(&ctx, 0x0400, 0x1f40)) != DMERR_OK)
+                goto out;
+            break;
+
+        case 0x24:
+        case 0x26:
+            if ((res = fmtDecodeSupeResByte   (&ctx)) != DMERR_OK)
+                goto out;
+
+            ctx.dstBuf[0x2710] = ctx.dbyte;
+
+            if ((res = fmtDecodeSupeResSection(&ctx, 0x1f40, 0x03e8)) != DMERR_OK ||
+                (res = fmtDecodeSupeResSection(&ctx, 0x2328, 0x03e8)) != DMERR_OK ||
+                (res = fmtDecodeSupeResSection(&ctx, 0x0000, 0x1f40)) != DMERR_OK)
+                goto out;
+
+            break;
+    }
+
+    res = dmC64DecodeGenericBMP(img,
+        dmGrowBufConstCreateFrom(&tmp, ctx.dstBuf, ctx.dstSize), fmt);
+
+out:
+    dmFree(ctx.dstBuf);
+    return res;
+}
+
+
 static const Uint8 fmtMarqPETSCII_ID1[] =
 {
     0x01, 0x08, 0x0b, 0x08, 0xef, 0x00, 0x9e, 0x32, 0x30, 0x36,
@@ -2874,6 +3081,33 @@
         NULL
     },
 
+    {
+        "suphi1", "SupeRes hires [clear] (packed)", -1, 0x23, DM_FMT_RD,
+        fmtProbeSupeRes,
+        fmtDecodeSupeRes, NULL,
+        { }, &dmC64CommonFormats[10]
+    },
+
+    {
+        "suphi2", "SupeRes hires [no-clear] (packed)", -1, 0x25, DM_FMT_RD,
+        fmtProbeSupeRes,
+        fmtDecodeSupeRes, NULL,
+        { }, &dmC64CommonFormats[10]
+    },
+
+    {
+        "supmc1", "SupeRes multicolor [clear] (packed)", -1, 0x24, DM_FMT_RD,
+        fmtProbeSupeRes,
+        fmtDecodeSupeRes, NULL,
+        { }, &dmC64CommonFormats[0]
+    },
+
+    {
+        "supmc2", "SupeRes multicolor [no-clear] (packed)", -1, 0x26, DM_FMT_RD,
+        fmtProbeSupeRes,
+        fmtDecodeSupeRes, NULL,
+        { }, &dmC64CommonFormats[0]
+    },
 };
 
 const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);