# HG changeset patch # User Matti Hamalainen # Date 1527631627 -10800 # Node ID 415c732dc14c905119fec132b117d7e4d14f09ce # Parent 262300a0359bf9e60f91898cd52c7b01ba73df5a Implement support for packed TruePaint images. diff -r 262300a0359b -r 415c732dc14c tools/lib64fmts.c --- 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] }, {