view tools/lib64util.c @ 2383:43e39d9ec42f

Add __attribute__(__format__ ..) specifiers for functions that use printf() style format specifiers.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 09 Jan 2020 14:55:41 +0200
parents 89cb93184175
children 5ffc48a0bebe
line wrap: on
line source

/*
 * Common utility functions for gfxconv and 64vw
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2019-2020 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#include "lib64util.h"
#include "dmfile.h"


//
// Some common C64 palettes
//
DMC64Palette dmC64DefaultPalettes[] =
{
    {
        "pepto",
        "Pepto's classic (default)",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xFF, 0xFF, 0xFF, 0xff },
            { 0x68, 0x37, 0x2B, 0xff },
            { 0x70, 0xA4, 0xB2, 0xff },
            { 0x6F, 0x3D, 0x86, 0xff },
            { 0x58, 0x8D, 0x43, 0xff },
            { 0x35, 0x28, 0x79, 0xff },
            { 0xB8, 0xC7, 0x6F, 0xff },
            { 0x6F, 0x4F, 0x25, 0xff },
            { 0x43, 0x39, 0x00, 0xff },
            { 0x9A, 0x67, 0x59, 0xff },
            { 0x44, 0x44, 0x44, 0xff },
            { 0x6C, 0x6C, 0x6C, 0xff },
            { 0x9A, 0xD2, 0x84, 0xff },
            { 0x6C, 0x5E, 0xB5, 0xff },
            { 0x95, 0x95, 0x95, 0xff },
        },
    },
    {
        "colodore",
        "Colodore",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xff, 0xff, 0xff, 0xff },
            { 0x96, 0x28, 0x2e, 0xff },
            { 0x5b, 0xd6, 0xce, 0xff },
            { 0x9f, 0x2d, 0xad, 0xff },
            { 0x41, 0xb9, 0x36, 0xff },
            { 0x27, 0x24, 0xc4, 0xff },
            { 0xef, 0xf3, 0x47, 0xff },
            { 0x9f, 0x48, 0x15, 0xff },
            { 0x5e, 0x35, 0x00, 0xff },
            { 0xda, 0x5f, 0x66, 0xff },
            { 0x47, 0x47, 0x47, 0xff },
            { 0x78, 0x78, 0x78, 0xff },
            { 0x91, 0xff, 0x84, 0xff },
            { 0x68, 0x64, 0xff, 0xff },
            { 0xae, 0xae, 0xae, 0xff },
        },
    },
    {
        "vice3",
        "VICE 3.3",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xfd, 0xfe, 0xfc, 0xff },
            { 0xbe, 0x1a, 0x24, 0xff },
            { 0x30, 0xe6, 0xc6, 0xff },
            { 0xb4, 0x1a, 0xe2, 0xff },
            { 0x1f, 0xd2, 0x1e, 0xff },
            { 0x21, 0x1b, 0xae, 0xff },
            { 0xdf, 0xf6, 0x0a, 0xff },
            { 0xb8, 0x41, 0x04, 0xff },
            { 0x6a, 0x33, 0x04, 0xff },
            { 0xfe, 0x4a, 0x57, 0xff },
            { 0x42, 0x45, 0x40, 0xff },
            { 0x70, 0x74, 0x6f, 0xff },
            { 0x59, 0xfe, 0x59, 0xff },
            { 0x5f, 0x53, 0xfe, 0xff },
            { 0xa4, 0xa7, 0xa2, 0xff },
        },
    },
};

const int ndmC64DefaultPalettes = sizeof(dmC64DefaultPalettes) / sizeof(dmC64DefaultPalettes[0]);


char * dmC64GetImageTypeString(char *buf, const size_t len, const int type, const BOOL lng)
{
    static const char *fmtModesShort[] = { "*", "HiR", "MC", "ECM" };
    static const char *fmtModesLong[] = { "*", "Hires", "Multi-color", "Extended Color Mode" };
    const char *fmtStr;
    size_t nfmt = type & D64_FMT_MODE_MASK;

    if (nfmt < sizeof(fmtModesShort) / sizeof(fmtModesShort[0]))
        fmtStr = lng ? fmtModesLong[nfmt] : fmtModesShort[nfmt];
    else
        fmtStr = lng ? "ERROR" : "ERR";

    snprintf(buf, len,
        "%s %s%s%s%s",
        fmtStr,
        (type & D64_FMT_ILACE) ? (lng ? "interlaced " : "ILace ") : "",
        (type & D64_FMT_FLI)   ? "FLI " : "",
        (type & D64_FMT_CHAR)  ? (lng ? "char-mode" : "CHAR") : "",
        (type & D64_FMT_SPRITES)  ? (lng ? "+ sprite-layer" : "SPR") : ""
        );

    return buf;
}


__attribute__ ((__format__ (__printf__, 4, 5)))
static void dmC64ImageDumpLine(FILE *fh, const char *indent, const char *field, const char *fmt, ...)
{
    va_list ap;

    fputs(indent, fh);
    fprintf(fh, "%-20s: ", field);
    va_start(ap, fmt);
    vfprintf(fh, fmt, ap);
    va_end(ap);
    fputs("\n", fh);
}


void dmC64ImageDump(FILE *fh, const DMC64Image *img, const DMC64ImageFormat *fmt, const char *indent)
{
    char typeStr[64];

    if (fmt != NULL)
    {
        dmC64ImageDumpLine(fh, indent,
            "Format", "%s [%s]",
            fmt->name, fmt->fext);
    }

    if (img != NULL)
    {
        dmC64GetImageTypeString(typeStr, sizeof(typeStr), img->extraInfo[D64_EI_MODE], TRUE);

        dmC64ImageDumpLine(fh, indent,
            "Type", "%s", typeStr);

        dmC64ImageDumpLine(fh, indent,
            "Internal blocks", "%d", img->nblocks);

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_ILACE)
        {
            char *tmps;
            switch (img->extraInfo[D64_EI_ILACE_TYPE])
            {
                case D64_ILACE_COLOR: tmps = "color"; break;
                case D64_ILACE_RES: tmps = "resolution"; break;
                default: tmps = "ERROR"; break;
            }
            dmC64ImageDumpLine(fh, indent,
                "Interlace type", "%s", tmps);
        }

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_FLI)
        {
            dmC64ImageDumpLine(fh, indent,
                "FLI type", "%d",
                img->extraInfo[D64_EI_FLI_TYPE]);
        }

        dmC64ImageDumpLine(fh, indent,
            "Width x Height", "%d x %d pixels",
            img->fmt->width, img->fmt->height);

        dmC64ImageDumpLine(fh, indent,
            "CHwidth x CHheight", "%d x %d",
            img->fmt->chWidth, img->fmt->chHeight);

        dmC64ImageDumpLine(fh, indent,
            "d020 / border", "%d ($%02x)",
            img->d020, img->d020);

        dmC64ImageDumpLine(fh, indent,
            "d021 / background", "%d ($%02x)",
            img->bgcolor, img->bgcolor);

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_CHAR)
        {
            if ((img->extraInfo[D64_EI_MODE] & D64_FMT_MODE_MASK) == (D64_FMT_MC | D64_FMT_ECM))
            {
                dmC64ImageDumpLine(fh, indent,
                    "d022", "%d ($%02x)",
                    img->d022, img->d022);
                dmC64ImageDumpLine(fh, indent,
                    "d023", "%d ($%02x)",
                    img->d023, img->d023);
            }

            if ((img->extraInfo[D64_EI_MODE] & D64_FMT_MODE_MASK) == D64_FMT_ECM)
            {
                dmC64ImageDumpLine(fh, indent,
                    "d024", "%d ($%02x)",
                    img->d024, img->d024);
            }
        }
    }
    else
    if (fmt != NULL)
    {
        dmC64GetImageTypeString(typeStr, sizeof(typeStr), fmt->format->mode, TRUE);

        dmC64ImageDumpLine(fh, indent,
            "Type", "%s", typeStr);

        dmC64ImageDumpLine(fh, indent,
            "Width x Height", "%d x %d pixels",
            fmt->format->width, fmt->format->height);

        dmC64ImageDumpLine(fh, indent,
            "CHwidth x CHheight", "%d x %d",
            fmt->format->chWidth, fmt->format->chHeight);
    }
}


void argShowC64Formats(FILE *fh, const BOOL rw)
{
    fprintf(fh,
        "Available C64 bitmap formats (-f <frmt>):\n"
        " frmt %s| Type            | Description\n"
        "------%s+-----------------+-------------------------------------\n",
        rw ? "| RW " : "",
        rw ? "+----" : ""
        );

    for (int i = 0; i < ndmC64ImageFormats; i++)
    {
        const DMC64ImageFormat *fmt = dmC64ImageFormatsSorted[i];
        char buf[64];

        fprintf(fh, "%-6s",
            fmt->fext);

        if (rw)
        {
            fprintf(fh, "| %c%c ",
                (fmt->flags & DM_FMT_RD) ? 'R' : ' ',
                (fmt->flags & DM_FMT_WR) ? 'W' : ' '
                );
        }

        fprintf(fh,
            "| %-15s | %s%s\n",
            dmC64GetImageTypeString(buf, sizeof(buf), fmt->format->mode, FALSE),
            fmt->name,
            fmt->flags & DM_FMT_BROKEN ? " [BROKEN]" : "");
    }

    fprintf(fh, "%d formats supported.\n", ndmC64ImageFormats);
}


void argShowC64PaletteHelp(FILE *fh)
{
    fprintf(fh,
        "\n"
        "Available internal C64 palettes (-p <name>):\n"
        "--------------------------------------------\n");

    for (int n = 0; n < ndmC64DefaultPalettes; n++)
    {
        DMC64Palette *pal = &dmC64DefaultPalettes[n];
        fprintf(fh,
            "%-10s | %s\n",
            pal->name, pal->desc);
    }

    fprintf(fh,
        "\n"
        "Instead of using one of the internal palettes,\n"
        "you can specify an external palette file.\n"
        "\n"
        "Supported palette file formats are:\n"
        "-----------------------------------\n"
        );

    for (int n = 0; n < ndmPaletteFormatList; n++)
    {
        const DMPaletteFormat *fmt = &dmPaletteFormatList[n];
        if (fmt->flags & DM_FMT_RD)
        {
            fprintf(fh,
                "%-6s | %s\n",
                fmt->fext, fmt->name);
        }
    }
    fprintf(fh,
        "\n"
        "Example: -p foobar.bin\n"
        "\n");
}


BOOL argHandleC64PaletteOption(char *optArg, DMC64Palette **ppal, char **palFile)
{
    if (strcasecmp(optArg, "help") == 0 ||
        strcasecmp(optArg, "list") == 0)
    {
        argShowC64PaletteHelp(stdout);
        return FALSE;
    }

    for (int n = 0; n < ndmC64DefaultPalettes; n++)
    {
        DMC64Palette *pal = &dmC64DefaultPalettes[n];
        if (strcasecmp(pal->name, optArg) == 0)
        {
            *ppal = pal;
            return TRUE;
        }
    }

    *palFile = optArg;
    return TRUE;
}


int dmHandleExternalPalette(const char *filename, DMPalette **ppal)
{
    DMResource *fh = NULL;
    const DMImageFormat *ifmt = NULL;
    const DMPaletteFormat *pfmt = NULL;
    DMImage *inImage = NULL;
    Uint8 *dataBuf = NULL;
    size_t dataSize;
    int index, res;

    dmMsg(1, "Probing file '%s' for palette data.\n", filename);

    if ((res = dmReadDataFile(NULL, filename, &dataBuf, &dataSize)) != DMERR_OK)
    {
        dmErrorMsg("No such palette '%s', and no such file found (%s).\n",
            filename, dmErrorStr(res));
        goto done;
    }

    if ((res = dmf_open_memio(NULL, filename, dataBuf, dataSize, &fh)) != DMERR_OK)
    {
        dmErrorMsg("Could not create MemIO handle for input.\n");
        goto done;
    }

    if (dmImageProbeGeneric(dataBuf, dataSize, &ifmt, &index) > 0 &&
        ifmt->read != NULL)
    {
        dmMsg(1, "Probed image format %s (%s)\n",
            ifmt->name, ifmt->fext);

        res = ifmt->read(fh, &inImage);
        if (res != DMERR_OK)
        {
            dmErrorMsg("Could not read image file: %s\n",
                dmErrorStr(res));
            goto done;
        }

        if (inImage->pal != NULL)
            res = dmPaletteCopy(ppal, inImage->pal);
        else
        {
            dmErrorMsg("Image file does not have a palette.\n");
            res = DMERR_NULLPTR;
        }
    }
    else
    if (dmPaletteProbeGeneric(dataBuf, dataSize, &pfmt, &index) > 0 &&
        pfmt->read != NULL)
    {
        dmMsg(1, "Probed palette format %s (%s)\n",
            pfmt->name, pfmt->fext);

        res = pfmt->read(fh, ppal);
    }
    else
    {
        res = DMERR_NOT_SUPPORTED;
        dmErrorMsg("Not an internal palette or recognized palette file '%s'.\n",
            filename);
    }

done:
    dmf_close(fh);
    dmImageFree(inImage);
    dmFree(dataBuf);

    return res;
}