diff tools/lib64fmts.c @ 1646:415c732dc14c

Implement support for packed TruePaint images.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 30 May 2018 01:07:07 +0300
parents 710961d02b8a
children 52cd979d63fd
line wrap: on
line diff
--- a/tools/lib64fmts.c	Wed May 30 00:57:21 2018 +0300
+++ b/tools/lib64fmts.c	Wed May 30 01:07:07 2018 +0300
@@ -309,6 +309,148 @@
 }
 
 
+static int fmtProbeTruePaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    // The beginning/un-changing part of the BASIC bootstrap and
+    // relocation of decompression code
+    static const Uint8 signature[] = {
+        0x0b, 0x08, 0x09, 0x00, 0x9e, 0x32, 0x30, 0x35,
+        0x39, 0x00, 0xa2, 0x00, 0x78, 0xbd, 0x1c, 0x08,
+        0x9d, 0xf5, 0x00, 0xe8, 0xd0, 0xf7, 0xe6, 0x01,
+        0x4c, 0x01, 0x01, 0xa5, 0xfe, 0xd0, 0x02, 0xc6,
+        0xff, 0xc6, 0xfe
+    };
+
+    if (len >= 512 && dmCompareAddr16(buf, 0, fmt->addr) &&
+        memcmp(buf + 2, signature, sizeof(signature)) == 0)
+        return DM_PROBE_SCORE_MAX;
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+//
+// Based on disassembly of the depacker routine. Encoding seems to be
+// some kind of "improved RLE" variant.
+//
+static int fmtDecodeTruePaintPacked(DMC64Image *img, const Uint8 *src, const size_t srcLen, const DMC64ImageFormat *fmt)
+{
+    int res = DMERR_OK;
+    Uint8 *dst = NULL;
+    const Uint8 *codeBook1, *codeBook2;
+    size_t
+        srcOffs, dstOffs,
+        dstLen  = 0x4be8;
+        // 1b7e-67e8 decoded by original depacker
+        // 1c00-67e8 is the actual area used tho
+
+    // Codebooks: #1 is trampoline table markers, #2 is RLE data table
+    codeBook1 = src + 0x81 - 2;
+    codeBook2 = src + 0x85 - 2;
+
+    // Allocate output buffer
+    if ((dst = dmMalloc0(dstLen)) == NULL)
+    {
+        res = dmError(DMERR_MALLOC,
+            "Could not allocate memory for temporary decompression buffer.\n");
+        goto out;
+    }
+
+    // Begin decompression
+    srcOffs = srcLen;
+    dstOffs = dstLen;
+
+    while (srcOffs > 0 && dstOffs > 0)
+    {
+        Uint8 data;
+        int count = 1, scount;
+        BOOL found = FALSE;
+
+        if (!dmReverseGetByte(src, &srcOffs, &data))
+        {
+            res = dmError(DMERR_INVALID_DATA,
+                "TruePaintRLE: Out of source data.\n");
+            goto out;
+        }
+
+        for (int n = 0; n < 8; n++)
+        if (codeBook1[n] == data && !found)
+        {
+            found = TRUE;
+            switch (n)
+            {
+                case 4: // Y = 4, JTO = $0B
+                    if (!dmReverseGetByte(src, &srcOffs, &data))
+                    {
+                        res = dmError(DMERR_INVALID_DATA,
+                            "TruePaintRLE: Y=4, JTO=$0B\n");
+                        goto out;
+                    }
+
+                    count = data;
+                    if (data == 0)
+                    {
+                        fprintf(stderr, "TruePaintRLE: BAILOUT\n");
+                        goto finish;
+                    }
+                    // NOTE: Intentional fall through here!
+
+                case 1: // Y = 1, JTO = $17
+                    count += 2;
+                    // NOTE: Intentional fallthrough here!
+
+                case 0: // Y = 0, JTO = $19
+                    if (!dmReverseGetByte(src, &srcOffs, &data))
+                    {
+                        res = dmError(DMERR_INVALID_DATA,
+                            "TruePaintRLE: Y=0, JTO=$19\n");
+                        goto out;
+                    }
+                    break;
+
+                case 2: // Y = 2, JTO = $07
+                    if (!dmReverseGetByte(src, &srcOffs, &data))
+                    {
+                        res = dmError(DMERR_INVALID_DATA,
+                            "foo: Y=2, JTO=$07\n");
+                        goto out;
+                    }
+                    count = data;
+                    // NOTE: Intentional fallthrough here!
+
+                case 3: // Y = 3, JTO = $0B
+                    count += 2;
+                    data   = 0;
+                    break;
+
+                default: // Y = [5..8], JTO = $00
+                    count++;
+                    data = codeBook2[n];
+                    break;
+            }
+        }
+
+        for (scount = count; count; count--)
+        {
+            if (!dmReversePutByte(dst, &dstOffs, data))
+            {
+                res = dmError(DMERR_INVALID_DATA,
+                    "TruePaintRLE: Out of output space for run: %d x $%02x!\n",
+                    scount, data);
+                goto out;
+            }
+        }
+    }
+
+finish:
+    res = dmC64DecodeGenericBMP(img, dst, dstLen, fmt);
+
+out:
+    dmFree(dst);
+    return res;
+}
+
+
 #define XX2_MIN_SIZE 4000
 
 static int fmtProbeFormatXX2(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
@@ -602,6 +744,18 @@
             { DT_ENC_FUNCTION, 0x2742, 0,  1, NULL, fmtDrazLaceSetLaceType },
             { DT_LAST,         0,      0,  0, NULL, NULL },
         },
+
+        {
+            // #6: TruePaint
+            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
+            { DT_COLOR_REG,    0x03e8, 0,  DC_BGCOL, NULL, NULL },
+            { DT_BITMAP_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_BITMAP_RAM,   0x2400, 1,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x4400, 1,  0, NULL, NULL },
+            { DT_COLOR_RAM,    0x4800, 0,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x0000, 0,  0, fmtTruePaintGetLaceType, NULL },
+            { DT_LAST,         0,      0,  0, NULL, NULL },
+        },
 };
 
 
@@ -698,17 +852,18 @@
         NULL, NULL,
         NULL, NULL,
         fmtGetPixelTruePaint,
-        {
-            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
-            { DT_COLOR_REG,    0x03e8, 0,  DC_BGCOL, NULL, NULL },
-            { DT_BITMAP_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_BITMAP_RAM,   0x2400, 1,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x4400, 1,  0, NULL, NULL },
-            { DT_COLOR_RAM,    0x4800, 0,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x0000, 0,  0, fmtTruePaintGetLaceType, NULL },
-            { DT_LAST,         0,      0,  0, NULL, NULL },
-        },
-        NULL
+        { }, &dmC64CommonFormatOps[6]
+    },
+
+    {
+        D64_FMT_MC | D64_FMT_ILACE, "mcip", "Truepaint (packed)", 0x0801, 0, DM_FMT_RD,
+        C64_SCR_WIDTH   , C64_SCR_HEIGHT,
+        C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT,
+        fmtProbeTruePaintPacked,
+        fmtDecodeTruePaintPacked, NULL,
+        NULL, NULL,
+        fmtGetPixelTruePaint,
+        { }, &dmC64CommonFormatOps[6]
     },
 
     {