changeset 652:d9888292f971

Rename again.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 16 Apr 2013 06:04:22 +0300
parents e2ac08228a0f
children 469119cab5b2
files tools/data2inc.c tools/gentab.c tools/gfxconv.c tools/mod2wav.c tools/objlink.c tools/packed.c tools/ppl.c tools/svg2qd.py tools/view64.c tools/viewmod.c tools/xm2jss.c utils/data2inc.c utils/gentab.c utils/gfxconv.c utils/mod2wav.c utils/objlink.c utils/packed.c utils/ppl.c utils/svg2qd.py utils/view64.c utils/viewmod.c utils/xm2jss.c
diffstat 22 files changed, 7004 insertions(+), 7004 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/data2inc.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,404 @@
+/*
+ * data2inc - Convert binary data to "C"-source or XA-compatible include file
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include <errno.h>
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmmutex.h"
+
+#define RA_LINEBUF    (16)
+
+enum
+{
+    FMT_AUTO = 0,
+    FMT_C,
+    FMT_ASM
+};
+
+char    *optInFilename = NULL,
+        *optOutFilename = NULL,
+        *optObjName = "default_object",
+        *optDataType = NULL,
+        *optAddLine = NULL;
+
+int     optIndentation = -1;
+int     optFormat = FMT_AUTO;
+BOOL    optHexMode = FALSE,
+        optQuiet = FALSE,
+        optExtraData = FALSE,
+        optFormatting = TRUE;
+
+
+void (*writeHeader) (FILE *, char *) = NULL;
+void (*writeDecl) (FILE *, size_t, char *) = NULL;
+void (*writeData) (FILE *, Uint8 *, size_t) = NULL;
+void (*writeFooter) (FILE *, size_t, char *) = NULL;
+
+
+static DMOptArg optList[] =
+{
+    {  0, '?', "help",           "Show this help", OPT_NONE },
+    {  4, 'A', "format-asm",     "Output in XA-compatible asm", OPT_NONE },
+    {  5, 'C', "format-c",       "Output in ANSI C", OPT_NONE },
+    {  1, 'n', "name",           "Set object name", OPT_ARGREQ },
+    {  2, 't', "type",           "Set datatype (unsigned char/byte)", OPT_ARGREQ },
+    {  3, 'a', "add-line",       "Add this line to start of file", OPT_ARGREQ },
+    {  6, 'x', "hexadecimal",    "Use hexadecimal output", OPT_NONE },
+    {  7, 'q', "quiet",          "Do not add comments", OPT_NONE },
+    {  8, 'f', "no-formatting",  "Disable additional output formatting", OPT_NONE },
+    {  9, 'i', "indentation",    "Set indentation (negative value = tab)", OPT_ARGREQ },
+    { 10, 'e', "extra-data",     "Add object end labels and size in asm output", OPT_NONE },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName,
+        "[options] [sourcefile] [destfile]");
+
+    dmArgsPrintHelp(stdout, optList, optListN);
+    
+    printf(
+    "\n"
+    "To convert a data file to a C structure using 'Uint8' as type:\n"
+    "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n"
+    "\n"
+    );
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            optObjName = optArg;
+            break;
+
+        case 2:
+            optDataType = optArg;
+            break;
+
+        case 3:
+            optAddLine = optArg;
+            break;
+
+        case 4:
+            optFormat = FMT_ASM;
+            break;
+        case 5:
+            optFormat = FMT_C;
+            break;
+        case 6:
+            optHexMode = TRUE;
+            break;
+        case 7:
+            optQuiet = TRUE;
+            break;
+        case 8:
+            optFormatting = FALSE;
+            break;
+
+        case 9:
+            optIndentation = atoi(optArg);
+            break;
+
+        case 10:
+            optExtraData = TRUE;
+            break;
+
+        default:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char * currArg)
+{
+    if (!optInFilename)
+        optInFilename = currArg;
+    else
+    if (!optOutFilename)
+        optOutFilename = currArg;
+    else
+        dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg);
+
+    return TRUE;
+}
+
+
+/* Assembler include data output functions
+ */
+void writeHeader_ASM(FILE * f, char *name)
+{
+    if (name)
+        fprintf(f, "; '%s'", name);
+    else
+        fprintf(f, "; Generated");
+    fprintf(f, " by %s v%s\n",
+        dmProgName, dmProgVersion);
+}
+
+void writeDecl_ASM(FILE * f, size_t len, char *name)
+{
+    if (optExtraData)
+        fprintf(f, "%s_size = %u\n", name, len);
+    fprintf(f, "%s:\n", name);
+}
+
+void writeData_ASM(FILE * f, Uint8 * buf, size_t len)
+{
+    size_t i;
+
+    fprintf(f, "%s ", optDataType);
+    for (i = 0; i < len; i++)
+    {
+        if (optFormatting)
+        {
+            if (optHexMode)
+                fprintf(f, "$%.2x", buf[i]);
+            else
+                fprintf(f, "%3d", buf[i]);
+        }
+        else
+        {
+            if (optHexMode)
+                fprintf(f, "$%x", buf[i]);
+            else
+                fprintf(f, "%d", buf[i]);
+        }
+
+        if (i < (len - 1))
+            fprintf(f, ",");
+    }
+}
+
+void writeFooter_ASM(FILE * f, size_t len, char *name)
+{
+    (void) len;
+    if (optExtraData)
+        fprintf(f, "%s_end: \n", name);
+    else
+        fprintf(f, "\n");
+}
+
+
+/* ANSI-C include data output functions
+ */
+void writeHeader_C(FILE * f, char *name)
+{
+    if (name)
+        fprintf(f, "/* '%s' generated", name);
+    else
+        fprintf(f, "/* Generated");
+
+    fprintf(f, " by %s v%s\n" " */\n",
+        dmProgName, dmProgVersion);
+}
+
+void writeDecl_C(FILE * f, size_t len, char *name)
+{
+    fprintf(f, "%s %s[%u] = {\n",
+        optDataType, name, len);
+
+    printf("extern %s %s[%u];\n",
+        optDataType, name, len);
+}
+
+void writeData_C(FILE * f, Uint8 * buf, size_t len)
+{
+    size_t i;
+
+    for (i = 0; i < len; i++)
+    {
+        if (optFormatting)
+        {
+            if (optHexMode)
+                fprintf(f, "0x%.2x", buf[i]);
+            else
+                fprintf(f, "%3d", buf[i]);
+        }
+        else
+        {
+            if (optHexMode)
+                fprintf(f, "0x%x", buf[i]);
+            else
+                fprintf(f, "%d", buf[i]);
+        }
+
+        fprintf(f, ",");
+    }
+}
+
+void writeFooter_C(FILE * f, size_t len, char *name)
+{
+    (void) len;
+    (void) name;
+    fprintf(f, "};\n");
+}
+
+
+off_t dmGetFileSize(FILE *f)
+{
+    off_t len, pos = ftell(f);
+    fseeko(f, 0, SEEK_END);
+    len = ftell(f);
+    fseek(f, pos, SEEK_SET);
+    return len;
+}
+
+
+int main(int argc, char *argv[])
+{
+    FILE *sfile = NULL, *dfile = NULL;
+    off_t inSize;
+    Uint8 inBuf[RA_LINEBUF];
+    int tmpRes;
+
+    /* Initialize */
+    dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL);
+    dmVerbosity = 0;
+
+    /* Parse arguments */
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    /* Determine output type, if not specified */
+    if (optFormat == FMT_AUTO)
+    {
+        char *dext;
+
+        if (optOutFilename == NULL)
+        {
+            dmError("Output format not specified and no output filename given (try --help)\n");
+            exit(1);
+        }
+
+        /* Check filename extension */
+        dext = strrchr(optOutFilename, '.');
+        if (dext)
+        {
+            dext++;
+            if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") ||
+                !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") ||
+                !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++"))
+                optFormat = FMT_C;
+            else
+                optFormat = FMT_ASM;
+        } else
+            optFormat = FMT_ASM;
+    }
+
+    /* Set functions */
+    switch (optFormat)
+    {
+        case FMT_ASM:
+            if (!optDataType)
+                optDataType = ".byte";
+
+            writeHeader = writeHeader_ASM;
+            writeDecl = writeDecl_ASM;
+            writeData = writeData_ASM;
+            writeFooter = writeFooter_ASM;
+            break;
+
+        case FMT_C:
+            if (!optDataType)
+                optDataType = "unsigned char";
+
+            writeHeader = writeHeader_C;
+            writeDecl = writeDecl_C;
+            writeData = writeData_C;
+            writeFooter = writeFooter_C;
+            break;
+
+        case FMT_AUTO:
+        default:
+            dmError("Internal error, FMT_AUTO at output function init.\n");
+            exit(2);
+    }
+
+    /* Open the files */
+    if (optInFilename == NULL)
+        sfile = stdin;
+    else
+    if ((sfile = fopen(optInFilename, "rb")) == NULL)
+    {
+        tmpRes = errno;
+        dmError("Error opening input file '%s'. (%s)\n",
+            optInFilename, strerror(tmpRes));
+        exit(3);
+    }
+
+    if (optOutFilename == NULL)
+        dfile = stdout;
+    else
+    if ((dfile = fopen(optOutFilename, "wa")) == NULL)
+    {
+        tmpRes = errno;
+        dmError("Error creating output file '%s'. (%s)\n",
+            optOutFilename, strerror(tmpRes));
+        exit(4);
+    }
+
+    /* Get sourcefile size */
+    inSize = dmGetFileSize(sfile);
+
+    /* Output header */
+    if (!optQuiet)
+        writeHeader(dfile, optOutFilename);
+
+    if (optAddLine)
+        fprintf(dfile, "%s\n", optAddLine);
+
+    /* Output declaration */
+    writeDecl(dfile, inSize, optObjName);
+
+    /* Output data */
+    while (!feof(sfile))
+    {
+        tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile);
+        if (tmpRes > 0)
+        {
+            if (optIndentation < 0)
+                fprintf(dfile, "\t");
+            else
+            if (optIndentation > 0)
+            {
+                int i;
+                for (i = 0; i < optIndentation; i++)
+                    fputs(" ", dfile);
+            }
+
+            writeData(dfile, inBuf, tmpRes);
+
+            fprintf(dfile, "\n");
+        }
+    }
+
+
+    /* Output footer */
+    writeFooter(dfile, inSize, optObjName);
+
+    /* Exit */
+    fclose(sfile);
+    fclose(dfile);
+
+    exit(0);
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gentab.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,264 @@
+#include "dmlib.h"
+#include "dmargs.h"
+#include <math.h>
+
+enum
+{
+    MT_SIN,
+    MT_COS,
+    MT_SMOOTH1,
+    MT_SCURVE,
+    MT_SMOOTH1_CLAMP,
+    MT_SCURVE_CLAMP,
+    MT_SIN_SCURVE,
+
+    MT_LAST
+};
+
+
+typedef struct
+{
+    char *name;
+    char *desc;
+} DMTransType;
+
+static DMTransType dmTransTypes[MT_LAST] =
+{
+    { "sin", "Sine" },
+    { "cos", "Cosine" },
+    { "smooth1", "Smoothstep1 LERP" },
+    { "scurve", "S-curve LERP" },
+    { "smooth1-clamp", "Clamped smoothstep1 LERP" },
+    { "scurve-clamp", "Clamped S-curve LERP" },
+    { "sin-scurve", "Sine S-curve" },
+};
+
+
+DMFloat
+    optSOffset     = 0.0f,
+    optSAmplitude  = 1.0f,
+    optSOmega      = 1.0f,
+    optStartValue  = 0.0f,
+    optEndValue    = 1.0f;
+
+int optNSteps      = 64,
+    optPerLine     = 16,
+    optTransType   = -1;
+
+char
+    *optObjectName = NULL,
+    *optOutFilename = NULL;
+
+
+static DMOptArg optList[] =
+{
+    {  0, '?', "help",        "Show this help", OPT_NONE },
+    {  1, 'v', "verbose",     "Increase verbosity", OPT_NONE },
+    {  2, 'o', "output",      "Set output file (default stdout)", OPT_ARGREQ },
+    {  3, 'n', "name",        "Set output object name", OPT_ARGREQ },
+
+    {  4, 's', "steps",       "Number of steps/values in output table", OPT_ARGREQ },
+    {  5, 't', "type",        "Curve/interpolation type (see list)", OPT_ARGREQ },
+
+    {  6, 'O', "offset",      "Output data offset", OPT_ARGREQ },
+    {  7, 'A', "amplitude",   "Output amplitude scale", OPT_ARGREQ },
+    {  8, 'W', "omega",       "Omega (w) multiplier", OPT_ARGREQ },
+
+    {  9, 'S', "start",       "Start value (only smooth/scurve)", OPT_ARGREQ },
+    { 10, 'E', "end",         "End value (only smooth/scurve)", OPT_ARGREQ },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    int index;
+    dmPrintBanner(stdout, dmProgName, "[options]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+
+    printf("\nAvailable types:\n");
+    for (index = 0; index < MT_LAST; index++)
+    {
+        DMTransType *tm = &dmTransTypes[index];
+        printf("%-15s | %s\n", tm->name, tm->desc);
+    }
+    printf("\n");
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            dmVerbosity++;
+            break;
+        
+        case 2:
+            optOutFilename = optArg;
+            break;
+        
+        case 3:
+            optObjectName = optArg;
+            break;
+        
+        case 4:
+            {
+                int tmp;
+                if (sscanf(optArg, "%d", &tmp) != 1)
+                {
+                    dmError("Invalid number of steps argument '%s'.\n", optArg);
+                    return FALSE;
+                }
+                optNSteps = tmp;
+            }
+            break;
+
+        case 5:
+            {
+                int index;
+                for (index = 0; index < MT_LAST; index++)
+                {
+                    DMTransType *tm = &dmTransTypes[index];
+                    if (strcasecmp(tm->name, optArg) == 0)
+                    {
+                        optTransType = index;
+                        return TRUE;
+                    }
+                }
+                dmError("Invalid transformation type option '%s'.\n",
+                    optArg);
+                return FALSE;
+            }
+            break;
+
+        case 6:
+        case 7:
+        case 8:
+        case 9:
+        case 10:
+            {
+                DMFloat tmp;
+                if (sscanf(optArg, "%f", &tmp) != 1)
+                {
+                    dmError("Invalid %s option argument '%s', expected a floating point value.\n",
+                        currArg, optArg);
+                    return FALSE;
+                }
+                switch (optN)
+                {
+                    case  6: optSOffset = tmp; break;
+                    case  7: optSAmplitude = tmp; break;
+                    case  8: optSOmega = tmp; break;
+                    case  9: optStartValue = tmp; break;
+                    case 10: optEndValue = tmp; break;
+                }
+            }
+            break;
+
+        default:
+            dmError("Unknown argument '%s'.\n", currArg);
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+int main(int argc, char *argv[])
+{
+    FILE *outFile;
+    DMLerpContext ctx;
+    int step, n;
+
+    dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL);
+    dmVerbosity = 1;
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, NULL, TRUE))
+        exit(1);
+
+    // Check settings
+    if (optTransType < 0)
+    {
+        dmError("No transformation type set, perhaps try --help\n");
+        return -1;
+    }
+    
+    if (optObjectName == NULL)
+    {
+        dmError("Object name not specified, try --help\n");
+        return -2;
+    }
+
+    if (optOutFilename == NULL)
+        outFile = stdout;
+    else
+    if ((outFile = fopen(optOutFilename, "w")) == NULL)
+    {
+        int err = dmGetErrno();
+        dmError("Could not open output file '%s', %d: %s\n",
+            optOutFilename, err, dmErrorStr(err));
+        return -2;
+    }
+    
+
+    // Generate table
+    dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps);
+
+    fprintf(outFile,
+        "cnt_%s = %d\n"
+        "vtab_%s: ",
+        optObjectName,
+        optNSteps,
+        optObjectName
+        );
+
+    for (n = 0, step = 0; step < optNSteps; step++)
+    {
+        DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value;
+        
+        switch (optTransType)
+        {
+            case MT_SIN:           delta = sin(t * 2 * DM_PI); break;
+            case MT_COS:           delta = cos(t * 2 * DM_PI); break;
+
+            case MT_SMOOTH1:       delta = dmLerp1(&ctx, step); break;
+            case MT_SCURVE:        delta = dmLerpSCurve(&ctx, step); break;
+            case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break;
+            case MT_SCURVE_CLAMP:  delta = dmLerpSCurveClamp(&ctx, step); break;
+            case MT_SIN_SCURVE:    delta = dmLerpSCurveClamp(&ctx, step); break;
+            
+            default: delta = 0;
+        }
+        
+        value = optSOffset + delta * optSAmplitude;
+        
+        // Print the value
+        if (n == 0)
+            fprintf(outFile, "\t.byte ");
+
+        fprintf(outFile, "%ld%s",
+            lrint(value),
+            (n < optPerLine - 1) ? "," : "");
+
+        if (++n >= optPerLine)
+        {
+            fprintf(outFile, "\n");
+            n = 0;
+        }
+    }
+    if (n > 0)
+        fprintf(outFile, "\n");
+    
+    fprintf(outFile, "\n");
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gfxconv.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,1697 @@
+/*
+ * gfxconv - Convert various graphics formats
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmfile.h"
+#include "dmmutex.h"
+#include "libgfx.h"
+#include "lib64gfx.h"
+
+//#define UNFINISHED 1
+
+#define DM_MAX_COLORS 256
+
+#define ASC_NBITS    8
+#define ASC_NCOLORS  4
+static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#";
+
+enum
+{
+    FFMT_AUTO = 0,
+
+    FFMT_ASCII,
+    FFMT_ANSI,
+    FFMT_IMAGE,
+
+    FFMT_CHAR,
+    FFMT_SPRITE,
+    FFMT_BITMAP,
+
+    FFMT_LAST
+};
+
+
+typedef struct
+{
+    char *name;
+    char *fext;
+    BOOL in, out;
+    int format;
+    int subformat;
+} DMConvFormat;
+
+
+static DMConvFormat convFormatList[] =
+{
+    {
+        "ASCII text", "asc", FALSE, TRUE,
+        FFMT_ASCII  , 0,
+    },
+    {
+        "ANSI colored text", "ansi", FALSE, TRUE,
+        FFMT_ANSI   , 0,
+    },
+    {
+        "PNG image file", "png", TRUE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PNG,
+    },
+    {
+        "PPM image file", "ppm", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PPM,
+    },
+    {
+        "PCX image file", "pcx", TRUE, TRUE,
+        FFMT_IMAGE  , IMGFMT_PCX,
+    },
+    {
+        "IFF ILBM file", "lbm", TRUE, FALSE,
+        FFMT_IMAGE  , IMGFMT_ILBM,
+    },
+    {
+        "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_RAW,
+    },
+    {
+        "IFFMaster RAW image file", "araw", FALSE, TRUE,
+        FFMT_IMAGE  , IMGFMT_ARAW,
+    },
+
+    {
+        "C64 bitmap image file", NULL, TRUE, TRUE,
+        FFMT_BITMAP , -1,
+    },
+
+    {
+        "C64 character/font data", "chr", TRUE, TRUE,
+        FFMT_CHAR   , 0
+    },
+    {
+        "C64 sprite data", "spr", TRUE, TRUE,
+        FFMT_SPRITE , 0
+    },
+};
+
+static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]);
+
+
+typedef struct
+{
+    BOOL triplet, alpha;
+    DMColor color;
+    int from, to;
+} DMMapValue;
+
+
+
+char    *optInFilename = NULL,
+        *optOutFilename = NULL;
+int     optInFormat = FFMT_AUTO,
+        optOutFormat = FFMT_ASCII,
+        optInSubFormat = IMGFMT_PNG,
+        optOutSubFormat = IMGFMT_PNG,
+        optItemCount = -1,
+        optPlanedWidth = 1,
+        optForcedFormat = -1;
+int     optInSkip = 0;
+BOOL    optInMulticolor = FALSE,
+        optSequential = FALSE,
+        optRemapColors = FALSE,
+        optRemapRemove = FALSE;
+int     optNRemapTable = 0;
+DMMapValue optRemapTable[DM_MAX_COLORS];
+int     optColors[C64_MAX_COLORS];
+
+DMImageSpec optSpec =
+{
+    .scale = 1,
+    .nplanes = 4,
+    .interleave = FALSE,
+    .paletted = FALSE,
+    .format = 0,
+};
+
+static DMOptArg optList[] =
+{
+    {  0, '?', "help",         "Show this help", OPT_NONE },
+    { 15, 'v', "verbose",      "Increase verbosity", OPT_NONE },
+    {  3, 'o', "output",       "Output filename", OPT_ARGREQ },
+    {  1, 'i', "informat",     "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ },
+    {  2, 'm', "multicolor",   "Input is multicolor / output in multicolor", OPT_NONE },
+    {  4, 's', "skip",         "Skip bytes in input", OPT_ARGREQ },
+    {  5, 'f', "format",       "Output format (see --formats)", OPT_ARGREQ },
+    { 17, 'F', "formats",      "Output format (see list below)", OPT_NONE },
+    {  8, 'q', "sequential",   "Output sequential files (image output only)", OPT_NONE },
+    {  6, 'c', "colormap",     "Color mappings (see below for information)", OPT_ARGREQ },
+    {  7, 'n', "numitems",     "How many 'items' to view (default: all)", OPT_ARGREQ },
+    {  9, 'S', "scale",        "Scale output by x (image output only)", OPT_ARGREQ },
+    { 10, 'b', "bformat",      "Force input bitmap format (see below)", OPT_ARGREQ },
+    { 11, 'w', "width",        "Item width (number of items per row, min 1)", OPT_ARGREQ },
+    { 12, 'P', "paletted",     "Use indexed/paletted output (png, pcx output only)", OPT_NONE },
+    { 13, 'B', "bplanes",      "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ },
+    { 14, 'I', "interleave",   "Interleave scanlines (default: output whole planes)", OPT_NONE },
+    { 16, 'R', "remap",        "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ },
+    { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowFormats()
+{
+    int i;
+
+    printf(
+    "Available input/output formats:\n"
+    "  Ext | I | O | Description\n"
+    "------+---+---+-----------------------------------------------\n"
+    );
+    
+    for (i = 0; i < nconvFormatList; i++)
+    {
+        DMConvFormat *fmt = &convFormatList[i];
+        printf("%-5s | %c | %c | %s\n",
+            fmt->fext ? fmt->fext : "",
+            fmt->in ? 'X' : ' ',
+            fmt->out ? 'X' : ' ',
+            fmt->name);
+    }
+
+    printf(
+    "\n"
+    "(Not all input->output combinations are actually supported.)\n"
+    "\n"
+    "Available bitmap formats:\n"
+    "  Ext | Type            | Description\n"
+    "------+-----------------+-------------------------------------\n"
+    );
+
+    for (i = 0; i < ndmC64ImageFormats; i++)
+    {
+        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
+        char buf[64];
+        printf("%-5s | %-15s | %s\n",
+            fmt->fext,
+            dmC64GetImageTypeString(buf, sizeof(buf), fmt->type),
+            fmt->name);
+    }
+}
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options] <input file>");
+    dmArgsPrintHelp(stdout, optList, optListN);
+
+    printf(
+    "\n"
+    "Color map definitions are used for ANSI and image output, to declare what\n"
+    "output colors of the C64 palette are used for each single color/multi color\n"
+    "bit-combination. For example, if the input is multi color sprite or char,\n"
+    "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n"
+    "The numbers are palette indexes, and the order is for bit(pair)-values\n"
+    "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n"
+    "special color that can be used for transparency.\n"
+    );
+}
+
+
+int dmGetConvFormat(int format, int subformat)
+{
+    int i;
+    for (i = 0; i < nconvFormatList; i++)
+    {
+        DMConvFormat *fmt = &convFormatList[i];
+        if (fmt->format == format &&
+            fmt->subformat == subformat)
+            return i;
+    }
+    return -1;
+}
+
+
+BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat)
+{
+    int i;
+    if (fext == NULL)
+        return FALSE;
+
+    for (i = 0; i < nconvFormatList; i++)
+    {
+        DMConvFormat *fmt = &convFormatList[i];
+        if (fmt->fext != NULL &&
+            strcasecmp(fext, fmt->fext) == 0)
+        {
+            *format = fmt->format;
+            *subformat = fmt->subformat;
+            return TRUE;
+        }
+    }
+
+    for (i = 0; i < ndmC64ImageFormats; i++)
+    {
+        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
+        if (fmt->fext != NULL &&
+            strcasecmp(fext, fmt->fext) == 0)
+        {
+            *format = FFMT_BITMAP;
+            *subformat = i;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+
+static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg)
+{
+    char *end, *split, *opt = dm_strdup(popt);
+
+    if (opt == NULL)
+        goto error;
+
+    if ((end = split = strchr(opt, ':')) == NULL)
+    {
+        dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt);
+        goto error;
+    }
+
+    // Trim whitespace
+    *end = 0;
+    for (end--; end > opt && *end && isspace(*end); end--)
+        *end = 0;
+
+    // Parse either a hex triplet color definition or a normal value
+    if (*opt == '#' || *opt == '%')
+    {
+        int colR, colG, colB, colA;
+
+        if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 ||
+            sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4)
+        {
+            value->alpha = TRUE;
+            value->color.a = colA;
+        }
+        else
+        if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 &&
+            sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3)
+        {
+            dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1);
+            goto error;
+        }
+
+        value->color.r = colR;
+        value->color.g = colG;
+        value->color.b = colB;
+        value->triplet = TRUE;
+    }
+    else
+    {
+        if (!dmGetIntVal(opt, &value->from))
+        {
+            dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt);
+            goto error;
+        }
+        value->triplet = FALSE;
+    }
+    
+    // Trim whitespace
+    split++;
+    while (*split && isspace(*split)) split++;
+    
+    // Parse destination value
+    if (!dmGetIntVal(split, &value->to))
+    {
+        dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split);
+        goto error;
+    }
+
+    if (!value->triplet && (value->from < 0 || value->from > 255))
+    {
+        dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from);
+        goto error;
+    }
+
+    if (value->to < 0 || value->to > nmax)
+    {
+        dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax);
+        goto error;
+    }
+
+    dmFree(opt);
+    return TRUE;
+
+error:
+    dmFree(opt);
+    return FALSE;
+}
+
+
+static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg)
+{
+    // Trim whitespace
+    if (end != NULL)
+    {
+        *end = 0;
+        for (end--; end > opt && *end && isspace(*end); end--)
+            *end = 0;
+    }
+    while (*opt && isspace(*opt)) opt++;
+
+    // Parse item based on mode
+    if (requireIndex)
+    {
+        DMMapValue *value = (DMMapValue *) pvalue;
+        if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg))
+            return FALSE;
+    }
+    else
+    {
+        int *value = (int *) pvalue;
+        char *split = strchr(opt, ':');
+        if (split != NULL)
+        {
+            dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt);
+            return FALSE;
+        }
+
+        if (!dmGetIntVal(opt, &value[index]))
+        {
+            dmError("Invalid %s value '%s', could not parse.\n", msg, opt);
+            return FALSE;
+        }
+    }
+    
+    return TRUE;
+}
+
+
+BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg)
+{
+    char *end, *start = opt;
+
+    *nvalues = 0;
+    while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL)
+    {
+        if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg))
+            return FALSE;
+
+        start = end + 1;
+        (*nvalues)++;
+    }
+    
+    if (*start && *nvalues < nmax)
+    {
+        if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg))
+            return FALSE;
+
+        (*nvalues)++;
+    }
+
+    return TRUE;   
+}
+
+
+int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax)
+{
+    FILE *fp;
+    char line[512];
+    int res = DMERR_OK;
+
+    if ((fp = fopen(filename, "r")) == NULL)
+    {
+        res = dmGetErrno();
+        dmError("Could not open color remap file '%s' for reading, %d: %s\n",
+            res, dmErrorStr(res));
+        return res;
+    }
+
+    while (fgets(line, sizeof(line), fp))
+    {
+        char *start = line;
+        while (*start && isspace(*start)) start++;
+        
+        if (*start != 0 && *start != ';')
+        {
+            if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file"))
+                goto error;
+            else
+            {
+                (*nvalue)++;
+                if (*nvalue >= nmax)
+                {
+                    dmError("Too many mapping pairs in '%s', maximum is %d.\n",
+                        filename, nmax);
+                    goto error;
+                }
+            }
+        }
+    }
+
+error:
+    fclose(fp);
+    return res;
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 17:
+            argShowFormats();
+            exit(0);
+            break;
+
+        case 15:
+            dmVerbosity++;
+            break;
+
+        case 1:
+            switch (tolower(optArg[0]))
+            {
+                case 's':
+                    optInFormat = FFMT_SPRITE;
+                    break;
+                case 'c':
+                    optInFormat = FFMT_CHAR;
+                    break;
+                case 'b':
+                    optInFormat = FFMT_BITMAP;
+                    break;
+                case 'i':
+                    optInFormat = FFMT_IMAGE;
+                    break;
+                default:
+                    dmError("Invalid input format '%s'.\n", optArg);
+                    return FALSE;
+            }
+            break;
+        
+        case 2:
+            optInMulticolor = TRUE;
+            break;
+
+        case 3:
+            optOutFilename = optArg;
+            break;
+        
+        case 4:
+            if (!dmGetIntVal(optArg, &optInSkip))
+            {
+                dmError("Invalid skip value argument '%s'.\n", optArg);
+                return FALSE;
+            }
+            break;
+
+        case 5:
+            if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat))
+            {
+                dmError("Invalid output format '%s'.\n", optArg);
+                return FALSE;
+            }
+            break;
+
+        case 6:
+            {
+                int index, ncolors;
+                if (!dmParseMapOptionString(optArg, optColors,
+                    &ncolors, C64_MAX_COLORS, FALSE, "color table option"))
+                    return FALSE;
+
+                dmMsg(1, "Set color table: ");
+                for (index = 0; index < ncolors; index++)
+                {
+                    dmPrint(1, "[%d:%d]%s",
+                        index, optColors[index],
+                        (index < ncolors) ? ", " : "");
+                }
+                dmPrint(1, "\n");
+            }
+            break;
+
+        case 7:
+            if (sscanf(optArg, "%d", &optItemCount) != 1)
+            {
+                dmError("Invalid count value argument '%s'.\n", optArg);
+                return FALSE;
+            }
+            break;
+
+        case 8:
+            optSequential = TRUE;
+            break;
+
+        case 9:
+            {
+                int tmp = atoi(optArg);
+                if (tmp < 1 || tmp > 50)
+                {
+                    dmError("Invalid scale value '%s'.\n", optArg);
+                    return FALSE;
+                }
+                optSpec.scale = tmp;
+            }
+            break;
+
+        case 11:
+            {
+                int tmp = atoi(optArg);
+                if (tmp < 1 || tmp > 512)
+                {
+                    dmError("Invalid width value '%s'.\n", optArg);
+                    return FALSE;
+                }
+                optPlanedWidth = tmp;
+            }
+            break;
+
+        case 12:
+            optSpec.paletted = TRUE;
+            break;
+
+        case 13:
+            {
+                int tmp = atoi(optArg);
+                if (tmp < 1 || tmp > 8)
+                {
+                    dmError("Invalid bitplanes/bpp value '%s'.\n", optArg);
+                    return FALSE;
+                }
+                optSpec.nplanes = tmp;
+            }
+            break;
+
+        case 14:
+            optSpec.interleave = TRUE;
+            break;
+
+
+        case 16:
+            if (optArg[0] == '@')
+            {
+                if (optArg[1] != 0)
+                {
+                    int res;
+                    if ((res = dmParseColorRemapFile(optArg + 1,
+                        optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK)
+                        return FALSE;
+                }
+                else
+                {
+                    dmError("No remap filename given.\n");
+                    return FALSE;
+                }
+            }
+            else
+            {
+                if (!dmParseMapOptionString(optArg, optRemapTable,
+                    &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option"))
+                    return FALSE;
+            }
+
+            optRemapColors = TRUE;
+            break;
+
+        case 18:
+            optRemapRemove = TRUE;
+            break;
+
+        default:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    if (!optInFilename)
+        optInFilename = currArg;
+    else
+    {
+        dmError("Source filename already specified, extraneous argument '%s'.\n",
+             currArg);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor)
+{
+    int i;
+    
+    if (multicolor)
+    {
+        for (i = ASC_NBITS; i; i -= 2)
+        {
+            int val = (byte & (3ULL << (i - 2))) >> (i - 2);
+            char ch;
+            switch (format)
+            {
+                case FFMT_ASCII:
+                    ch = dmASCIIPalette[val];
+                    fprintf(out, "%c%c", ch, ch);
+                    break;
+                case FFMT_ANSI:
+                    fprintf(out, "%c[0;%d;%dm##%c[0m",
+                        0x1b,
+                        1,
+                        31 + optColors[val],
+                        0x1b);
+                    break;
+            }
+        }
+    }
+    else
+    {
+        for (i = ASC_NBITS; i; i--)
+        {
+            int val = (byte & (1ULL << (i - 1))) >> (i - 1);
+            char ch;
+            switch (format)
+            {
+                case FFMT_ASCII:
+                    ch = val ? '#' : '.';
+                    fputc(ch, out);
+                    break;
+                case FFMT_ANSI:
+                    fprintf(out, "%c[0;%d;%dm %c[0m",
+                        0x1b,
+                        1,
+                        31 + optColors[val],
+                        0x1b);
+                    break;
+            }
+        }
+    }
+}
+
+
+void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor)
+{
+    int yc;
+
+    for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
+    {
+        fprintf(outFile, "%04x : ", *offs);
+        dmPrintByte(outFile, buf[yc], format, multicolor);
+        fprintf(outFile, "\n");
+        (*offs)++;
+    }
+}
+
+
+void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor)
+{
+    int bufOffs, xc, yc;
+
+    for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++)
+    {
+        fprintf(outFile, "%04x : ", *offs);
+        for (xc = 0; xc < C64_SPR_WIDTH; xc++)
+        {
+            dmPrintByte(outFile, buf[bufOffs], format, multicolor);
+            fprintf(outFile, " ");
+            bufOffs++;
+            (*offs)++;
+        }
+        fprintf(outFile, "\n");
+    }
+    (*offs)++;
+}
+
+
+#ifdef UNFINISHED
+int dmConvertBMP2(DMImage *screen, const DM64Image *img)
+{
+    int yc;
+    Uint8 *dp = screen->data;
+    
+    for (yc = 0; yc < screen->height; yc++)
+    {
+        Uint8 *d = dp;
+        const int y = yc / 8, yb = yc & 7;
+        const int scroffsy = y * C64_SCR_CH_WIDTH;
+        const int bmoffsy = y * C64_SCR_WIDTH;
+        int xc;
+
+        for (xc = 0; xc < screen->width / 2; xc++)
+        {
+            const int x = xc / 4;
+            const int scroffs = scroffsy + x;
+            const int b = img->bitmap[0][bmoffsy + (x * 8) + yb];
+            const int v = 6 - ((xc * 2) & 6);
+            Uint8 c;
+
+            switch ((b >> v) & 3)
+            {
+                case 0: c = img->bgcolor; break;
+                case 1: c = img->screen[0][scroffs] >> 4; break;
+                case 2: c = img->screen[0][scroffs] & 15; break;
+                case 3: c = img->color[0][scroffs] & 15; break;
+            }
+            
+            *d++ = c;
+            *d++ = c;
+        }
+
+        dp += screen->pitch;
+    }
+    
+    return 0;
+}
+#endif
+
+
+int dmRemapImageColors(DMImage *image)
+{
+    DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor));
+    int  *mapping = dmMalloc(image->ncolors * sizeof(int));
+    BOOL *mapped  = dmMalloc(image->ncolors * sizeof(BOOL));
+    BOOL *used    = dmMalloc(image->ncolors * sizeof(BOOL));
+    int n, index, xc, yc, ncolors;
+
+    dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors);
+
+    if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL)
+    {
+        dmError("Could not allocate memory for reused palette.\n");
+        return DMERR_MALLOC;
+    }
+
+    for (index = 0; index < image->ncolors; index++)
+    {
+        mapping[index] = -1;
+        mapped[index] = used[index] = FALSE;
+    }
+
+    // Find used colors
+    dmMsg(2, "Scanning image for used colors...\n");
+    for (ncolors = yc = 0; yc < image->height; yc++)
+    {
+        Uint8 *dp = image->data + image->pitch * yc;
+        for (xc = 0; xc < image->width; xc++)
+        {
+            Uint8 col = dp[xc];
+            if (col < image->ncolors && !used[col])
+            {
+                used[col] = TRUE;
+                ncolors++;
+            }
+        }
+    }
+    dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors);
+
+    // Match and mark mapped colors
+    for (index = 0; index < optNRemapTable; index++)
+    {
+        DMMapValue *map = &optRemapTable[index];
+        if (map->triplet)
+        {
+            BOOL found = FALSE;
+            for (n = 0; n < image->ncolors; n++)
+            {
+                if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha))
+                {
+                    dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n",
+                        map->color.r, map->color.g, map->color.b, map->color.a,
+                        n,
+                        map->to);
+
+                    mapping[n] = map->to;
+                    mapped[map->to] = TRUE;
+                    found = TRUE;
+                }
+            }
+            
+            if (!found)
+            {
+                dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n",
+                    index,
+                    map->color.r, map->color.g, map->color.b, map->color.a);
+            }
+        }
+        else
+        {
+            dmMsg(3, "Map index: %d -> %d\n",
+                map->from, map->to);
+
+            mapping[map->from] = map->to;
+            mapped[map->to] = TRUE;
+        }
+    }
+
+    
+    // Fill in the rest
+    if (optRemapRemove)
+    {
+        dmMsg(2, "Removing unused colors.\n");
+        for (index = 0; index < image->ncolors; index++)
+        if (mapping[index] < 0 && used[index])
+        {
+            for (n = 0; n < image->ncolors; n++)
+            if (!mapped[n])
+            {
+                mapping[index] = n;
+                mapped[n] = TRUE;
+                break;
+            }
+        }
+    }
+    else
+    {
+        for (index = 0; index < image->ncolors; index++)
+        if (mapping[index] < 0)
+        {
+            for (n = 0; n < image->ncolors; n++)
+            if (!mapped[n])
+            {
+                mapping[index] = n;
+                mapped[n] = TRUE;
+                break;
+            }
+        }
+    }
+
+    // Calculate final number of palette colors
+    ncolors = 0;
+    for (index = 0; index < image->ncolors; index++)
+    {
+        if (mapping[index] + 1 > ncolors)
+            ncolors = mapping[index] + 1;
+    }
+    
+    // Copy palette entries
+    for (index = 0; index < image->ncolors; index++)
+    {
+        if (mapping[index] >= 0)
+        {
+            memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor));
+        }
+    }
+
+    // Remap image
+    dmMsg(1, "Remapping image to %d colors...\n", ncolors);
+    for (yc = 0; yc < image->height; yc++)
+    {
+        Uint8 *dp = image->data + image->pitch * yc;
+        for (xc = 0; xc < image->width; xc++)
+        {
+            Uint8 col = dp[xc];
+            if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors)
+                dp[xc] = mapping[col];
+            else
+                dp[xc] = 0;
+        }
+    }
+
+    // Set new palette, free memory
+    dmFree(image->pal);
+    image->pal = npal;
+    image->ncolors = ncolors;
+
+    dmFree(mapping);
+    dmFree(mapped);
+    dmFree(used);
+    return DMERR_OK;
+}
+
+
+int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps)
+{
+    FILE *outFile = NULL;
+    Uint8 *buf = NULL;
+    size_t bufSize;
+    int res = DMERR_OK;
+    const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat];
+
+    dmMsg(1, "Converting to %s format bitmap.\n", fmt->name);
+    if (image->type != fmt->type && enableFixUps)
+    {
+        // Try to do some simple fixups
+        if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0)
+        {
+            dmMsg(1, "Upconverting multicolor to FLI.\n");
+            int i;
+            for (i = 1; i < C64_SCR_MAX_BANK; i++)
+            {
+                memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE);
+                memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE);
+            }
+        }
+    }
+
+
+    if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK)
+        goto error;
+
+    dmMsg(2, "Result: %d bytes\n", bufSize);
+
+    if ((outFile = fopen(filename, "wb")) == NULL)
+    {
+        res = dmGetErrno();
+        dmError("Error opening output file '%s', %d: %s\n",
+            filename, res, dmErrorStr(res));
+        goto error;
+    }
+
+    if (!dm_fwrite_str(outFile, buf, bufSize))
+    {
+        res = dmGetErrno();
+        dmError("Error writing image data to '%s', %d: %s\n",
+            filename, res, dmErrorStr(res));
+    }
+
+error:
+    if (outFile != NULL)
+        fclose(outFile);
+    dmFree(buf);
+    return res;
+}
+
+
+int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info)
+{
+    if (info)
+    {
+        dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n",
+            dmImageFormatList[iformat].fext,
+            image->width, image->height,
+            image->width * spec->scale, image->height * spec->scale,
+            spec->scale);
+    }
+
+    // Perform color remapping
+    if (optRemapColors)
+    {
+        int res;
+        if ((res = dmRemapImageColors(image)) != DMERR_OK)
+            return res;
+    }
+
+    switch (iformat)
+    {
+#ifdef DM_USE_LIBPNG
+        case IMGFMT_PNG:
+            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA");
+            spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA;
+            return dmWritePNGImage(filename, image, spec);
+#endif
+
+        case IMGFMT_PPM:
+            if (info) dmMsg(2, "24bit RGB output.\n");
+            spec->format = DM_IFMT_RGB;
+            return dmWritePPMImage(filename, image, spec);
+
+        case IMGFMT_PCX:
+            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB");
+            return dmWritePCXImage(filename, image, spec);
+
+        case IMGFMT_RAW:
+        case IMGFMT_ARAW:
+            {
+                FILE *fp;
+                char *dataFilename, *fext, *tmpFilename = dm_strdup(filename);
+                
+                // Form data file filename
+                if (tmpFilename == NULL)
+                    return DMERR_MALLOC;
+
+                fext = strrchr(tmpFilename, '.');
+                if (fext != NULL)
+                    *fext = 0;
+                dataFilename = dm_strdup_printf("%s.inc", tmpFilename);
+                dmFree(tmpFilename);
+
+                // Open data file for writing
+                if ((fp = fopen(dataFilename, "w")) == NULL)
+                    dmError("Could not create '%s'.\n", dataFilename);
+                dmFree(dataFilename);
+
+                if (fp != NULL)
+                {
+                    // Strip extension
+                    int i;
+                    char *palID = dm_strdup_printf("img_%s", filename);
+                    char *fext = strrchr(palID, '.');
+                    if (fext != NULL)
+                        *fext = 0;
+
+                    // Replace any non-alphanumerics
+                    for (i = 0; palID[i]; i++)
+                    {
+                        if (isalnum(palID[i]))
+                            palID[i] = tolower(palID[i]);
+                        else
+                            palID[i] = '_';
+                    }
+
+                    if (iformat == IMGFMT_ARAW)
+                    {
+                        fprintf(fp,
+                        "%s_width: dw.w %d\n"
+                        "%s_height: dw.w %d\n"
+                        "%s_nplanes: dw.w %d\n"
+                        "%s_ncolors: dw.w %d\n"
+                        "%s_palette:\n",
+                        palID, image->width,
+                        palID, image->height,
+                        palID, spec->nplanes,
+                        palID, image->ncolors,
+                        palID);
+
+                        dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL);
+
+                        fprintf(fp,
+                        "%s: incbin \"%s\"\n",
+                        palID, filename);
+                    }
+                    else
+                    {
+                        fprintf(fp,
+                        "%s_width: dw.w %d\n"
+                        "%s_height: dw.w %d\n"
+                        "%s_nplanes: dw.w %d\n",
+                        palID, image->width,
+                        palID, image->height,
+                        palID, spec->nplanes);
+                    }
+
+                    fclose(fp);
+                    dmFree(palID);
+                }
+
+                if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without");
+                return dmWriteRAWImage(filename, image, spec);
+            }
+            break;
+
+        default:
+            return DMERR_INVALID_DATA;
+    }
+}
+
+
+static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor)
+{
+    Uint8 byte = 0;
+    int xc;
+
+    if (multicolor)
+    {
+        for (xc = 0; xc < 8 / 2; xc++)
+        {
+            Uint8 pixel = sp[xc * 2] & 3;
+            byte |= pixel << (6 - (xc * 2));
+        }
+    }
+    else
+    {
+        for (xc = 0; xc < 8; xc++)
+        {
+            Uint8 pixel = sp[xc] == 0 ? 0 : 1;
+            byte |= pixel << (7 - xc);
+        }
+    }
+
+    return byte;
+}
+
+
+BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image,
+    const int xoffs, const int yoffs, const BOOL multicolor)
+{
+    int yc;
+
+    if (xoffs < 0 || yoffs < 0 ||
+        xoffs + C64_CHR_WIDTH_PX > image->width ||
+        yoffs + C64_CHR_HEIGHT > image->height)
+        return FALSE;
+
+    for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
+    {
+        const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs;
+        buf[yc] = dmConvertByte(sp, multicolor);
+    }
+
+    return TRUE;
+}
+
+
+BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image,
+    const int xoffs, const int yoffs, const BOOL multicolor)
+{
+    int yc, xc;
+
+    if (xoffs < 0 || yoffs < 0 ||
+        xoffs + C64_SPR_WIDTH_PX > image->width ||
+        yoffs + C64_SPR_HEIGHT > image->height)
+        return FALSE;
+
+    for (yc = 0; yc < C64_SPR_HEIGHT; yc++)
+    {
+        for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++)
+        {
+            const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs;
+            buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor);
+        }
+    }
+
+    return TRUE;
+}
+
+
+int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor)
+{
+    int outBlockW, outBlockH, bx, by;
+    FILE *outFile = NULL;
+    Uint8 *buf = NULL;
+    size_t bufSize;
+    char *outType;
+
+    switch (outFormat)
+    {
+        case FFMT_CHAR:
+            bufSize = C64_CHR_SIZE;
+            outBlockW = image->width / C64_CHR_WIDTH_PX;
+            outBlockH = image->height / C64_CHR_HEIGHT;
+            outType = "char";
+            break;
+
+        case FFMT_SPRITE:
+            bufSize = C64_SPR_SIZE;
+            outBlockW = image->width / C64_SPR_WIDTH_PX;
+            outBlockH = image->height / C64_SPR_HEIGHT;
+            outType = "sprite";
+            break;
+
+        default:
+            dmError("Invalid output format %d, internal error.\n", outFormat);
+            goto error;
+    }
+
+    if (outBlockW <= 0 || outBlockH <= 0)
+    {
+        dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n",
+            outBlockW, outBlockH);
+        goto error;
+    }
+
+    if ((outFile = fopen(filename, "wb")) == NULL)
+    {
+        int err = dmGetErrno();
+        dmError("Could not open '%s' for writing, %d: %s.\n",
+            filename, err, dmErrorStr(err));
+        goto error;
+    }
+
+    if ((buf = dmMalloc(bufSize)) == NULL)
+    {
+        dmError("Could not allocate %d bytes for conversion buffer.\n",
+            bufSize);
+        goto error;
+    }
+
+    dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n",
+        outBlockW, outBlockH, outBlockW * outBlockH, outType);
+
+    for (by = 0; by < outBlockH; by++)
+    for (bx = 0; bx < outBlockW; bx++)
+    {
+        switch (outFormat)
+        {
+            case FFMT_CHAR:
+                if (!dmConvertImage2Char(buf, image,
+                    bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT,
+                    multicolor))
+                    goto error;
+                break;
+
+            case FFMT_SPRITE:
+                if (!dmConvertImage2Sprite(buf, image,
+                    bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT,
+                    multicolor))
+                    goto error;
+        }
+
+        if (!dm_fwrite_str(outFile, buf, bufSize))
+        {
+            int err = dmGetErrno();
+            dmError("Error writing data block %d,%d to '%s', %d: %s\n",
+                bx, by, filename, err, dmErrorStr(err));
+            goto error;
+        }
+    }
+
+    fclose(outFile);
+    dmFree(buf);
+    return 0;
+
+error:
+    if (outFile != NULL)
+        fclose(outFile);
+    dmFree(buf);
+    return -1;
+}
+
+
+int dmDumpSpritesAndChars(FILE *inFile)
+{
+    int dataOffs, itemCount, outWidth, outWidthPX, outHeight;
+    size_t bufSize;
+    Uint8 *bufData;
+
+    switch (optInFormat)
+    {
+        case FFMT_CHAR:
+            bufSize = C64_CHR_SIZE;
+            outWidth = C64_CHR_WIDTH;
+            outWidthPX = C64_CHR_WIDTH_PX;
+            outHeight = C64_CHR_HEIGHT;
+            break;
+
+        case FFMT_SPRITE:
+            bufSize = C64_SPR_SIZE;
+            outWidth = C64_SPR_WIDTH;
+            outWidthPX = C64_SPR_WIDTH_PX;
+            outHeight = C64_SPR_HEIGHT;
+            break;
+
+        default:
+            dmError("Invalid input format %d, internal error.\n", optInFormat);
+            return -1;
+    }
+
+    if ((bufData = dmMalloc(bufSize)) == NULL)
+    {
+        dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize);
+        return -2;
+    }
+
+
+    dataOffs = optInSkip;
+    itemCount = 0;
+
+    if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII)
+    {
+        BOOL error = FALSE;
+        FILE *outFile;
+
+        if (optOutFilename == NULL)
+            outFile = stdout;
+        else
+        if ((outFile = fopen(optOutFilename, "w")) == NULL)
+        {
+            int res = dmGetErrno();
+            dmError("Error opening output file '%s', %d: %s\n",
+                  optOutFilename, res, dmErrorStr(res));
+            goto error;
+        }
+
+        while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount))
+        {
+            memset(bufData, 0, bufSize);
+
+            if (fread(bufData, 1, bufSize, inFile) != bufSize)
+            {
+                dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
+                    bufSize, dataOffs);
+                error = TRUE;
+            }
+            
+            fprintf(outFile, "---- : -------------- #%d\n", itemCount);
+
+            switch (optInFormat)
+            {
+                case FFMT_CHAR:
+                    dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
+                    break;
+                case FFMT_SPRITE:
+                    dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
+                    break;
+            }
+            itemCount++;
+        }
+
+        fclose(outFile);
+    }
+    else
+    if (optOutFormat == FFMT_IMAGE)
+    {
+        DMImage *outImage = NULL;
+        char *outFilename = NULL;
+        int outX = 0, outY = 0, err;
+
+        if (optSequential)
+        {
+            if (optOutFilename == NULL)
+            {
+                dmError("Sequential image output requires filename template.\n");
+                goto error;
+            }
+
+            outImage = dmImageAlloc(outWidthPX, outHeight);
+            dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n",
+                optItemCount,
+                outImage->width, outImage->height,
+                outImage->width * optSpec.scale, outImage->height * optSpec.scale);
+        }
+        else
+        {
+            int outIWidth, outIHeight;
+            if (optItemCount <= 0)
+            {
+                dmError("Single-image output requires count to be set (-n).\n");
+                goto error;
+            }
+            
+            outIWidth = optPlanedWidth;
+            outIHeight = (optItemCount / optPlanedWidth);
+            if (optItemCount % optPlanedWidth)
+                outIHeight++;
+            
+            outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight);
+        }
+
+        outImage->constpal = TRUE;
+        outImage->pal      = dmC64Palette;
+        outImage->ncolors  = C64_NCOLORS;
+        outImage->ctransp  = 255;
+        
+        while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount))
+        {
+            memset(bufData, 0, bufSize);
+
+            if (fread(bufData, 1, bufSize, inFile) != bufSize)
+            {
+                dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
+                    bufSize, dataOffs);
+                break;
+            }
+
+            if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight,
+                bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK)
+            {
+                dmError("Internal error in conversion of raw data to bitmap: %d.\n", err);
+                break;
+            }
+
+            if (optSequential)
+            {
+                outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext);
+                if (outFilename == NULL)
+                {
+                    dmError("Could not allocate memory for filename template?\n");
+                    goto error;
+                }
+                
+                dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
+                dmFree(outFilename);
+            }
+            else
+            {
+                if (++outX >= optPlanedWidth)
+                {
+                    outX = 0;
+                    outY++;
+                }
+            }
+            
+            itemCount++;
+        }
+
+        if (!optSequential)
+        {
+            dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
+        }
+        
+        dmImageFree(outImage);
+    }
+    else
+    if (optOutFormat == FFMT_BITMAP)
+    {
+        if (optSequential)
+        {
+            dmError("Sequential output not supported for spr/char -> bitmap conversion.\n");
+            goto error;
+        }
+    }
+
+    dmFree(bufData);
+    return 0;
+
+error:
+    dmFree(bufData);
+    return -1;
+}
+
+
+int main(int argc, char *argv[])
+{
+    FILE *inFile;
+    const DMC64ImageFormat *cfmt;
+    DMC64Image cimage;
+    Uint8 *dataBuf = NULL;
+    size_t dataSize;
+    int i;
+
+    // Default colors
+    for (i = 0; i < C64_MAX_COLORS; i++)
+        optColors[i] = i;
+
+    // Initialize and parse commandline
+    dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL);
+
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+#ifndef DM_USE_LIBPNG
+    if (optOutFormat == IMGFMT_PNG)
+    {
+        dmError("PNG output format support not compiled in, sorry.\n");
+        goto error;
+    }
+#endif
+
+    // Determine input format, if not specified'
+    if (optInFormat == FFMT_AUTO && optInFilename != NULL)
+    {
+        char *dext = strrchr(optInFilename, '.');
+        dmMsg(4, "Trying to determine file format by extension.\n");
+        if (dext)
+        {
+            dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat);
+        }
+    }
+
+    if (optInFilename == NULL)
+    {
+        if (optInFormat == FFMT_AUTO)
+        {
+            dmError("Standard input cannot be used without specifying input format.\n");
+            dmError("Perhaps you should try using --help\n");
+            goto error;
+        }
+        inFile = stdin;
+    }
+    else
+    if ((inFile = fopen(optInFilename, "rb")) == NULL)
+    {
+        int res = dmGetErrno();
+        dmError("Error opening input file '%s', %d: %s\n",
+              optInFilename, res, dmErrorStr(res));
+        goto error;
+    }
+
+    if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0)
+        goto error;
+
+    if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP)
+    {
+        // Probe for format
+        const DMC64ImageFormat *forced = NULL;
+        int res;
+
+        if (optForcedFormat >= 0)
+        {
+            forced = &dmC64ImageFormats[optForcedFormat];
+            dmMsg(0,"Forced %s format image, type %d, %s\n",
+                forced->name, forced->type, forced->fext);
+        }
+
+        res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced);
+        if (forced == NULL && cfmt != NULL)
+        {
+            dmMsg(1,"Probed %s format image, type %d, %s\n",
+                cfmt->name, cfmt->type, cfmt->fext);
+        }
+        
+        if (res == 0)
+            optInFormat = FFMT_BITMAP;
+    }
+
+    if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE)
+    {
+        DMImageFormat *ifmt = NULL;
+        int index;
+        dmMsg(4, "Trying to probe image formats.\n");
+        if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0)
+        {
+            optInFormat = FFMT_IMAGE;
+            optInSubFormat = index;
+            dmMsg(2, "Probed %s format image.\n", ifmt->fext);
+        }
+    }
+
+    if (optInFormat == FFMT_AUTO)
+    {
+        dmError("No input format specified, and could not be determined automatically.\n");
+        exit(1);
+    }
+
+    // Skip, if needed
+    if (fseek(inFile, optInSkip, SEEK_SET) != 0)
+    {
+        int res = dmGetErrno();
+        dmError("Could not seek to file position %d (0x%x): %s\n",
+            optInSkip, optInSkip, dmErrorStr(res));
+        goto error;
+    }
+    
+    int inFormat = dmGetConvFormat(optInFormat, optInSubFormat),
+        outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat);
+    
+    if (inFormat != -1 && outFormat != -1)
+    {
+        char *inFmtName = convFormatList[inFormat].name,
+             *inFmtExt = convFormatList[inFormat].fext,
+             *outFmtName = convFormatList[outFormat].name,
+             *outFmtExt = convFormatList[outFormat].fext;
+
+        if (optInFormat == FFMT_BITMAP)
+            inFmtExt = cfmt->name;
+
+        dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n",
+            inFmtName, inFmtExt, outFmtName, outFmtExt);
+    }
+
+    switch (optInFormat)
+    {
+        case FFMT_SPRITE:
+        case FFMT_CHAR:
+            dmDumpSpritesAndChars(inFile);
+            break;
+        
+        case FFMT_BITMAP:
+            {
+                DMImage *outImage = NULL;
+                int res = DMERR_OK;
+
+                if (optOutFilename == NULL)
+                {
+                    dmError("Output filename not set, required for image formats.\n");
+                    goto error;
+                }
+
+                switch (optOutFormat)
+                {
+                    case FFMT_IMAGE:
+                        res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE);
+
+                        if (res != DMERR_OK || outImage == NULL)
+                        {
+                            dmError("Error in bitmap to image conversion.\n");
+                            goto error;
+                        }
+
+                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
+                        break;
+
+
+                    case FFMT_BITMAP:
+                        res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE);
+                        break;
+
+                    case FFMT_CHAR:
+                    case FFMT_SPRITE:
+                        res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor);
+                        break;
+
+                    default:
+                        dmError("Unsupported output format for bitmap/image conversion.\n");
+                        break;
+                }
+                
+                dmImageFree(outImage);
+            }
+            break;
+
+        case FFMT_IMAGE:
+            {
+                DMImage *outImage = NULL;
+                int res = DMERR_OK;
+
+                if (optOutFilename == NULL)
+                {
+                    dmError("Output filename not set, required for image formats.\n");
+                    goto error;
+                }
+
+                // Read input
+                DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat];
+                if (ifmt->readFILE != NULL)
+                    res = ifmt->readFILE(inFile, &outImage);
+                else
+                    dmError("Unsupported input image format for bitmap/image conversion.\n");
+
+                if (res != DMERR_OK || outImage == NULL)
+                    break;
+                
+                switch (optOutFormat)
+                {
+                    case FFMT_IMAGE:
+                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
+                        break;
+
+                    case FFMT_CHAR:
+                    case FFMT_SPRITE:
+                        res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor);
+                        break;
+
+                    default:
+                        dmError("Unsupported output format for bitmap/image conversion.\n");
+                        break;
+                }
+                
+                dmImageFree(outImage);
+            }
+            break;
+    }
+
+    fclose(inFile);
+
+    dmFree(dataBuf);
+    exit(0);
+    return 0;
+
+error:
+    dmFree(dataBuf);
+    return -3;
+    exit(3);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/mod2wav.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,314 @@
+/*
+ * mod2wav - Render XM/JSSMOD module to WAV waveform file
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2007 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "jss.h"
+#include "jssmod.h"
+#include "jssmix.h"
+#include "jssplr.h"
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmwav.h"
+#include "dmmutex.h"
+
+
+char    *optInFilename = NULL, *optOutFilename = NULL;
+int     optOutFormat = JSS_AUDIO_S16,
+        optOutChannels = 2,
+        optOutFreq = 44100,
+        optMuteOChannels = -1,
+        optStartOrder = -1;
+BOOL    optUsePlayTime = FALSE;
+size_t  optPlayTime;
+
+
+DMOptArg optList[] =
+{
+    {  0, '?', "help",     "Show this help", OPT_NONE },
+    {  2, 'v', "verbose",  "Be more verbose", OPT_NONE },
+    {  3, '1', "16bit",    "16-bit output", OPT_NONE },
+    {  4, '8', "8bit",     "8-bit output", OPT_NONE },
+    {  5, 'm', "mono",     "Mono output", OPT_NONE },
+    {  6, 's', "stereo",   "Stereo output", OPT_NONE },
+    {  7, 'f', "freq",     "Output frequency", OPT_ARGREQ },
+    {  8, 'M', "mute",     "Mute other channels than #", OPT_ARGREQ },
+    {  9, 'o', "order",    "Start from order #", OPT_ARGREQ },
+    { 10, 't', "time",     "Play for # seconds", OPT_ARGREQ },
+//    {10, 'l', "loop",    "Loop for # times", OPT_ARGREQ },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+    
+    switch (optN)
+    {
+        case 0:
+            dmPrintBanner(stdout, dmProgName,
+                "[options] [sourcefile] [destfile]");
+                
+            dmArgsPrintHelp(stdout, optList, optListN);
+            exit(0);
+            break;
+
+        case 2:
+            dmVerbosity++;
+            break;
+        
+        case 3:
+            optOutFormat = JSS_AUDIO_S16;
+            break;
+
+        case 4:
+            optOutFormat = JSS_AUDIO_U8;
+            break;
+
+        case 5:
+            optOutChannels = JSS_AUDIO_MONO;
+            break;
+
+        case 6:
+            optOutChannels = JSS_AUDIO_STEREO;
+            break;
+
+        case 7:
+            optOutFreq = atoi(optArg);
+            break;
+
+        case 8:
+            optMuteOChannels = atoi(optArg);
+            break;
+
+        case 9:
+            optStartOrder = atoi(optArg);
+            break;
+
+        case 10:
+            optPlayTime = atoi(optArg);
+            optUsePlayTime = TRUE;
+            break;
+
+        default:
+            dmError("Unknown argument '%s'.\n", currArg);
+            return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    if (!optInFilename)
+        optInFilename = currArg;
+    else
+    if (!optOutFilename)
+        optOutFilename = currArg;
+    else
+    {
+        dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+int main(int argc, char *argv[])
+{
+    DMResource *inFile = NULL;
+    FILE *outFile = NULL;
+    JSSModule *mod = NULL;
+    JSSMixer *dev = NULL;
+    JSSPlayer *plr = NULL;
+    int result = -1;
+    size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize;
+    Uint8 *mb = NULL;
+
+    dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL);
+    dmVerbosity = 1;
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Check arguments
+    if (optInFilename == NULL || optOutFilename == NULL)
+    {
+        dmError("Input or output file not specified. Try --help.\n");
+        return 1;
+    }
+    
+    // Initialize miniJSS
+    jssInit();
+    
+    // Open the source file
+    if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL)
+    {
+        dmError("Error opening input file '%s', %d: %s\n",
+            optInFilename, errno, strerror(errno));
+        return 1;
+    }
+
+    // Read module file
+    fprintf(stderr, "Reading file: %s\n", optInFilename);
+#ifdef JSS_SUP_XM
+    fprintf(stderr, "* Trying XM...\n");
+    result = jssLoadXM(inFile, &mod);
+#endif
+#ifdef JSS_SUP_JSSMOD
+    if (result != 0)
+    {
+        size_t bufgot, bufsize = dmfsize(inFile);
+        Uint8 *buf = dmMalloc(bufsize);
+        dmfseek(inFile, 0L, SEEK_SET);
+        fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
+        if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize)
+        {
+            fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n",
+                bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile)));
+            return 2;
+        }
+        result = jssLoadJSSMOD(buf, bufsize, &mod);
+        dmFree(buf);
+    }
+#endif
+    dmf_close(inFile);
+    if (result != DMERR_OK)
+    {
+        dmError("Error loading module file, %d: %s\n",
+            result, dmErrorStr(result));
+        return 3;
+    }
+
+    // Try to convert it
+    if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK)
+    {
+        dmError("Could not convert module for playing, %d: %s\n",
+            result, dmErrorStr(result));
+        return 3;
+    }
+
+    // Open mixer
+    dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO);
+    if (dev == NULL)
+    {
+        dmError("jvmInit() returned NULL\n");
+        return 4;
+    }
+
+    sampSize = jvmGetSampleSize(dev);
+    if ((mb = dmMalloc(bufLen * sampSize)) == NULL)
+    {
+        dmError("Could not allocate mixing buffer\n");
+        return 5;
+    }
+    
+    dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n",
+        optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq,
+        sampSize);
+    
+    // Initialize player
+    if ((plr = jmpInit(dev)) == NULL)
+    {
+        dmError("jmpInit() returned NULL.\n");
+        return 6;
+    }
+    
+    // Set callback
+    jvmSetCallback(dev, jmpExec, plr);
+    
+    // Initialize playing
+    jmpSetModule(plr, mod);
+    if (optStartOrder >= 0)
+    { 
+        dmMsg(1, "Starting from song order #%d\n", optStartOrder);
+    } else
+        optStartOrder = 0;
+
+    jmpPlayOrder(plr, optStartOrder);
+    jvmSetGlobalVol(dev, 150);
+    
+    if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels)
+    {
+        int i;
+        for (i = 0; i < mod->nchannels; i++)
+            jvmMute(dev, i, TRUE);
+        jvmMute(dev, optMuteOChannels - 1, FALSE);
+    }
+    
+    // Open output file
+    if ((outFile = fopen(optOutFilename, "wb")) == NULL)
+    {
+        dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno));
+        return 7;
+    }
+
+    // Write initial header
+    dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024);
+
+    // Render audio data and output to file
+    if (optUsePlayTime)
+        dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime);
+    else
+        dmMsg(1, "Rendering module ...\n");
+    
+    optPlayTime *= optOutFreq;
+    dataTotal = 0;
+    dataWritten = 1;
+    while (plr->isPlaying && dataWritten > 0)
+    {
+        size_t writeLen = bufLen;
+        if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime)
+            writeLen = optPlayTime - dataTotal;
+        
+        if (writeLen > 0)
+        {
+            jvmRenderAudio(dev, mb, writeLen);
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+            jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess);
+#endif
+            dataWritten = fwrite(mb, sampSize, writeLen, outFile);
+            if (dataWritten < writeLen)
+            {
+                dmError("Error writing data!\n");
+                fclose(outFile);
+                return 8;
+            }
+            dataTotal += dataWritten;
+        }
+        
+        if (optUsePlayTime && dataTotal >= optPlayTime)
+            break;
+    }
+    
+    // Write the correct header
+    if (fseek(outFile, 0L, SEEK_SET) != 0)
+    {
+        dmError("Error rewinding to header position!\n");
+        return 9;
+    }
+    
+    dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal);
+    
+    // Done!
+    fclose(outFile);
+
+    jmpClose(plr);
+    jvmClose(dev);
+    jssFreeModule(mod);
+    jssClose();
+
+    dmMsg(1, "OK.\n");
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/objlink.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,990 @@
+/*
+ * objlink - Link files (RAW and PRG) into one PRG object
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2002-2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include <errno.h>
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmfile.h"
+#include "dmmutex.h"
+
+#define MAX_FILENAMES    (128)
+#define MAX_MEMBLOCKS    (128)
+
+
+/* Typedefs
+ */
+typedef struct
+{
+    ssize_t start, end;	// Start and end address
+    int type;           // Type
+    char *name;         // Name of the block
+    int placement;
+} DMMemBlock;
+
+typedef struct
+{
+    char *name;         // Description of memory model
+    char *desc;
+    ssize_t size;        // Total addressable memory size
+    ssize_t nmemBlocks;  // Defined memory areas
+    DMMemBlock memBlocks[MAX_MEMBLOCKS];
+} DMMemModel;
+
+typedef struct
+{
+    char *filename;
+    int type;
+    int placement;
+    ssize_t addr;
+} DMSourceFile;
+
+// Source file type
+enum
+{
+    STYPE_RAW = 1,
+    STYPE_PRG,
+    STYPE_PRGA
+};
+
+// How to determine block placement / address
+enum
+{
+    PLACE_STATIC = 1,  // Already known
+    PLACE_ARGUMENT,   // Commandline argument
+    PLACE_FILE,       // From file
+};
+
+enum
+{
+    FMT_GENERIC = 1,
+    FMT_PLAIN,
+    FMT_DECIMAL
+};
+
+enum
+{
+    MTYPE_NONE = 0,
+    MTYPE_ROM,        // Hard ROM
+    MTYPE_ROM_WT,     // Write to RAM through ROM
+    MTYPE_IO,         // I/O lines
+    MTYPE_RES         // RESERVED
+};
+
+enum
+{
+    LA_NONE = -2,
+    LA_AUTO = -1
+};
+
+/* Memory models
+ */
+const DMMemModel memoryModels[] = {
+    { "C64 unrestricted", "$01 = $34", (64*1024), 0, {
+    { 0, 0, 0, NULL, 0 }
+    }},
+
+    { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, {
+    { 0xA000, 0xBFFF,    MTYPE_ROM_WT,    "Basic ROM",  PLACE_STATIC },
+    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
+    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM",  PLACE_STATIC },
+    }},
+
+    { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, {
+    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
+    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM",  PLACE_STATIC },
+    }},
+
+    { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, {
+    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
+    }},
+
+    { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, {
+    { 0xA000, 0xBFFF,    MTYPE_ROM_WT,    "Basic ROM",  PLACE_STATIC },
+    { 0xD000, 0xDFFF,    MTYPE_ROM,       "Char ROM", PLACE_STATIC },
+    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM", PLACE_STATIC },
+    }},
+
+/*
+    { "C64 normal", "$01 = $37", (64*1024), 0, {
+    { 0x0000, 0x0000,    MTYPE_RAM,    "" },
+    }},
+*/
+};
+
+static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]);
+
+
+/* Global variables
+ */
+int           nsrcFiles = 0;              // Number of source files
+DMSourceFile  srcFiles[MAX_FILENAMES];    // Source file names
+
+int        nmemBlocks = 0;
+DMMemBlock memBlocks[MAX_FILENAMES];
+
+char       *optLinkFileName = NULL;
+int        optLinkFileFormat = FMT_GENERIC;
+
+BOOL       optDescribe = FALSE,
+           optAllowOverlap = FALSE;
+
+Uint32     optInitValue = 0;
+int        optInitValueType = 1;
+ssize_t    optCropStart, optCropEnd;
+BOOL       optCropOutput = FALSE;
+
+ssize_t    optLoadAddress = LA_AUTO;
+
+int        optMemModel = 0;
+const DMMemModel *memModel = NULL;
+Uint8      *memory = NULL;
+
+char       *optDestName = NULL;
+
+
+/* Arguments
+ */
+static DMOptArg optList[] = {
+    {  0, '?', "help",        "Show this help", OPT_NONE },
+    {  1, 'r', "input-raw",   "RAW input: -r <file>:<addr>", OPT_ARGREQ },
+    {  2, 'p', "input-prg",   "PRG input: -p <file>[:<addr>]", OPT_ARGREQ },
+    { 12, 's', "section",     "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ },
+    {  5, 'o', "output",      "Specify output file, -o <file>", OPT_ARGREQ },
+    {  6, 'O', "overlap",     "Allow overlapping memory areas", OPT_NONE },
+    {  7, 'm', "model",       "Set memory model", OPT_ARGREQ },
+    {  8, 'l', "link-file",   "Output addresses and labels into file", OPT_ARGREQ },
+    {  9, 'f', "format",      "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ },
+    { 10, 'i', "initvalue",   "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ },
+    { 11, 'd', "describe",    "Output ASCII memory map description", OPT_NONE },
+    { 13, 'c', "crop",        "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ },
+    { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    int i;
+
+    dmPrintBanner(stdout, dmProgName, "[options]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+
+    printf(
+    "\n"
+    "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n"
+    "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n"
+    "\n"
+    "Available memory models:\n");
+
+    for (i = 0; i < nmemoryModels; i++)
+    {
+        const DMMemModel *m = &memoryModels[i];
+        printf("  %d = %-40s [%s] (%d kB)\n",
+            i, m->name, m->desc, m->size / 1024);
+    }
+}
+
+
+off_t dmGetFileSize(FILE *f)
+{
+    off_t len, pos = ftell(f);
+    fseeko(f, 0, SEEK_END);
+    len = ftell(f);
+    fseek(f, pos, SEEK_SET);
+    return len;
+}
+
+
+/* Memory block handling
+ */
+void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType)
+{
+    if (startAddr > endAddr)
+    {
+        dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n",
+            blockName, startAddr, endAddr);
+        exit(4);
+    }
+
+    if (nmemBlocks < MAX_FILENAMES)
+    {
+        memBlocks[nmemBlocks].start = startAddr;
+        memBlocks[nmemBlocks].end   = endAddr;
+        memBlocks[nmemBlocks].name  = dm_strdup(blockName);
+        memBlocks[nmemBlocks].type  = blockType;
+        nmemBlocks++;
+    }
+    else
+    {
+        dmError("Maximum number of memBlock definitions (%d) exceeded!\n",
+            MAX_FILENAMES);
+        exit(4);
+    }
+}
+
+
+int compareMemBlock(const void *cva, const void *cvb)
+{
+    const DMMemBlock *a = cva, *b = cvb;
+    return a->start - b->start;
+}
+
+
+BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName)
+{
+    char sectMode, *sep, *str, *namesep;
+    ssize_t tmpi;
+
+    // Define reserved section
+    // Create a copy of the argument
+    if ((str = dm_strdup(arg)) == NULL)
+    {
+        dmError("Could not allocate temporary string!\n");
+        exit(128);
+    }
+
+    // Get start address
+    if ((sep = strchr(str, '-')) == NULL &&
+        (sep = strchr(str, ':')) == NULL)
+    {
+        dmError("Section definition '%s' invalid.\n", arg);
+        goto error;
+    }
+    sectMode = *sep;
+    *sep = 0;
+
+    // Get value
+    if (!dmGetIntVal(str, sectStart))
+    {
+        dmError("Section start address '%s' in '%s' invalid.\n", str, arg);
+        goto error;
+    }
+    
+    // Check for name
+    namesep = strchr(sep + 1, ',');
+    if (canHasName && namesep != NULL)
+    {
+        *namesep = 0;
+        namesep++;
+        if (*namesep == 0)
+        {
+            dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n",
+                arg);
+            goto error;
+        }
+        *sectName = dm_strdup(namesep);
+    }
+    else
+    if (namesep != NULL)
+    {
+        dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n",
+            arg, namesep);
+        goto error;
+    }
+
+    // Get end address or length
+    if (!dmGetIntVal(sep + 1, &tmpi))
+    {
+        dmError("Section %s '%s' in '%s' invalid.\n",
+            sectMode == '-' ? "end address" : "length",
+            sep + 1, arg);
+        goto error;
+    }
+
+    if (sectMode == ':')
+    {
+        *sectEnd = *sectStart + tmpi - 1;
+    }
+    else
+    {
+        if (tmpi < *sectStart)
+        {
+            dmError("Section start address > end address in '%s'.\n",
+                arg);
+            goto error;
+        }
+        *sectEnd = tmpi;
+    }
+
+    dmFree(str);
+    return TRUE;
+
+error:
+    dmFree(str);
+    return FALSE;
+}
+
+
+BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr)
+{
+    ssize_t tmpi = 0;
+    BOOL hasAddr = FALSE;
+    char *sep;
+
+    if ((sep = strrchr(arg, ':')) != NULL)
+    {
+        *sep = 0;
+        if (!dmGetIntVal(sep + 1, &tmpi))
+        {
+            dmError("Invalid %s address '%s' specified for '%s'.\n",
+                desc, sep + 1, arg);
+            return FALSE;
+        }
+        hasAddr = TRUE;
+    }
+    else
+    if (requireAddr)
+    {
+        dmError("No %s loading address specified for '%s'.\n", desc, arg);
+        return FALSE;
+    }
+
+    srcFiles[nsrcFiles].filename = arg;
+    srcFiles[nsrcFiles].type = hasAddr ? type1 : type2;
+    srcFiles[nsrcFiles].addr = tmpi;
+    nsrcFiles++;
+    return TRUE;
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    char *p;
+    ssize_t tmpi;
+
+    switch (optN) {
+    case 0:
+        argShowHelp();
+        exit(0);
+        break;
+
+    case 1:
+        // Add RAW
+        if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE))
+            return FALSE;
+        break;
+
+    case 2:
+        // Add PRG
+        if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE))
+            return FALSE;
+        break;
+
+    case 5:
+        // Set output file name
+        optDestName = optArg;
+        break;
+
+    case 6:
+        // Allow overlapping segments
+        optAllowOverlap = TRUE;
+        dmError("Warning, allowing overlapping data.\n");
+        break;
+
+    case 7:
+        // Set memory model
+        optMemModel = atoi(optArg);
+        if (optMemModel < 0 || optMemModel >= nmemoryModels)
+        {
+            dmError("Invalid memory model number %i!\n", optMemModel);
+            return FALSE;
+        }
+        break;
+
+    case 8:
+        // Linker file
+        optLinkFileName = optArg;
+        break;
+
+    case 9:
+        // Linker file format
+        switch (tolower(optArg[0]))
+        {
+            case 'g':
+                optLinkFileFormat = FMT_GENERIC;
+                break;
+            case 'p':
+                optLinkFileFormat = FMT_PLAIN;
+                break;
+            case 'd':
+                optLinkFileFormat = FMT_DECIMAL;
+                break;
+
+            default:
+                dmError("Invalid/unknown linker file format '%s'!\n",
+                    optArg);
+                return FALSE;
+        }
+        break;
+
+    case 10:
+        // Initialization value
+        optInitValueType = 1;
+        if ((p = strrchr(optArg, ':')) != NULL)
+        {
+            *p = 0;
+            switch (tolower(p[1]))
+            {
+                case 'b': optInitValueType = 1; break;
+                case 'w': optInitValueType = 2; break;
+                case 'd': optInitValueType = 4; break;
+                default:
+                    dmError("Invalid init value type '%c' specified for '%s'.\n",
+                        p[1], optArg);
+                    return FALSE; 
+            }
+        }
+        if (!dmGetIntVal(optArg, &tmpi))
+        {
+            dmError("Invalid initvalue '%s'.\n", optArg);
+            return FALSE;
+        }
+        optInitValue = tmpi;
+        break;
+
+    case 11:
+        // Set describe mode
+        optDescribe = TRUE;
+        break;
+
+    case 12:
+        {
+            char *sectName = "Clear";
+            ssize_t sectStart, sectEnd, sectLen;
+            if (!dmParseSection(optArg, &sectStart, &sectEnd, &sectName, TRUE))
+                return FALSE;
+
+            // Allocate memory block
+            sectLen = sectEnd - sectStart + 1;
+            dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n",
+                sectStart, sectEnd, sectLen, sectLen, sectName);
+
+            reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES);
+        }
+        break;
+
+    case 13:
+        {
+            size_t cropLen;
+            if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE))
+                return FALSE;
+
+            cropLen = optCropEnd - optCropEnd + 1;
+            dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n",
+                optCropStart, optCropEnd, cropLen, cropLen);
+
+            optCropOutput = TRUE;
+        }
+        break;
+
+    case 14:
+        // Set loading address
+        if (strcasecmp(optArg, "none") == 0)
+            optLoadAddress = LA_NONE;
+        else
+        {
+            if (!dmGetIntVal(optArg, &tmpi))
+            {
+                dmError("Invalid loading address '%s'.\n", optArg);
+                return FALSE;
+            }
+            if (tmpi < 0 || tmpi >= 64*1024)
+            {
+                dmError("Invalid or insane loading address %d/$%x!\n",
+                    tmpi);
+                return FALSE;
+            }
+            optLoadAddress = tmpi;
+        }
+        break;
+
+    default:
+        dmError("Unknown argument '%s'.\n", currArg);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr)
+{
+    FILE *f;
+    ssize_t dataSize, loadAddr, endAddr;
+    Uint16 tmpAddr;
+
+    // Open the input file
+    if ((f = fopen(filename, "rb")) == NULL)
+    {
+        dmError("Error opening input file '%s' (%s).\n",
+            filename, strerror(errno));
+        return 1;
+    }
+
+    // Get filesize
+    if ((dataSize = dmGetFileSize(f) - 2) < 0)
+    {
+        dmError("Error getting file size for '%s'.\n", filename);
+        return 6;
+    }
+
+    // Get loading address
+    if (!dm_fread_le16(f, &tmpAddr))
+    {
+        dmError("Error reading input file '%s' (%s).\n",
+            filename, strerror(errno));
+        return 2;
+    }
+
+    // Show information
+    loadAddr = forceAddr ? destAddr : tmpAddr;
+    endAddr = loadAddr + dataSize - 1;
+
+    dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x",
+        filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr);
+
+    if (endAddr >= memModel->size)
+    {
+        dmPrint(1, " .. Does not fit into the memory!\n");
+        return 5;
+    }
+
+    // Load data
+    if (fread(&memory[loadAddr], dataSize, 1, f) < 1)
+    {
+        dmPrint(1, " .. Error: %s.\n",
+            strerror(errno));
+        return 4;
+    }
+
+    dmPrint(1, " .. OK\n");
+
+    // Add to list of blocks
+    reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES);
+
+    return 0;
+}
+
+
+int dmLoadRAW(const char *filename, const ssize_t destAddr)
+{
+    FILE *f;
+    ssize_t dataSize, endAddr;
+
+    // Open the input file
+    if ((f = fopen(filename, "rb")) == NULL)
+    {
+        dmError("Error opening input file '%s' (%s).\n",
+            filename, strerror(errno));
+        return 1;
+    }
+
+    // Get filesize
+    if ((dataSize = dmGetFileSize(f)) < 0)
+    {
+        dmError("Error getting file size for '%s'.\n", filename);
+        return 6;
+    }
+
+    // Show information
+    endAddr = destAddr + dataSize - 1;
+    dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x",
+        filename, destAddr, endAddr);
+
+    if (endAddr >= memModel->size)
+    {
+        dmPrint(1, " .. Does not fit into the memory!\n");
+        return 5;
+    }
+
+    // Load data
+    if (fread(&memory[destAddr], dataSize, 1, f) < 1)
+    {
+        dmPrint(1, " .. Error: %s.\n",
+            strerror(errno));
+        return 4;
+    }
+
+    dmPrint(1, " .. OK\n");
+
+    // Add info to list
+    reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES);
+
+    return 0;
+}
+
+
+int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd)
+{
+    char *tmpStr, *s, *t;
+    int blockSize;
+
+    blockSize = (blockEnd - blockStart + 1);
+
+    // Create label name from filename
+    tmpStr = dm_strdup(blockName);
+    if (tmpStr == NULL)
+    {
+        dmError("Could not allocate memory for string '%s'!\n",
+            blockName);
+        return -1;
+    }
+
+    if ((t = strrchr(tmpStr, '/')))
+        s = (t + 1);
+    else if ((t = strrchr(tmpStr, '\\')))
+        s = (t + 1);
+    else
+        s = tmpStr;
+
+    if ((t = strrchr(s, '.')))
+        *t = 0;
+
+    for (t = s; *t; t++)
+    {
+        if (!isalnum(*t))
+            *t = '_';
+    }
+
+    // Print the label line
+    switch (optLinkFileFormat)
+    {
+        case FMT_PLAIN:
+            fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart);
+            break;
+
+        case FMT_DECIMAL:
+            fprintf(dfile, "%s = %d\n", tmpStr, blockStart);
+            break;
+
+        case FMT_GENERIC:
+        default:
+            fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n",
+                blockName, blockStart, blockEnd, blockSize, blockSize);
+            fprintf(dfile, "%s = $%.4x\n", s, blockStart);
+            break;
+    }
+
+    dmFree(tmpStr);
+    return 0;
+}
+
+
+/* Print out an ASCII presentation of memory map
+ */
+void memPrintLine(FILE *f)
+{
+    fprintf(f, "              +------------------------------------------+\n");
+}
+
+void memPrintEmpty(FILE *f, ssize_t n)
+{
+    ssize_t i;
+    for (i = 0; i < n; i++)
+    fprintf(f, "              |                                          |\n");
+}
+
+void dmDescribeMemory(FILE *f)
+{
+    int i;
+    DMMemBlock *prev = NULL;
+
+    memPrintLine(f);
+
+    for (i = 0; i < nmemBlocks; i++)
+    {
+        DMMemBlock *curr = &memBlocks[i];
+        char desc[512], *s;
+        ssize_t siz, kz;
+
+        // Check for empty, unreserved areas
+        siz = (curr->start - 1) - (prev->end + 1) + 1;
+        if (prev != NULL && siz > 1)
+        {
+            kz = siz / (1024 * 2);
+
+            if (kz > 1) memPrintEmpty(f, kz);
+
+            snprintf(desc, sizeof(desc), "EMPTY (%d)", siz);
+            fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc);
+
+            if (kz > 1) memPrintEmpty(f, kz);
+            memPrintLine(f);
+        }
+        prev = curr;
+
+        // Print current block
+        switch (curr->type)
+        {
+            case MTYPE_NONE:   s = "N/A (NC)"; break;
+            case MTYPE_ROM:    s = "ROM"; break;
+            case MTYPE_ROM_WT: s = "ROM/WT"; break;
+            case MTYPE_IO:     s = "I/O"; break;
+            case MTYPE_RES:    s = "RSVD"; break;
+            default:           s = "????"; break;
+        }
+
+        siz = curr->end - curr->start + 1;
+        kz = siz / (1024 * 2);
+
+        if (kz > 1) memPrintEmpty(f, kz);
+        snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz);
+        fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc);
+        if (kz > 1) memPrintEmpty(f, kz);
+        memPrintLine(f);
+
+    }
+
+    fprintf(f,
+    "\n"
+    "NC     = Not Connected\n"
+    "RSVD   = Reserved\n"
+    "ROM/WT = RAM under 'write-through' ROM\n"
+    "\n"
+    );
+}
+
+
+/*
+ * The main program
+ */
+int main(int argc, char *argv[])
+{
+    FILE *dfile = NULL;
+    BOOL hasOverlaps;
+    int i, j;
+    ssize_t startAddr, endAddr, dataSize, totalSize;
+
+    dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL);
+    dmVerbosity = 1;
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, NULL, TRUE))
+        exit(1);
+
+    if (nsrcFiles < 1)
+    {
+        dmError("Nothing to do. (try --help)\n");
+        exit(0);
+    }
+
+    // Allocate memory
+    memModel = &memoryModels[optMemModel];
+    dmMsg(1, "Using memory model #%d '%s', %d bytes.\n",
+        optMemModel, memModel->name, memModel->size);
+
+    memory = (Uint8 *) dmMalloc(memModel->size + 32);
+    if (memory == NULL)
+    {
+        dmError("Could not allocate memory.\n");
+        exit(2);
+    }
+
+    // Initialize memory
+    dmMsg(1, "Initializing memory with ");
+
+    if (optInitValueType == 1 || optInitValue <= 0xff)
+    {
+        dmPrint(1, "BYTE 0x%.2x\n", optInitValue);
+        memset(memory, optInitValue, memModel->size);
+    }
+    else
+    if (optInitValueType == 2 || optInitValue <= 0xffff)
+    {
+        uint16_t *mp = (uint16_t *) memory;
+        dmPrint(1, "WORD 0x%.4x\n", optInitValue);
+        for (i = memModel->size / sizeof(*mp); i; i--)
+        {
+            *mp++ = optInitValue;
+        }
+    }
+    else
+    {
+        Uint32 *mp = (Uint32 *) memory;
+        dmPrint(1, "DWORD 0x%.8x\n", optInitValue);
+        for (i = memModel->size / sizeof(*mp); i; i--)
+        {
+            *mp++ = optInitValue;
+        }
+    }
+
+    // Load the datafiles
+    for (i = 0; i < nsrcFiles; i++)
+    switch (srcFiles[i].type)
+    {
+        case STYPE_RAW:
+            dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr);
+            break;
+
+        case STYPE_PRG:
+            dmLoadPRG(srcFiles[i].filename, FALSE, 0);
+            break;
+
+        case STYPE_PRGA:
+            dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr);
+            break;
+    }
+
+    // Add memory model blocks
+    dmMsg(1, "Applying memory model restrictions...\n");
+    for (i = 0; i < memModel->nmemBlocks; i++)
+    {
+        reserveMemBlock(
+            memModel->memBlocks[i].start,
+            memModel->memBlocks[i].end,
+            memModel->memBlocks[i].name,
+            memModel->memBlocks[i].type);
+    }
+
+    // Sort the blocks
+    qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock);
+
+    // Check for overlapping conflicts
+    hasOverlaps = FALSE;
+    for (i = 0; i < nmemBlocks; i++)
+    for (j = 0; j < nmemBlocks; j++)
+    if (j != i && memBlocks[i].type == MTYPE_RES)
+    {
+        DMMemBlock *mbi = &memBlocks[i],
+                   *mbj = &memBlocks[j];
+
+        // Check for per-file conflicts
+        if ((mbj->start >= mbi->start && mbj->start <= mbi->end) ||
+            (mbj->end >= mbi->start && mbj->end <= mbi->end))
+        {
+            dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x  vs  $%.4x-$%.4x)\n",
+                mbi->name, mbj->name, mbi->start,
+                mbi->end, mbj->start, mbj->end);
+            hasOverlaps = TRUE;
+        }
+    }
+
+    if (!optAllowOverlap && hasOverlaps)
+    {
+        dmError("Error occured, overlaps not allowed.\n");
+        exit(5);
+    }
+
+    // Find out start and end-addresses
+    startAddr = memModel->size;
+    totalSize = endAddr = 0;
+    for (i = 0; i < nmemBlocks; i++)
+    {
+        DMMemBlock *mbi = &memBlocks[i];
+        if (mbi->type == MTYPE_RES)
+        {
+            if (mbi->start < startAddr)
+                startAddr = mbi->start;
+
+            if (mbi->end > endAddr)
+                endAddr = mbi->end;
+
+            totalSize += (mbi->end - mbi->start + 1);
+        }
+    }
+
+    if (startAddr >= memModel->size || endAddr < startAddr)
+    {
+        dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr);
+        exit(8);
+    }
+
+    // Output linkfile
+    if (optLinkFileName)
+    {
+        dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName);
+        if ((dfile = fopen(optLinkFileName, "wb")) == NULL)
+        {
+            dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno));
+            exit(1);
+        }
+
+        switch (optLinkFileFormat)
+        {
+            case FMT_GENERIC:
+            default:
+                fprintf(dfile, "; Definitions generated by %s v%s\n",
+                    dmProgName, dmProgVersion);
+                break;
+        }
+
+        for (i = 0; i < nmemBlocks; i++)
+        {
+            DMMemBlock *mbi = &memBlocks[i];
+            outputLinkData(dfile, mbi->name, mbi->start, mbi->end);
+        }
+
+        fclose(dfile);
+    }
+
+    // Show some information
+    if (optCropOutput)
+    {
+        startAddr = optCropStart;
+        endAddr = optCropEnd;
+    }
+
+    dataSize = endAddr - startAddr + 1;
+
+    if (dataSize - totalSize > 0)
+    {
+        dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n",
+            dataSize - totalSize, dataSize - totalSize);
+    }
+
+    dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ",
+        startAddr, endAddr, dataSize, dataSize);
+
+
+    // Open the destination file
+    if (optDestName == NULL)
+    {
+        dfile = stdout;
+        dmPrint(1, "...\n");
+    }
+    else if ((dfile = fopen(optDestName, "wb")) == NULL)
+    {
+        dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno));
+        exit(1);
+    }
+    else
+        dmPrint(1, "to '%s'\n", optDestName);
+
+    // Save loading address
+    if (optLoadAddress >= 0)
+    {
+        dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress);
+        dm_fwrite_le16(dfile, optLoadAddress);
+    }
+    else
+    if (optLoadAddress == LA_AUTO)
+    {
+        dmMsg(1, "Using automatic loading address $%.4x\n", startAddr);
+        dm_fwrite_le16(dfile, startAddr);
+    }
+    else
+    {
+        dmMsg(1, "Writing raw output, without loading address.\n");
+    }
+
+    // Save the data
+    if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1)
+    {
+        dmError("Error writing to file (%s)\n", strerror(errno));
+    }
+
+    fclose(dfile);
+
+    // Describe
+    if (optDescribe)
+        dmDescribeMemory(stdout);
+
+    exit(0);
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/packed.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,465 @@
+/*
+ * PACKed - PACKfile EDitor
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmpack.h"
+#include "dmpackutil.h"
+#include "dmres.h"
+#include "dmmutex.h"
+#include <errno.h>
+
+#define	SET_MAX_FILES	  (4096)
+#define SET_DEFAULT_PACK  "data.pak"
+
+enum
+{
+    CMD_NONE = 0,
+    CMD_CREATE,
+    CMD_ADD,
+    CMD_LIST,
+    CMD_EXTRACT
+} DCOMMAND;
+
+enum
+{
+    PACK_EXTRACTED = 0x0001,
+};
+
+int    nsrcFilenames = 0;
+char * srcFilenames[SET_MAX_FILES];
+char * optPackFilename = NULL;
+BOOL   optCompress = TRUE;
+int    optCommand = CMD_NONE;
+int    optDefResFlags = 0;
+
+
+static DMOptArg optList[] =
+{
+    { 0, '?', "help",        "Show this help", OPT_NONE },
+    { 1, 'p', "pack",        "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ },
+    { 2, 'c', "create",      "Create and add files to PACK", OPT_NONE },
+    { 3, 'a', "add",         "Add files to PACK", OPT_NONE },
+    { 4, 'l', "list",        "List files in PACK", OPT_NONE },
+    { 5, 'e', "extract",     "Extract files from PACK", OPT_NONE },
+    { 6, 'n', "nocompress",  "No compression", OPT_NONE },
+    { 7, 'v', "verbose",     "Increase verbosity", OPT_NONE },
+    { 8, 'f', "resflags",    "Set default resource flags (-f 0xff)", OPT_ARGREQ },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+    fprintf(stdout,
+    "\n"
+    "Examples:\n"
+    "$ %s -p test.pak -l         -- list files in test.pak\n"
+    "$ %s -a foobar.jpg          -- add foobar.jpg in " SET_DEFAULT_PACK "\n"
+    "$ %s -x foobar.jpg          -- extract foobar.jpg from " SET_DEFAULT_PACK "\n",
+    dmProgName, dmProgName, dmProgName);
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            optPackFilename = optArg;
+            break;
+        case 2:
+            optCommand = CMD_CREATE;
+            break;
+        case 3:
+            optCommand = CMD_ADD;
+            break;
+        case 4:
+            optCommand = CMD_LIST;
+            break;
+        case 5:
+            optCommand = CMD_EXTRACT;
+            break;
+
+        case 6:
+            optCompress = FALSE;
+            break;
+
+        case 7:
+            dmVerbosity++;
+            break;
+
+        case 8:
+            {
+                int i;
+                if (!dmGetIntVal(optArg, &i))
+                {
+                    dmError("Invalid flags value '%s'.\n", optArg);
+                    return FALSE;
+                }
+                optDefResFlags = i;
+            }
+            break;
+
+        default:
+            dmError("Unknown argument '%s'.\n", currArg);
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    if (nsrcFilenames < SET_MAX_FILES)
+    {
+        srcFilenames[nsrcFilenames] = currArg;
+        nsrcFilenames++;
+    }
+    else
+    {
+        dmError("Maximum number of input files (%d) exceeded!\n",
+              SET_MAX_FILES);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+/* Compare a string to a pattern. Case-SENSITIVE version.
+ * The matching pattern can consist of any normal characters plus
+ * wildcards ? and *. "?" matches any character and "*" matches
+ * any number of characters.
+ */
+BOOL dm_strmatch(const char *str, const char *pattern)
+{
+    BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE;
+    const char *tmpPattern = NULL;
+
+    // Check given pattern and string
+    if (str == NULL || pattern == NULL)
+        return FALSE;
+
+    // Start comparision
+    do {
+        didMatch = FALSE;
+        switch (*pattern)
+        {
+        case '?':
+            // Any single character matches
+            if (*str)
+            {
+                didMatch = TRUE;
+                pattern++;
+                str++;
+            }
+            break;
+
+        case '*':
+            didMatch = TRUE;
+            pattern++;
+            if (!*pattern)
+                isEnd = TRUE;
+            isAnyMode = TRUE;
+            tmpPattern = pattern;
+            break;
+
+        case 0:
+            if (isAnyMode)
+            {
+                if (*str)
+                    str++;
+                else
+                    isEnd = TRUE;
+            }
+            else
+            {
+                if (*str)
+                {
+                    if (tmpPattern)
+                    {
+                        isAnyMode = TRUE;
+                        pattern = tmpPattern;
+                    }
+                    else
+                        didMatch = FALSE;
+                }
+                else
+                    isEnd = TRUE;
+            }
+            break;
+        default:
+            if (isAnyMode)
+            {
+                if (*pattern == *str)
+                {
+                    isAnyMode = FALSE;
+                    didMatch = TRUE;
+                }
+                else
+                {
+                    if (*str)
+                    {
+                        didMatch = TRUE;
+                        str++;
+                    }
+                }
+            }
+            else
+            {
+                if (*pattern == *str)
+                {
+                    didMatch = TRUE;
+                    if (*pattern)
+                        pattern++;
+                    if (*str)
+                        str++;
+                }
+                else
+                {
+                    if (tmpPattern)
+                    {
+                        didMatch = TRUE;
+                        isAnyMode = TRUE;
+                        pattern = tmpPattern;
+                    }
+                }
+            }
+
+            if (!*str && !*pattern)
+                isEnd = TRUE;
+            break;
+
+        }        // switch
+
+    } while (didMatch && !isEnd);
+
+    return didMatch;
+}
+
+
+int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags)
+{
+    DMPackEntry *node;
+    int res = dm_pack_add_file(pack, filename, compression, resFlags, &node);
+
+    if (res != DMERR_OK)
+    {
+        dmPrint(1, "%-32s [ERROR:%d]\n",
+            filename, res);
+    }
+    else
+    {
+        char tmp[16];
+        dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags);
+        dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n",
+            filename, node->filename,
+            node->size, node->length, node->offset,
+            tmp);
+    }
+
+    return res;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int i, res = 0;
+    DMPackFile *pack = NULL;
+
+#ifndef __WIN32
+    stderr = stdout;
+#endif
+
+    // Parse arguments
+    dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL);
+    dmVerbosity = 1;
+    
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Check PACK filename
+    if (optPackFilename == NULL)
+        optPackFilename = SET_DEFAULT_PACK;
+
+    if (optCommand == CMD_NONE)
+    {
+        argShowHelp();
+        dmError("Nothing to do.\n");
+        exit(0);
+        return 0;
+    }
+    
+    dmMsg(1, "Processing %s ...\n", optPackFilename);
+
+    // Execute command
+    switch (optCommand)
+    {
+    case CMD_CREATE:
+    case CMD_ADD:
+        switch (optCommand)
+        {
+        case CMD_CREATE:
+            dmMsg(1, "Creating new PACK\n");
+            res = dm_pack_create(optPackFilename, &pack);
+            break;
+
+        case CMD_ADD:
+            dmMsg(1, "Opening existing PACK\n");
+            res = dm_pack_open(optPackFilename, &pack, FALSE);
+            break;
+        }
+
+        // Add files into PACK
+        if (res == DMERR_OK)
+        {
+            dmMsg(1, "Adding %d files...\n", nsrcFilenames);
+
+            for (i = 0; i < nsrcFilenames; i++)
+            {
+                // Handle resource definition files
+                if (srcFilenames[i][0] == '@')
+                {
+                }
+                else
+                {
+                    dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags);
+                }
+            }
+
+            dmMsg(1, "w=%d\n", dm_pack_write(pack));
+            dmMsg(1, "c=%d\n", dm_pack_close(pack));
+        }
+        else
+        {
+            dmError("Could not open packfile, error #%d: %s\n", res,
+                  dmErrorStr(res));
+        }
+        break;
+
+    case CMD_LIST:
+        // List files in PACK
+        res = dm_pack_open(optPackFilename, &pack, TRUE);
+        if (res == DMERR_OK)
+        {
+            DMPackEntry *node;
+            for (i = 0, node = pack->entries; node; i++)
+                node = node->next;
+            dmMsg(1, "%d files total\n", i);
+
+            dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n",
+                "Name", "Size", "CSize", "Offset", "ResFlags");
+
+            for (node = pack->entries; node != NULL; node = node->next)
+            {
+                BOOL match;
+                
+                // Check for matches
+                if (nsrcFilenames > 0)
+                {
+                    match = FALSE;
+                    for (i = 0; i < nsrcFilenames && !match; i++)
+                    {
+                        match = dm_strmatch(node->filename, srcFilenames[i]);
+                    }
+                }
+                else
+                    match = TRUE;
+
+                if (match)
+                {
+                    char flags[16];
+                    dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags);
+
+                    dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n",
+                        node->filename, node->size, node->length,
+                        node->offset, flags);
+                }
+            }
+
+            dmMsg(1, "c=%d\n", dm_pack_close(pack));
+        }
+        else
+            dmError("Could not open packfile, error #%d: %s\n", res,
+                  dmErrorStr(res));
+        break;
+
+    case CMD_EXTRACT:
+        // Extract files from PACK
+        res = dm_pack_open(optPackFilename, &pack, TRUE);
+        if (res == DMERR_OK)
+        {
+            DMPackEntry *node;
+            FILE *resFile = fopen(DMRES_RES_FILE, "w");
+            if (resFile == NULL)
+            {
+                dmError("Could not create resource output file '%s' #%d: %s\n",
+                    DMRES_RES_FILE, errno, strerror(errno));
+            }
+
+            for (node = pack->entries; node != NULL; node = node->next)
+            {
+                BOOL match;
+                
+                // Check for matches
+                if (nsrcFilenames > 0)
+                {
+                    match = FALSE;
+                    for (i = 0; (i < nsrcFilenames) && !match; i++)
+                    {
+                        match = dm_strmatch(node->filename, srcFilenames[i]);
+                    }
+                }
+                else
+                    match = TRUE;
+
+                if (match && (node->privFlags & PACK_EXTRACTED) == 0)
+                {
+                    char tmp[16];
+
+                    // Mark as done
+                    node->privFlags |= PACK_EXTRACTED;
+
+                    // Print one entry
+                    dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags);
+                    dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n",
+                            node->filename, node->size, node->length,
+                            node->offset, tmp);
+
+                    dm_pack_extract_file(pack, node);
+                    
+                    if (resFile != NULL)
+                    {
+                        fprintf(resFile,
+                        "%s|%s\n", node->filename, tmp);
+                    }
+                }
+            }
+
+            dmMsg(1, "c=%d\n", dm_pack_close(pack));
+            
+            if (resFile != NULL)
+                fclose(resFile);
+        }
+        else
+            dmError("Could not open packfile, error #%d: %s\n", res,
+                  dmErrorStr(res));
+        break;
+
+    }
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ppl.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,932 @@
+/*
+ * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include <SDL.h>
+#include "dmlib.h"
+
+#include "jss.h"
+#include "jssmod.h"
+#include "jssmix.h"
+#include "jssplr.h"
+
+#include "dmargs.h"
+#include "dmimage.h"
+#include "dmtext.h"
+
+#include "setupfont.h"
+
+
+struct
+{
+    BOOL exitFlag;
+    SDL_Surface *screen;
+    SDL_Event event;
+    int optScrWidth, optScrHeight, optVFlags, optScrDepth;
+
+    int actChannel;
+    BOOL pauseFlag;
+
+    JSSModule *mod;
+    JSSMixer *dev;
+    JSSPlayer *plr;
+    SDL_AudioSpec afmt;
+} engine;
+
+struct
+{
+    Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel;
+} col;
+
+
+DMBitmapFont *font = NULL;
+
+char    *optFilename = NULL;
+int     optOutFormat = JSS_AUDIO_S16,
+        optOutChannels = 2,
+        optOutFreq = 48000,
+        optMuteOChannels = -1,
+        optStartOrder = 0;
+BOOL    optUsePlayTime = FALSE;
+size_t  optPlayTime;
+
+
+DMOptArg optList[] =
+{
+    {  0, '?', "help",     "Show this help", OPT_NONE },
+    {  1, 'v', "verbose",  "Be more verbose", OPT_NONE },
+    {  2,   0, "fs",       "Fullscreen", OPT_NONE },
+    {  3, 'w', "window",   "Initial window size/resolution -w 640x480", OPT_ARGREQ },
+
+    {  4, '1', "16bit",    "16-bit output", OPT_NONE },
+    {  5, '8', "8bit",     "8-bit output", OPT_NONE },
+    {  6, 'm', "mono",     "Mono output", OPT_NONE },
+    {  7, 's', "stereo",   "Stereo output", OPT_NONE },
+    {  8, 'f', "freq",     "Output frequency", OPT_ARGREQ },
+
+    {  9, 'M', "mute",     "Mute other channels than #", OPT_ARGREQ },
+    { 10, 'o', "order",    "Start from order #", OPT_ARGREQ },
+    { 11, 't', "time",     "Play for # seconds", OPT_ARGREQ },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options] <module>");
+    dmArgsPrintHelp(stdout, optList, optListN);
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    switch (optN) {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            dmVerbosity++;
+            break;
+        
+        case 2:
+            engine.optVFlags |= SDL_FULLSCREEN;
+            break;
+
+        case 3:
+            {
+                int w, h;
+                if (sscanf(optArg, "%dx%d", &w, &h) == 2)
+                {
+                    if (w < 320 || h < 200 || w > 3200 || h > 3200)
+                    {
+                        dmError("Invalid width or height: %d x %d\n", w, h);
+                        return FALSE;
+                    }
+                    engine.optScrWidth = w;
+                    engine.optScrHeight = h;
+                }
+                else 
+                {
+                    dmError("Invalid size argument '%s'.\n", optArg);
+                    return FALSE;
+                }
+            }
+            break;
+
+        case 4:
+            optOutFormat = JSS_AUDIO_S16;
+            break;
+
+        case 5:
+            optOutFormat = JSS_AUDIO_U8;
+            break;
+
+        case 6:
+            optOutChannels = JSS_AUDIO_MONO;
+            break;
+
+        case 7:
+            optOutChannels = JSS_AUDIO_STEREO;
+            break;
+
+        case 8:
+            optOutFreq = atoi(optArg);
+            break;
+
+        case 9:
+            optMuteOChannels = atoi(optArg);
+            break;
+
+        case 10:
+            optStartOrder = atoi(optArg);
+            break;
+
+        case 11:
+            optPlayTime = atoi(optArg);
+            optUsePlayTime = TRUE;
+            break;
+
+        default:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    if (!optFilename)
+        optFilename = currArg;
+    else
+    {
+        dmError("Too many filename arguments '%s'\n", currArg);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt)
+{
+    const char *ptr = fmt;
+    DMUnscaledBlitFunc blit = NULL;
+
+    while (*ptr)
+    {
+        int ch = *ptr++;
+        SDL_Surface *glyph;
+
+        if (ch == '_')
+        {
+            xc += 4;
+            continue;
+        }
+        
+        if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL)
+        {
+            if (blit == NULL)
+                blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode);
+            
+            blit(glyph, xc, yc, screen);
+            xc += font->width;
+        }
+        else
+            xc += font->width;
+    }
+}
+
+
+void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap)
+{
+    char tmp[512];
+    vsnprintf(tmp, sizeof(tmp), fmt, ap);
+    dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp);
+}
+
+
+void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...)
+{
+    va_list ap;
+    
+    va_start(ap, fmt);
+    dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap);
+    va_end(ap);
+}
+
+
+Uint32 dmCol(float r, float g, float b)
+{
+    return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b);
+}
+
+
+BOOL dmInitializeVideo()
+{
+    SDL_FreeSurface(engine.screen);
+
+    engine.screen = SDL_SetVideoMode(
+        engine.optScrWidth, engine.optScrHeight, engine.optScrDepth,
+        engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE);
+
+    if (engine.screen == NULL)
+    {
+        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
+        return FALSE;
+    }
+
+    col.inboxBg    = dmCol(0.6, 0.5, 0.2);
+    col.boxBg      = dmCol(0.7, 0.6, 0.3);
+    col.box1       = dmCol(1.0, 0.9, 0.6);
+    col.box2       = dmCol(0.3, 0.3, 0.15);
+    col.viewDiv    = dmCol(0,0,0);
+    col.activeRow  = dmCol(0.5,0.4,0.1);
+    col.activeChannel = dmCol(0.6, 0.8, 0.2);
+
+    return TRUE;
+}
+
+
+void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn)
+{
+    int yh = y1 - y0 - 2;
+    if (yh < 10 || chn == NULL)
+        return;
+
+    int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume);
+    int pitch = screen->pitch / sizeof(Uint32);
+    int len = FP_GETH(chn->chSize);
+    DMFixedPoint offs = chn->chPos;
+    Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0);
+    Uint32 *pix = screen->pixels;
+    Sint16 *data = chn->chData;
+
+
+    dmFillBox3D(screen, x0, y0, x1, y1,
+        (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)),
+        nchannel == engine.actChannel ? colx : col.box2,
+        nchannel == engine.actChannel ? colx : col.box1);
+
+    if (chn->chData == NULL || !chn->chPlaying)
+        return;
+
+    if (chn->chDirection)
+    {
+        for (xc = x0 + 1; xc < x1 - 1; xc++)
+        {
+            if (FP_GETH(offs) >= len)
+                break;
+            Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255);
+            pix[xc + val * pitch] = coln;
+            FP_ADD(offs, chn->chDeltaO);
+        }
+    }
+    else
+    {
+        for (xc = x0 + 1; xc < x1 - 1; xc++)
+        {
+            if (FP_GETH(offs) < 0)
+                break;
+            Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255);
+            pix[xc + val * pitch] = coln;
+            FP_SUB(offs, chn->chDeltaO);
+        }
+    }
+}
+
+
+void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev)
+{
+    int nchannel, qx, qy,
+        qwidth = x1 - x0,
+        qheight = y1 - y0,
+        nwidth = jsetNChannels,
+        nheight = 1;
+    
+    if (qheight < 40)
+        return;
+    
+    while (qwidth / nwidth <= 60 && qheight / nheight >= 40)
+    {
+        nheight++;
+        nwidth /= nheight;
+    }
+
+//    fprintf(stderr, "%d x %d\n", nwidth, nheight);
+    
+    if (qheight / nheight <= 40)
+    {
+        nwidth = qwidth / 60;
+        nheight = qheight / 40;
+    }
+
+    qwidth /= nwidth;
+    qheight /= nheight;
+        
+    for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++)
+    {
+        for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++)
+        {
+            int xc = x0 + qx * qwidth,
+                yc = y0 + qy * qheight;
+
+            dmDisplayChn(screen, xc + 1, yc + 1,
+                xc + qwidth - 1, yc + qheight - 1,
+                nchannel, &dev->channels[nchannel]);
+
+            nchannel++;
+        }
+    }
+}
+
+
+static const char patNoteTable[12][3] =
+{
+    "C-", "C#", "D-",
+    "D#", "E-", "F-",
+    "F#", "G-", "G#",
+    "A-", "A#", "B-"
+};
+
+
+#define jmpNMODEffectTable (36)
+static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static const char jmpHexTab[16] = "0123456789ABCDEF";
+
+static inline char dmHexVal(int v)
+{
+    return jmpHexTab[v & 15];
+}
+
+void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n)
+{
+    char text[32];
+    char *ptr = text;
+    
+    switch (n->note)
+    {
+        case jsetNotSet:
+            strcpy(ptr, "..._");
+            break;
+        case jsetNoteOff:
+            strcpy(ptr, "===_");
+            break;
+        default:
+            sprintf(ptr, "%s%i_",
+                patNoteTable[n->note % 12],
+                n->note / 12);
+            break;
+    }
+
+    ptr += 4;
+
+    if (n->instrument != jsetNotSet)
+    {
+        int v = n->instrument + 1;
+        *ptr++ = dmHexVal(v >> 4);
+        *ptr++ = dmHexVal(v);
+    }
+    else
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+    *ptr++ = '_';
+
+    if (n->volume == jsetNotSet)
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+    else
+    if (n->volume >= 0x00 && n->volume <= 0x40)
+    {
+        *ptr++ = dmHexVal(n->volume >> 4);
+        *ptr++ = dmHexVal(n->volume);
+    }
+    else
+    {
+        char c;
+        switch (n->volume & 0xf0)
+        {
+            case 0x50: c = '-'; break;
+            case 0x60: c = '+'; break;
+            case 0x70: c = '/'; break;
+            case 0x80: c = '\\'; break;
+            case 0x90: c = 'S'; break;
+            case 0xa0: c = 'V'; break;
+            case 0xb0: c = 'P'; break;
+            case 0xc0: c = '<'; break;
+            case 0xd0: c = '>'; break;
+            case 0xe0: c = 'M'; break;
+            default:   c = '?'; break;
+        }
+        *ptr++ = c;
+        *ptr++ = dmHexVal(n->volume);
+    }
+    *ptr++ = '_';
+    
+    if (n->effect >= 0 && n->effect < jmpNMODEffectTable)
+        *ptr++ = jmpMODEffectTable[n->effect];
+    else
+        *ptr++ = (n->effect == jsetNotSet ? '.' : '?');
+
+    if (n->param != jsetNotSet)
+    {
+        *ptr++ = dmHexVal(n->param >> 4);
+        *ptr++ = dmHexVal(n->param);
+    }
+    else
+    {
+        *ptr++ = '.';
+        *ptr++ = '.';
+    }
+
+    *ptr = 0;
+
+    dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text);
+}
+
+
+void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row)
+{
+    int cwidth = (font->width * 10 + 3 * 4 + 5),
+        lwidth = 6 + font->width * 3,
+        qy0 = y0 + font->height + 2,
+        qy1 = y1 - font->height - 2,
+        qwidth  = ((x1 - x0 - lwidth) / cwidth),
+        qheight = ((qy1 - qy0 - 4) / (font->height + 1)),
+        nrow, nchannel, yc, choffs,
+        midrow = qheight / 2;
+
+    if (engine.actChannel < qwidth / 2)
+        choffs = 0;
+    else
+    if (engine.actChannel >= pat->nchannels - qwidth/2)
+        choffs = pat->nchannels - qwidth;
+    else
+        choffs = engine.actChannel - qwidth/2;
+
+    dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1);
+
+    for (nchannel = 0; nchannel < qwidth; nchannel++)
+    {
+        int bx0 = x0 + lwidth + 1 + nchannel * cwidth, 
+            bx1 = bx0 + cwidth;
+            
+        if (engine.actChannel == nchannel + choffs)
+        {
+            dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel);
+        }
+        else
+        {
+            dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg);
+        }
+    }
+
+    yc = qy0 + 2 + (font->height + 1) * midrow;
+    dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow);
+
+    for (nchannel = 0; nchannel < qwidth; nchannel++)
+    {
+        int bx0 = x0 + lwidth + 1 + nchannel * cwidth, 
+            bx1 = bx0 + cwidth;
+
+        dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv);
+
+        if (jvmGetMute(engine.dev, nchannel + choffs))
+        {
+            dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT,
+                bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED");
+        }
+        
+        dmDrawBMTextQ(screen, font, DMD_TRANSPARENT,
+            bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d",
+            nchannel + choffs);
+    }
+    
+    for (nrow = 0; nrow < qheight; nrow++)
+    {
+        int crow = nrow - midrow + row;
+        yc = qy0 + 2 + (font->height + 1) * nrow;
+        
+        if (crow >= 0 && crow < pat->nrows)
+        {
+            dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow);
+
+            for (nchannel = 0; nchannel < qwidth; nchannel++)
+            {
+                if (choffs + nchannel >= pat->nchannels)
+                    break;
+
+                dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc,
+                    pat->data + (pat->nchannels * crow) + choffs + nchannel);
+            }
+        }
+    }
+}
+
+
+void audioCallback(void *userdata, Uint8 *stream, int len)
+{
+    JSSMixer *d = (JSSMixer *) userdata;
+
+    if (d != NULL)
+    {
+        jvmRenderAudio(d, stream, len / jvmGetSampleSize(d));
+    }
+}
+
+
+void dmMuteChannels(BOOL mute)
+{
+    int i;
+    for (i = 0; i < engine.mod->nchannels; i++)
+        jvmMute(engine.dev, i, mute);
+}
+
+int main(int argc, char *argv[])
+{
+    BOOL initSDL = FALSE, audioInit = FALSE;
+    DMResource *file = NULL;
+    int result = -1;
+    BOOL muteState = FALSE;
+
+    memset(&engine, 0, sizeof(engine));
+
+    engine.optScrWidth = 640;
+    engine.optScrHeight = 480;
+    engine.optScrDepth = 32;
+
+    dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL);
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Open the files
+    if (optFilename == NULL)
+    {
+        dmError("No filename specified.\n");
+        return 1;
+    }
+    
+    if ((file = dmf_create_stdio(optFilename, "rb")) == NULL)
+    {
+        int err = dmGetErrno();
+        dmError("Error opening file '%s', %d: (%s)\n",
+            optFilename, err, dmErrorStr(err));
+        return 1;
+    }
+
+    // Initialize miniJSS
+    jssInit();
+
+    // Read module file
+    dmMsg(1, "Reading file: %s\n", optFilename);
+#ifdef JSS_SUP_XM
+    dmMsg(2, "* Trying XM...\n");
+    result = jssLoadXM(file, &engine.mod);
+#endif
+#ifdef JSS_SUP_JSSMOD
+    if (result != 0)
+    {
+        size_t bufgot, bufsize = dmfsize(file);
+        Uint8 *buf = dmMalloc(bufsize);
+        dmfseek(file, 0L, SEEK_SET);
+        dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
+        if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize)
+        {
+            dmf_close(file);
+            dmError("Error reading file (not enough data %d), #%d: %s\n",
+                bufgot, dmferror(file), dmErrorStr(dmferror(file)));
+            goto error_exit;
+        }
+        result = jssLoadJSSMOD(buf, bufsize, &engine.mod);
+        dmFree(buf);
+    }
+#endif
+    dmf_close(file);
+
+    if (result != DMERR_OK)
+    {
+        dmError("Error loading module file, %d: %s\n",
+            result, dmErrorStr(result));
+        goto error_exit;
+    }
+
+    // Try to convert it
+    if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK)
+    {
+        dmError("Could not convert module for playing, %d: %s\n",
+            result, dmErrorStr(result));
+        goto error_exit;
+    }
+
+    // Get font
+//    file = dmf_create_stdio("fnsmall.fnt", "rb");
+    file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont));
+    if (file == NULL)
+    {
+        dmError("Error opening font file 'pplfont.fnt'.\n");
+        goto error_exit;
+    }
+    result = dmLoadBitmapFont(file, &font);
+    dmf_close(file);
+    if (result != DMERR_OK)
+    {
+        dmError("Could not load font from file, %d: %s\n",
+            result, dmErrorStr(result));
+        goto error_exit;
+    }
+
+    // Initialize SDL components
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0)
+    {
+        dmError("Could not initialize SDL: %s\n", SDL_GetError());
+        goto error_exit;
+    }
+    initSDL = TRUE;
+
+
+    // Initialize mixing device
+    dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n",
+        optOutFormat, optOutChannels, optOutFreq);
+
+    engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO);
+    if (engine.dev == NULL)
+    {
+        dmError("jvmInit() returned NULL\n");
+        goto error_exit;
+    }
+    
+    switch (optOutFormat)
+    {
+        case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break;
+        case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break;
+        case JSS_AUDIO_S8:  engine.afmt.format = AUDIO_S8; break;
+        case JSS_AUDIO_U8:  engine.afmt.format = AUDIO_U8; break;
+        default:
+            dmError("Unsupported audio format %d (could not set matching SDL format)\n",
+                optOutFormat);
+            goto error_exit;
+    }
+
+    engine.afmt.freq     = optOutFreq;
+    engine.afmt.channels = optOutChannels;
+    engine.afmt.samples  = optOutFreq / 16;
+    engine.afmt.callback = audioCallback;
+    engine.afmt.userdata = (void *) engine.dev;
+
+    // Open the audio device
+    if (SDL_OpenAudio(&engine.afmt, NULL) < 0)
+    {
+        dmError("Couldn't open SDL audio: %s\n",
+            SDL_GetError());
+        goto error_exit;
+    }
+    audioInit = TRUE;
+    
+    // Initialize player
+    if ((engine.plr = jmpInit(engine.dev)) == NULL)
+    {
+        dmError("jmpInit() returned NULL\n");
+        goto error_exit;
+    }
+    
+    jvmSetCallback(engine.dev, jmpExec, engine.plr);
+    jmpSetModule(engine.plr, engine.mod);
+    jmpPlayOrder(engine.plr, optStartOrder);
+    jvmSetGlobalVol(engine.dev, 64);
+
+    if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels)
+    {
+        dmMuteChannels(TRUE);
+        jvmMute(engine.dev, optMuteOChannels, FALSE);
+        engine.actChannel = optMuteOChannels;
+        muteState = TRUE;
+    }
+
+    // Initialize video
+    if (!dmInitializeVideo())
+        goto error_exit;
+
+    SDL_WM_SetCaption(dmProgDesc, dmProgName);
+
+    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
+    // okay, main loop here ... "play" module and print out info
+    SDL_LockAudio();
+    SDL_PauseAudio(0);
+    SDL_UnlockAudio();
+
+    int currTick, prevTick = 0, prevRow = -1;
+    
+    while (!engine.exitFlag)
+    {
+        currTick = SDL_GetTicks();
+        BOOL force = (currTick - prevTick > 500), updated = FALSE;
+
+        while (SDL_PollEvent(&engine.event))
+        switch (engine.event.type)
+        {
+            case SDL_KEYDOWN:
+                switch (engine.event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE:
+                        engine.exitFlag = TRUE;
+                        break;
+                    
+                    case SDLK_SPACE:
+                        engine.pauseFlag = !engine.pauseFlag;
+                        SDL_PauseAudio(engine.pauseFlag);
+                        break;
+
+                    case SDLK_LEFT:
+                        if (engine.actChannel > 0)
+                        {
+                            engine.actChannel--;
+                            force = TRUE;
+                        }
+                        break;
+
+                    case SDLK_RIGHT:
+                        if (engine.actChannel < engine.mod->nchannels)
+                        {
+                            engine.actChannel++;
+                            force = TRUE;
+                        }
+                        break;
+
+                    case SDLK_m:
+                        if (engine.event.key.keysym.mod & KMOD_SHIFT)
+                        {
+                            muteState = !muteState;
+                            dmMuteChannels(muteState);
+                        }
+                        else
+                        if (engine.event.key.keysym.mod & KMOD_CTRL)
+                        {
+                            dmMuteChannels(FALSE);
+                        }
+                        else
+                        {
+                            jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel));
+                        }
+                        force = TRUE;
+                        break;
+
+                    case SDLK_PAGEUP:
+                        JSS_LOCK(engine.dev);
+                        JSS_LOCK(engine.plr);
+                        jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders));
+                        JSS_UNLOCK(engine.plr);
+                        JSS_UNLOCK(engine.dev);
+                        force = TRUE;
+                        break;
+
+                    case SDLK_PAGEDOWN:
+                        JSS_LOCK(engine.dev);
+                        JSS_LOCK(engine.plr);
+                        jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders));
+                        JSS_UNLOCK(engine.plr);
+                        JSS_UNLOCK(engine.dev);
+                        force = TRUE;
+                        break;
+
+                    case SDLK_f:
+                        engine.optVFlags ^= SDL_FULLSCREEN;
+                        if (!dmInitializeVideo())
+                            goto error_exit;
+                        force = TRUE;
+                        break;
+
+                    default:
+                        break;
+                }
+
+                break;
+
+            case SDL_VIDEORESIZE:
+                engine.optScrWidth = engine.event.resize.w;
+                engine.optScrHeight = engine.event.resize.h;
+
+                if (!dmInitializeVideo())
+                    goto error_exit;
+
+                break;
+
+            case SDL_VIDEOEXPOSE:
+                break;
+
+            case SDL_QUIT:
+                engine.exitFlag = TRUE;
+                break;
+        }
+
+
+#if 1
+        JSS_LOCK(engine.plr);
+        JSSPattern *currPattern = engine.plr->pattern;
+        int currRow = engine.plr->row;
+        if (!engine.plr->isPlaying)
+            engine.exitFlag = TRUE;
+        JSS_UNLOCK(engine.plr);
+        
+        if (currRow != prevRow || force)
+        {
+            prevRow = currRow;
+            force = TRUE;
+        }
+        
+        // Draw frame
+        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
+        {
+            dmError("Can't lock surface.\n");
+            goto error_exit;
+        }
+
+        if (force)
+        {
+            dmClearSurface(engine.screen, col.boxBg);
+            
+            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion);
+
+            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11,
+                "Song: '%s'",
+                engine.mod->moduleName);
+
+            dmDisplayPattern(engine.screen, 5, 40,
+                engine.screen->w - 6, engine.screen->h * 0.8,
+                currPattern, currRow);
+            
+            JSS_LOCK(engine.plr);
+            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12,
+            "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d",
+            engine.plr->tempo, engine.plr->speed,
+            engine.plr->row, engine.plr->pattern->nrows,
+            engine.plr->order, engine.mod->norders,
+            engine.plr->npattern, engine.mod->npatterns);
+            JSS_UNLOCK(engine.plr);
+            updated = TRUE;
+        }
+
+        if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20))
+        {
+            JSS_LOCK(engine.dev);
+            dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5,
+                engine.screen->w - 5, engine.screen->h - 5, engine.dev);
+            JSS_UNLOCK(engine.dev);
+            updated = TRUE;
+        }
+
+        if (force)
+            prevTick = currTick;
+
+#endif
+        // Flip screen
+        if (SDL_MUSTLOCK(engine.screen) != 0)
+            SDL_UnlockSurface(engine.screen);
+
+        if (updated)
+            SDL_Flip(engine.screen);
+
+        SDL_Delay(engine.pauseFlag ? 100 : 30);
+    }
+
+error_exit:
+    if (engine.screen)
+        SDL_FreeSurface(engine.screen);
+
+    dmMsg(0, "Audio shutdown.\n");
+    if (audioInit)
+    {
+        SDL_LockAudio();
+        SDL_PauseAudio(1);
+        SDL_UnlockAudio();
+        SDL_CloseAudio();
+    }
+
+    jmpClose(engine.plr);
+    jvmClose(engine.dev);
+    jssFreeModule(engine.mod);
+
+    dmFreeBitmapFont(font);
+
+    if (initSDL)
+        SDL_Quit();
+
+    jssClose();
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/svg2qd.py	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+import sys
+import re
+import xml.etree.ElementTree as ET
+
+
+def bf(x) :
+   return int(round(float(x)))
+
+
+def printVertex(v) :
+   if type(v) is list :
+      return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2])
+   else :
+      return v
+
+
+def getTransform(elem) :
+   if "transform" in elem.attrib :
+      ntrans = elem.attrib["transform"]
+      tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE)
+      for trns in tmatch.finditer(ntrans) :
+         coord = trns.group(1).split(",")
+         return [float(coord[0]), float(coord[1]), 0]
+   return None
+
+
+def getStyle(elem) :
+   style = {}
+   if "style" in elem.attrib :
+      for elem in elem.attrib["style"].split(";") :
+         kv = elem.split(":")
+         style[kv[0]] = kv[1]
+   return style
+
+
+def printVertices(type, vertices, width, level) :
+   if len(vertices) > 0 :
+      list = map(lambda v:printVertex(v), vertices)
+      str = "# "+ type
+      if type == "m" :
+         str = "R"
+      elif type == "M" :
+         str = "L"
+      elif type == "c" :
+         str = "R"
+      print "{}{}{} {} {}".format("  "*level, str, len(vertices)-1, " ".join(list), width)
+
+
+def printPath(path, level) :
+   style = getStyle(path)
+   width = bf(style["stroke-width"])
+
+   trans = getTransform(path)
+   if trans :
+      print "{}G{}".format("  "*level, printVertex(trans))
+
+   vertices = []
+   type = ""
+   for elem in path.attrib["d"].split(" ") :
+      if elem == "m" or elem == "M" :
+         printVertices(type, vertices, width, level)
+         vertices = []
+         type = elem
+      elif elem == "z" :
+         vertices.append("Z")
+      elif elem == "c" or elem == "C" :
+         print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"])
+         sys.exit(0)
+      else :
+         tmp = elem.split(",")
+         px = float(tmp[0])
+         py = float(tmp[1])
+         vertices.append([px, py, 0])
+
+   printVertices(type, vertices, width, level)
+   if trans :
+      print "{}E\n".format("  "*level)
+
+
+def iterateDocument(elems, level) :
+   for elem in elems:
+      if elem.tag == "{http://www.w3.org/2000/svg}g" :
+         print "\n{}# GROUP".format("  "*level)
+         tmp = getTransform(elem)
+         if tmp :
+            print "{}G{}".format("  "*level, printVertex(getTransform(elem)))
+            iterateDocument(elem, level + 1)
+            print "{}E\n".format("  "*level)
+         else :
+            iterateDocument(elem, level)
+      elif elem.tag == "{http://www.w3.org/2000/svg}path" :
+         printPath(elem, level)
+
+
+# Ns. paaohjelma
+if len(sys.argv) != 2 :
+   print "Usage: "+sys.argv[0]+" <input.svg>"
+   sys.exit(1)
+   
+tree = ET.parse(sys.argv[1])
+iterateDocument(tree.getroot(), 0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/view64.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,321 @@
+/*
+ * view64 - Display some C64 etc graphics formats via libSDL
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmfile.h"
+#include "lib64gfx.h"
+#include <SDL.h>
+
+
+char * optFilename = NULL;
+int    optVFlags = SDL_SWSURFACE | SDL_HWPALETTE;
+int    optScrWidth, optScrHeight;
+int    optForcedFormat = -1;
+
+
+static DMOptArg optList[] =
+{
+    { 0, '?', "help",       "Show this help", OPT_NONE },
+    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
+    { 2,   0, "fs",         "Fullscreen", OPT_NONE },
+    { 3, 'S', "scale",      "Scale image by factor (1-10)", OPT_ARGREQ },
+    { 4, 'f', "format",     "Force input format (see list below)", OPT_ARGREQ },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void dmSetScaleFactor(float factor)
+{
+    optScrWidth = (int) ((float) C64_SCR_WIDTH * factor * C64_SCR_PAR_XY);
+    optScrHeight = (int) ((float) C64_SCR_HEIGHT * factor);
+}
+
+
+void argShowHelp()
+{
+    int i;
+
+    dmPrintBanner(stdout, dmProgName, "[options] <input image file>");
+    dmArgsPrintHelp(stdout, optList, optListN);
+
+    printf("\nAvailable bitmap formats:\n");
+    for (i = 0; i < ndmC64ImageFormats; i++)
+    {
+        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
+        char buf[64];
+        printf("%3d | %-5s | %-15s | %s\n",
+            i, fmt->fext,
+            dmC64GetImageTypeString(buf, sizeof(buf), fmt->type),
+            fmt->name);
+    }
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            dmVerbosity++;
+            break;
+        
+        case 2:
+            optVFlags |= SDL_FULLSCREEN;
+            break;
+
+        case 3:
+            {
+                float factor;
+                if (sscanf(optArg, "%f", &factor) == 1)
+                {
+                    if (factor < 1 || factor >= 10)
+                    {
+                        dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor);
+                        return FALSE;
+                    }
+
+                    dmSetScaleFactor(factor);
+                }
+                else
+                {
+                    dmError("Invalid scale factor '%s'.\n", optArg);
+                    return FALSE;
+                }
+            }
+            break;
+
+        case 4:
+            {
+                int i;
+                if (sscanf(optArg, "%d", &i) == 1)
+                {
+                    if (i < 0 || i >= ndmC64ImageFormats)
+                    {
+                        dmError("Invalid image format index %d, see help for valid values.\n", i);
+                        return FALSE;
+                    }
+                    optForcedFormat = i;
+                }
+                else
+                {
+                    dmError("Invalid image format argument '%s'.\n", optArg);
+                    return FALSE;
+                }
+            }
+            break;
+        
+        default:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *filename)
+{
+    if (optFilename == NULL)
+    {
+        optFilename = dm_strdup(filename);
+        return TRUE;
+    }
+    else
+    {
+        dmError("Too many filenames specified ('%s')\n", filename);
+        return FALSE;
+    }
+}
+
+
+BOOL dmInitializeVideo(SDL_Surface **screen)
+{
+    *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
+    if (*screen == NULL)
+    {
+        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+int main(int argc, char *argv[])
+{
+    SDL_Surface *screen = NULL, *surf = NULL;
+    DMImage bmap;
+    BOOL initSDL = FALSE, exitFlag, needRedraw;
+    const DMC64ImageFormat *fmt = NULL, *forced;
+    DMC64Image image;
+    char *windowTitle;
+    Uint8 *dataBuf = NULL;
+    size_t dataSize;
+    int ret;
+
+    dmSetScaleFactor(2.0);
+    
+    dmInitProg("view64", "Display some C64 bitmap graphics formats", "0.2", NULL, NULL);
+
+    /* Parse arguments */
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, FALSE))
+        exit(1);
+
+
+    if (optFilename == NULL)
+    {
+        dmError("No input file specified, perhaps you need some --help\n");
+        goto error;
+    }
+        
+    if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK)
+        goto error;
+
+    dmMsg(1, "Read %d bytes of input.\n", dataSize);
+
+    // Probe for format
+    if (optForcedFormat >= 0)
+    {
+        forced = &dmC64ImageFormats[optForcedFormat];
+        dmMsg(0,"Forced %s format image, type %d, %s\n",
+            forced->name, forced->type, forced->fext);
+    }
+    else
+        forced = NULL;
+
+    ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced);
+    if (forced == NULL && fmt != NULL)
+    {
+        dmMsg(0,"Probed %s format image, type %d, %s\n",
+            fmt->name, fmt->type, fmt->fext);
+    }
+
+    if (ret < 0)
+    {
+        dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret);
+        return -1;
+    }
+
+
+    // Initialize libSDL
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
+    {
+        dmError("Could not initialize SDL: %s\n", SDL_GetError());
+        goto error;
+    }
+    initSDL = TRUE;
+
+
+    // Open window/set video mode
+    screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
+    if (screen == NULL)
+    {
+        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
+        goto error;
+    }
+
+    // Create surface (we are lazy and ugly)
+    surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_HEIGHT, 8, 0, 0, 0, 0);
+    SDL_SetColors(surf, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
+    SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
+
+    // Convert bitmap (this is a bit ugly and lazy here)
+    bmap.data = surf->pixels;
+    bmap.pitch = surf->pitch;
+    bmap.width = surf->w;
+    bmap.height = surf->h;
+    bmap.constpal = TRUE;
+
+    if (fmt->convertFrom != NULL)
+        ret = fmt->convertFrom(&bmap, &image, TRUE);
+    else
+        ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE);
+
+
+    // Set window title and caption
+    windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename);
+    SDL_WM_SetCaption(windowTitle, dmProgName);
+    dmFree(windowTitle);
+
+
+    // Start main loop
+    needRedraw = TRUE;
+    exitFlag = FALSE;
+    while (!exitFlag)
+    {
+        SDL_Event event;
+        while (SDL_PollEvent(&event))
+        switch (event.type)
+        {
+            case SDL_KEYDOWN:
+                switch (event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE: exitFlag = TRUE; break;
+                    
+                    default:
+                        break;
+                }
+
+                needRedraw = TRUE;
+                break;
+            
+            case SDL_VIDEORESIZE:
+                optScrWidth = event.resize.w;
+                optScrHeight = event.resize.h;
+
+                if (!dmInitializeVideo(&screen))
+                    goto error;
+
+                needRedraw = TRUE;
+                break;
+            
+            case SDL_VIDEOEXPOSE:
+                needRedraw = TRUE;
+                break;
+
+            case SDL_QUIT:
+                exit(0);
+        }
+        
+        if (needRedraw)
+        {
+            if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0)
+            {
+                dmError("Can't lock surface.\n");
+                goto error;
+            }
+            
+            dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, screen);
+            SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
+
+            if (SDL_MUSTLOCK(screen) != 0)
+                SDL_UnlockSurface(screen);
+
+            SDL_Flip(screen);
+            needRedraw = FALSE;
+        }
+        
+        SDL_Delay(100);
+    }
+
+
+error:
+    if (screen)
+        SDL_FreeSurface(screen);
+
+    if (initSDL)
+        SDL_Quit();
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/viewmod.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,475 @@
+/*
+ * viewmod - View information about given module file
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2006-2007 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "jss.h"
+#include "jssmod.h"
+#include <errno.h>
+#include <string.h>
+#include "dmargs.h"
+#include "dmmutex.h"
+
+
+char    *optFilename = NULL;
+BOOL    optViewPatterns = FALSE,
+        optViewInstruments = FALSE,
+        optViewExtInstruments = FALSE,
+        optViewGeneralInfo = FALSE;
+
+
+DMOptArg optList[] =
+{
+    { 0, '?', "help", "Show this help and exit", OPT_NONE },
+    { 1, 'p', "patterns", "View patterns", OPT_NONE },
+    { 2, 'i', "instruments", "View instruments", OPT_NONE },
+    { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE },
+    { 3, 'g', "general", "General information", OPT_NONE },
+    { 4, 'v', "verbose", "Be more verbose", OPT_NONE },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options] [modfile]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+    
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            optViewPatterns = TRUE;
+            break;
+
+        case 2:
+            optViewInstruments = TRUE;
+            break;
+
+        case 3:
+            optViewGeneralInfo = TRUE;
+            break;
+
+        case 4:
+            dmVerbosity++;
+            break;
+
+        case 5:
+            optViewExtInstruments = TRUE;
+            break;
+
+        default:
+            dmError("Unknown argument '%s'.\n", currArg);
+            return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    // Was not option argument
+    if (!optFilename)
+        optFilename = currArg;
+    else {
+        dmError("Gay error '%s'!\n", currArg);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+const char patNoteTable[12][3] =
+{
+    "C-", "C#", "D-",
+    "D#", "E-", "F-",
+    "F#", "G-", "G#",
+    "A-", "A#", "B-"
+};
+
+#define    jmpNMODEffectTable (36)
+static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+
+/* Print a given pattern
+ */
+void printPattern(FILE *f, JSSPattern *p)
+{
+    int i, j;
+    char c;
+    JSSNote *n;
+
+    if (!p)
+        return;
+
+    n = p->data;
+
+    for (i = 0; i < p->nrows; i++)
+    {
+        fprintf(f, "%.2x: ", i);
+
+        for (j = 0; j < p->nchannels; j++)
+        {
+            switch (n->note)
+            {
+            case jsetNotSet:
+                fprintf(f, "... ");
+                break;
+            case jsetNoteOff:
+                fprintf(f, "=== ");
+                break;
+            default:
+                fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12);
+                break;
+            }
+
+            if (n->instrument != jsetNotSet)
+                fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally
+            else
+                fprintf(f, ".. ");
+            
+            if (n->volume == jsetNotSet)
+                fprintf(f, ".. ");
+            else if (n->volume >= 0x00 && n->volume <= 0x40)
+                fprintf(f, "%.2x ", n->volume);
+            else
+            {
+                switch (n->volume & 0xf0)
+                {
+                    case 0x50: c = '-'; break;
+                    case 0x60: c = '+'; break;
+                    case 0x70: c = '/'; break;
+                    case 0x80: c = '\\'; break;
+                    case 0x90: c = 'S'; break;
+                    case 0xa0: c = 'V'; break;
+                    case 0xb0: c = 'P'; break;
+                    case 0xc0: c = '<'; break;
+                    case 0xd0: c = '>'; break;
+                    case 0xe0: c = 'M'; break;
+                    default:   c = '?'; break;
+                }
+                fprintf(f, "%c%x ", c, (n->volume & 0x0f));
+            }
+            
+            if (n->effect >= 0 && n->effect < jmpNMODEffectTable)
+                fprintf(f, "%c", jmpMODEffectTable[n->effect]);
+            else if (n->effect == jsetNotSet)
+                fprintf(f, ".");
+            else
+                fprintf(f, "?");
+
+            if (n->param != jsetNotSet)
+                fprintf(f, "%.2x|", n->param);
+            else
+                fprintf(f, "..|");
+
+            n++;
+        }
+
+        fprintf(f, "\n");
+    }
+}
+
+
+/*
+ * Print given extended instrument
+ */
+void printEnvelope(FILE *f, JSSEnvelope *e, char *s)
+{
+    int i;
+
+    fprintf(f,
+        "\t%s-envelope:\n"
+        "\t - flags.....: %.4x", s, e->flags);
+
+    if (e->flags & jenvfUsed)
+        fprintf(f, " [used]");
+    if (e->flags & jenvfSustain)
+        fprintf(f, " [sust]");
+    if (e->flags & jenvfLooped)
+        fprintf(f, " [loop]");
+
+    fprintf(f, "\n"
+        "\t - npoints...: %i\n"
+        "\t - sustain...: %i\n"
+        "\t - loopS.....: %i\n"
+        "\t - loopE.....: %i\n",
+        e->npoints, e->sustain, e->loopS, e->loopE);
+
+    if (dmVerbosity >= 2)
+    {
+        fprintf(f, "\t - Points....:");
+        for (i = 0; i < e->npoints; i++)
+        {
+            fprintf(f, " [%i:%i]",
+            e->points[i].frame, e->points[i].value);
+        }
+
+        fprintf(f, "\n");
+    }
+}
+
+
+void printExtInstrument(FILE *f, JSSExtInstrument *i)
+{
+    if (!i)
+    {
+        fprintf(f, "\n");
+        return;
+    }
+
+#ifndef JSS_LIGHT
+    if (i->desc)
+        fprintf(f,
+        "Description: '%s'\n", i->desc);
+#endif
+    fprintf(f,
+        "nsamples.......: %i\n"
+        "vibratoType....: %i\n"
+        "vibratoSweep...: %i\n"
+        "vibratoDepth...: %i\n"
+        "vibratoRate....: %i\n"
+        "fadeOut........: %i\n",
+        i->nsamples, i->vibratoType, i->vibratoSweep,
+        i->vibratoDepth, i->vibratoRate, i->fadeOut);
+
+    if (dmVerbosity >= 1)
+    {
+        printEnvelope(f, &i->volumeEnv, "Volume");
+        printEnvelope(f, &i->panningEnv, "Panning");
+    }
+    fprintf(f, "\n");
+}
+
+
+void printInstrument(FILE *f, JSSInstrument *i)
+{
+    if (!i)
+    {
+        fprintf(f, "\n");
+        return;
+    }
+
+    if (dmVerbosity >= 1)
+    {
+#ifndef JSS_LIGHT
+        if (i->desc)
+            fprintf(f, "Description: '%s'\n", i->desc);
+#endif
+        fprintf(f,
+            "size...........: %ld (0x%lx)\n"
+            "loopStart......: %ld (0x%lx)\n"
+            "loopEnd........: %ld (0x%lx)\n"
+            "volume.........: %d (0x%x)\n"
+            "flags..........: 0x%x ",
+            (unsigned long) i->size, (unsigned long) i->size,
+            (unsigned long) i->loopS, (unsigned long) i->loopE,
+            (unsigned long) i->loopS, (unsigned long) i->loopE,
+            i->volume, i->volume,
+            i->flags);
+        
+        if (i->flags & jsfLooped)  fprintf(f, "[loop] ");
+        if (i->flags & jsfBiDi)    fprintf(f, "[bi-di] ");
+        if (i->flags & jsf16bit)   fprintf(f, "[16bit] ");
+        
+        fprintf(f,
+            "\nC4BaseSpeed....: %d (0x%x)\n"
+            "ERelNote.......: %d (%s%d)\n"
+            "EFineTune......: %d\n"
+            "EPanning,,,....: %d (0x%x)\n\n",
+            i->C4BaseSpeed, i->C4BaseSpeed,
+            i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12,
+            i->EFineTune, i->EPanning, i->EPanning);
+    }
+    else
+    {
+#ifndef JSS_LIGHT
+        if (i->desc)
+            fprintf(f, "'%s', ", i->desc);
+#endif
+        fprintf(f,
+        "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n",
+        (unsigned long) i->size, (unsigned long) i->size,
+        (unsigned long) i->loopS, (unsigned long) i->loopE,
+        (unsigned long) i->loopS, (unsigned long) i->loopE,
+        i->volume, i->volume, i->flags, i->C4BaseSpeed,
+        i->C4BaseSpeed, i->ERelNote,
+        patNoteTable[(48 + i->ERelNote) % 12],
+        (48 + i->ERelNote) / 12, i->EFineTune,
+        i->EPanning, i->EPanning);
+    }
+}
+
+
+void printGeneralInfo(FILE *f, JSSModule *m)
+{
+    int i;
+    
+    if (!m)
+        return;
+
+    fprintf(f, "Module type.....: %i\n", m->moduleType);
+#ifndef JSS_LIGHT
+    if (m->moduleName)
+        fprintf(f, "Module name.....: '%s'\n", m->moduleName);
+    if (m->trackerName)
+        fprintf(f, "Tracker name....: '%s'\n", m->trackerName);
+#endif
+    fprintf(f,
+        "Speed...........: %d ticks\n"
+        "Tempo...........: %d bpm\n"
+        "Flags...........: %x ",
+        m->defSpeed, m->defTempo, m->defFlags);
+    
+    if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] ");
+    if (m->defFlags & jmdfAmigaLimits)  fprintf(f, "[Amiga limits] ");
+    if (m->defFlags & jmdfStereo)       fprintf(f, "[stereo] ");
+    if (m->defFlags & jmdfFT2Replay)    fprintf(f, "[FT2 replay] ");
+    if (m->defFlags & jmdfST300Slides)  fprintf(f, "[ST300 slides] ");
+    if (m->defFlags & jmdfByteLStart)   fprintf(f, "[ByteStart] ");
+    
+    fprintf(f, "\n"
+        "Restart pos.....: %d (order)\n"
+        "IntVersion......: %x\n"
+        "Channels........: %d\n"
+        "Instruments.....: %d\n"
+        "Ext.instruments.: %d\n"
+        "Patterns........: %d\n"
+        "Orders..........: %d\n",
+        m->defRestartPos, m->intVersion, m->nchannels,
+        m->ninstruments, m->nextInstruments, m->npatterns,
+        m->norders);
+
+    if (dmVerbosity >= 1)
+    {
+        fprintf(f, "Orderlist: ");
+        for (i = 0; i < m->norders - 1; i++)
+            fprintf(f, "%d, ", m->orderList[i]);
+        if (i < m->norders)
+            fprintf(f, "%d", m->orderList[i]);
+        fprintf(f, "\n");
+    }
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    int result = -1, i;
+    DMResource *file;
+    JSSModule *mod;
+
+    dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL);
+    dmVerbosity = 0;
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Initialize miniJSS
+    jssInit();
+
+    // Open the file
+    dmMsg(1, "Reading module file '%s'\n", optFilename);
+    if (optFilename == NULL)
+        file = dmf_create_stdio_stream(stdin);
+    else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL)
+    {
+        dmError("Error opening input file '%s'. (%s)\n",
+            optFilename, strerror(errno));
+        return 1;
+    }
+
+    // Read module file
+    dmMsg(1, "Reading file: %s\n", optFilename);
+#ifdef JSS_SUP_XM
+    dmMsg(1, "* Trying XM...\n");
+    result = jssLoadXM(file, &mod);
+#endif
+#ifdef JSS_SUP_JSSMOD
+    if (result != 0)
+    {
+        size_t bufgot, bufsize = dmfsize(file);
+        Uint8 *buf = dmMalloc(bufsize);
+        dmfseek(file, 0L, SEEK_SET);
+        dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
+        if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize)
+        {
+            dmError("Error reading file (not enough data %d), #%d: %s\n",
+                bufgot, dmferror(file), dmErrorStr(dmferror(file)));
+            return 2;
+        }
+        result = jssLoadJSSMOD(buf, bufsize, &mod);
+        dmFree(buf);
+    }
+#endif
+    dmf_close(file);
+    if (result != DMERR_OK)
+    {
+        dmError("Error loading module file, %d: %s\n",
+            result, dmErrorStr(result));
+        return 3;
+    }
+
+    // Print out information
+    if (optViewGeneralInfo)
+        printGeneralInfo(stdout, mod);
+
+    if (optViewPatterns)
+    {
+        for (i = 0; i < mod->npatterns; i++)
+        {
+            printf("\nPattern #%03i:\n", i);
+            printPattern(stdout, mod->patterns[i]);
+        }
+    }
+
+    if (optViewExtInstruments)
+    {
+        printf("\n"
+        "ExtInstruments:\n"
+        "---------------\n"
+        );
+        for (i = 0; i < mod->nextInstruments; i++)
+        {
+            printf("#%03i: ", i + 1);
+            printExtInstrument(stdout, mod->extInstruments[i]);
+        }
+    }
+
+    if (optViewInstruments)
+    {
+        printf("\n"
+        "Instruments:\n"
+        "------------\n"
+        );
+        for (i = 0; i < mod->ninstruments; i++)
+        {
+            printf("#%03i: ", i + 1);
+            printInstrument(stdout, mod->instruments[i]);
+        }
+    }
+
+    // Free module data
+    jssFreeModule(mod);
+    jssClose();
+
+    exit(0);
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xm2jss.c	Tue Apr 16 06:04:22 2013 +0300
@@ -0,0 +1,1040 @@
+/*
+ * xm2jss - Convert XM module to JSSMOD
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2006-2009 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include "jss.h"
+#include "jssmod.h"
+#include "jssplr.h"
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmres.h"
+#include "dmmutex.h"
+
+
+#define jmpNMODEffectTable (36)
+static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+
+char  *optInFilename = NULL, *optOutFilename = NULL;
+BOOL  optIgnoreErrors = FALSE,
+      optStripExtInstr = FALSE,
+      optStripInstr = FALSE,
+      optStripSamples = FALSE,
+      optOptimize = FALSE;
+
+int   optPatternMode = PATMODE_COMP_HORIZ,
+      optSampMode16 = jsampDelta,
+      optSampMode8 = jsampFlipSign | jsampDelta;
+
+#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta)
+
+
+static const char* patModeTable[PATMODE_LAST] =
+{
+    "Raw horizontal",
+    "Compressed horizontal (similar to XM modules)",
+    "Raw vertical",
+    "Compressed vertical",
+    "Raw vertical for each element",
+};
+
+
+DMOptArg optList[] = {
+    { 0, '?', "help",           "Show this help", OPT_NONE },
+    { 1, 'v', "verbose",        "Be more verbose", OPT_NONE },
+    { 2, 'i', "ignore",         "Ignore errors", OPT_NONE },
+    { 3, 'p', "patterns",       "Pattern storage mode", OPT_ARGREQ },
+    { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE },
+    { 5, 'I', "strip-instr",    "Strip instruments (implies -S)", OPT_NONE },
+    { 6, 'S', "strip-samples",  "Strip instr. sampledata", OPT_NONE },
+    { 7, '8', "smode8",         "8-bit sample conversion flags", OPT_ARGREQ },
+    { 8, '1', "smode16",        "16-bit sample conversion flags", OPT_ARGREQ },
+    { 9, 'O', "optimize",       "Optimize module", OPT_NONE },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    int i;
+
+    dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>");
+    dmArgsPrintHelp(stdout, optList, optListN);
+
+    printf("\n"
+    "Pattern storage modes:\n");
+    
+    for (i = 1; i < PATMODE_LAST; i++)
+        printf("  %d = %s\n", i, patModeTable[i-1]);
+    
+    printf(
+    "\n"
+    "Sample data conversion flags (summative):\n"
+    "  1 = Delta encoding (DEF 8 & 16)\n"
+    "  2 = Flip signedness (DEF 8)\n"
+    "  4 = Swap endianess (affects 16-bit only)\n"
+    "  8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n"
+    "\n"
+    );
+}
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+    
+    switch (optN)
+    {
+    case 0:
+        argShowHelp();
+        exit(0);
+        break;
+
+    case 1:
+        dmVerbosity++;
+        break;
+
+    case 2:
+        optIgnoreErrors = TRUE;
+        break;
+
+    case 3:
+        optPatternMode = atoi(optArg);
+        if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST)
+        {
+            dmError("Unknown pattern conversion mode %d\n", optPatternMode);
+            return FALSE;
+        }
+        break;
+
+    case 4: optStripExtInstr = TRUE; break;
+    case 5: optStripInstr = TRUE; break;
+    case 6: optStripSamples = TRUE; break;
+
+    case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break;
+    case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break;
+
+    case 9: optOptimize = TRUE; break;
+
+    default:
+        dmError("Unknown argument '%s'.\n", currArg);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    // Was not option argument
+    if (!optInFilename)
+        optInFilename = currArg;
+    else
+    if (!optOutFilename)
+        optOutFilename = currArg;
+    else
+    {
+        dmError("Too many filename arguments specified, '%s'.\n", currArg);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+/* These functions and the macro mess are meant to make the
+ * conversion routines themselves clearer and simpler.
+ */
+BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val)
+{
+    if (*npatBuf >= patBufSize)
+        return FALSE;
+    else
+    {
+        patBuf[*npatBuf] = val;
+        (*npatBuf)++;
+        return TRUE;
+    }
+}
+
+#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0)
+
+#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0)
+
+#define JSCOMPPUT(xf,xv,qv)  do {                       \
+    if (qflags & (xf)) {                                \
+        if ((xv) < 0 || (xv) > 255)                     \
+            JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,        \
+            "%s value out of bounds %d.\n", qv, (xv));  \
+        JSPUTBYTE(xv);                                  \
+    }                                                   \
+} while (0)
+
+#define JSCONVPUT(xv,qv)    do {                        \
+    if ((xv) != jsetNotSet) {                           \
+        if ((xv) < 0 || (xv) > 254)                     \
+            JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,        \
+            "%s value out of bounds %d.\n", qv, (xv));  \
+        JSPUTBYTE((xv) + 1);                            \
+    } else {                                            \
+        JSPUTBYTE(0);                                   \
+    }                                                   \
+} while (0)
+
+
+/* Convert a note
+ */
+static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note)
+{
+    Uint8 tmp;
+    if (note->note == jsetNotSet)
+        tmp = 0;
+    else if (note->note == jsetNoteOff)
+        tmp = 127;
+    else
+        tmp = note->note + 1;
+
+    if (tmp > 0x7f)
+        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
+
+    JSPUTBYTE(tmp & 0x7f);
+    
+    JSCONVPUT(note->instrument, "Instrument");
+    JSCONVPUT(note->volume, "Volume");
+    JSCONVPUT(note->effect, "Effect");
+    
+    tmp = (note->param != jsetNotSet) ? note->param : 0;
+    JSPUTBYTE(tmp);
+    
+    return DMERR_OK;
+}
+
+
+/* Compress a note
+ */
+static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note)
+{
+    Uint8 qflags = 0;
+    int qcomp = 0;
+    
+    JSCOMP(note->note,       COMP_NOTE);
+    JSCOMP(note->instrument, COMP_INSTRUMENT);
+    JSCOMP(note->volume,     COMP_VOLUME);
+    JSCOMP(note->effect,     COMP_EFFECT);
+    if (note->param != jsetNotSet && note->param != 0)
+    {
+        qflags |= COMP_PARAM;
+        qcomp++;
+    }
+    
+    if (qcomp < 4)
+    {
+        JSPUTBYTE(qflags | 0x80);
+        
+        if (note->note != jsetNotSet)
+        {
+            Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127;
+            if (tmp > 0x7f)
+                JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
+            JSPUTBYTE(tmp);
+        }
+        
+        JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument");
+        JSCOMPPUT(COMP_VOLUME, note->volume, "Volume");
+        JSCOMPPUT(COMP_EFFECT, note->effect, "Effect");
+        JSCOMPPUT(COMP_PARAM, note->param, "Param");
+    } else
+        return jssConvertNote(patBuf, patBufSize, patSize, note);
+    
+    return DMERR_OK;
+}
+
+
+/* Compress pattern
+ */
+static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
+{
+    int row, channel;
+    *patSize = 0;
+    
+    for (row = 0; row < pattern->nrows; row++)
+    for (channel = 0; channel < pattern->nchannels; channel++)
+    {
+        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
+        const int res = jssCompressNote(patBuf, patBufSize, patSize, note);
+        if (res != DMERR_OK)
+        {
+            JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
+            patBuf, patBufSize, *patSize, row, channel);
+            return res;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
+{
+    int row, channel;
+    *patSize = 0;
+    
+    for (channel = 0; channel < pattern->nchannels; channel++)
+    for (row = 0; row < pattern->nrows; row++)
+    {
+        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
+        const int res = jssCompressNote(patBuf, patBufSize, patSize, note);
+        if (res != DMERR_OK)
+        {
+            JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
+            patBuf, patBufSize, *patSize, row, channel);
+            return res;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+/* Convert a pattern
+ */
+static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
+{
+    int row, channel;
+    *patSize = 0;
+    
+    for (row = 0; row < pattern->nrows; row++)
+    for (channel = 0; channel < pattern->nchannels; channel++)
+    {
+        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
+        const int res = jssConvertNote(patBuf, patBufSize, patSize, note);
+        if (res != DMERR_OK)
+        {
+            JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
+            patBuf, patBufSize, *patSize, row, channel);
+            return res;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
+{
+    int row, channel;
+    *patSize = 0;
+    
+    for (channel = 0; channel < pattern->nchannels; channel++)
+    for (row = 0; row < pattern->nrows; row++)
+    {
+        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
+        const int res = jssConvertNote(patBuf, patBufSize, patSize, note);
+        if (res != DMERR_OK)
+        {
+            JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
+            patBuf, patBufSize, *patSize, row, channel);
+            return res;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+#define JSFOREACHNOTE1                                                              \
+  for (channel = 0; channel < pattern->nchannels; channel++)                        \
+  for (row = 0; row < pattern->nrows; row++) {                                      \
+  const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
+
+#define JSFOREACHNOTE2 }
+
+static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
+{
+    Uint8 tmp;
+    int row, channel;
+    *patSize = 0;
+    
+    JSFOREACHNOTE1;
+    if (note->note == jsetNotSet)
+        tmp = 0;
+    else if (note->note == jsetNoteOff)
+        tmp = 127;
+    else
+        tmp = note->note + 1;
+    if (tmp > 0x7f)
+        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
+    JSPUTBYTE(tmp);
+    JSFOREACHNOTE2;
+    
+    JSFOREACHNOTE1;
+    JSCONVPUT(note->instrument, "Instrument");
+    JSFOREACHNOTE2;
+    
+    JSFOREACHNOTE1;
+    JSCONVPUT(note->volume, "Volume");
+    JSFOREACHNOTE2;
+    
+    JSFOREACHNOTE1;
+    JSCONVPUT(note->effect, "Effect");
+    JSFOREACHNOTE2;
+    
+    JSFOREACHNOTE1;
+    tmp = (note->param != jsetNotSet) ? note->param : 0;
+    JSPUTBYTE(tmp);
+    JSFOREACHNOTE2;
+    
+    return DMERR_OK;
+}
+
+#undef JSFOREACHNOTE1
+#undef JSFOREACHNOTE2
+
+
+static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e)
+{
+    int i;
+    
+    je->flags   = e->flags;
+    je->npoints = e->npoints;
+    je->sustain = e->sustain;
+    je->loopS   = e->loopS;
+    je->loopE   = e->loopE;
+    
+    for (i = 0; i < e->npoints; i++)
+    {
+        je->points[i].frame = e->points[i].frame;
+        je->points[i].value = e->points[i].value;
+    }
+}
+
+
+/* Save a JSSMOD file
+ */
+int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16)
+{
+    JSSMODHeader jssH;
+    int i, pattern, order, instr, totalSize;
+    const size_t patBufSize = 64*1024; // 64kB pattern buffer
+    Uint8 *patBuf;
+
+    // Check the module
+    if (m == NULL)
+        JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n");
+
+    if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1))
+        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,
+        "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n",
+        m->nchannels, m->npatterns, m->norders);
+
+    // Create the JSSMOD header
+    jssH.idMagic[0]         = 'J';
+    jssH.idMagic[1]         = 'M';
+    jssH.idVersion          = JSSMOD_VERSION;
+    jssH.norders            = m->norders;
+    jssH.npatterns          = m->npatterns;
+    jssH.nchannels          = m->nchannels;
+    jssH.nextInstruments    = m->nextInstruments;
+    jssH.ninstruments       = m->ninstruments;
+    jssH.defFlags           = m->defFlags;
+    jssH.intVersion         = m->intVersion;
+    jssH.defRestartPos      = m->defRestartPos;
+    jssH.defSpeed           = m->defSpeed;
+    jssH.defTempo           = m->defTempo;
+    jssH.patMode            = patMode;
+    
+    // Write header
+    totalSize = sizeof(jssH);
+    if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1)
+        JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n");
+
+    dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize);
+
+    // Write orders list
+    for (totalSize = order = 0; order < m->norders; order++)
+    {
+        Uint16 tmp = m->orderList[order];
+        totalSize += sizeof(tmp);
+        if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1)
+            JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n");
+    }
+
+    dmMsg(1," * %d item orders list, %d bytes.\n",
+        m->norders, totalSize);
+
+    // Allocate pattern compression buffer
+    if ((patBuf = dmMalloc(patBufSize)) == NULL)
+        JSSERROR(DMERR_MALLOC, DMERR_MALLOC,
+        "Error allocating memory for pattern compression buffer.\n");
+
+    
+    // Write patterns
+    for (totalSize = pattern = 0; pattern < m->npatterns; pattern++)
+    {
+        JSSMODPattern patHead;
+        size_t finalSize = 0;
+        
+        switch (patMode)
+        {
+            case PATMODE_RAW_HORIZ:
+                i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
+                break;
+            case PATMODE_COMP_HORIZ:
+                i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
+                break;
+            case PATMODE_RAW_VERT:
+                i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
+                break;
+            case PATMODE_COMP_VERT:
+                i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
+                break;
+            case PATMODE_RAW_ELEM:
+                i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
+                break;
+            default:
+                i = DMERR_INVALID_DATA;
+                dmFree(patBuf);
+                JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA,
+                "Unsupported pattern conversion mode %d.\n", patMode);
+                break;
+        }
+
+        if (i != DMERR_OK)
+        {
+            dmFree(patBuf);
+            JSSERROR(i, i, "Error converting pattern data #%i\n", pattern);
+        }
+        else
+        {
+            dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize);
+            patHead.nrows = m->patterns[pattern]->nrows;
+            patHead.size = finalSize;
+            totalSize += finalSize + sizeof(patHead);
+
+            if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1)
+            {
+                dmFree(patBuf);
+                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
+                "Error writing pattern #%d header\n", pattern);
+            }
+
+            if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize)
+            {
+                dmFree(patBuf);
+                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
+                "Error writing pattern #%d data\n", pattern);
+            }
+        }
+    }
+    dmFree(patBuf);
+    dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize);
+
+    // Write extended instruments
+    for (totalSize = instr = 0; instr < m->nextInstruments; instr++)
+    {
+        JSSMODExtInstrument jssE;
+        JSSExtInstrument *einst = m->extInstruments[instr];
+        
+        memset(&jssE, 0, sizeof(jssE));
+
+        if (einst)
+        {
+            // Create header
+            jssE.nsamples = einst->nsamples;
+            for (i = 0; i < jsetNNotes; i++)
+            {
+                int snum = einst->sNumForNotes[i];
+                jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0;
+            }
+            
+            jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv));
+            jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv));
+            jssE.vibratoType  = einst->vibratoType;
+            jssE.vibratoSweep = einst->vibratoSweep;
+            jssE.vibratoDepth = einst->vibratoDepth;
+            jssE.fadeOut      = einst->fadeOut;
+        } else
+            JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr);
+        
+        // Write to file
+        totalSize += sizeof(jssE);
+        if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1)
+            JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
+            "Could not write JSSMOD extended instrument #%i to file!\n", instr);
+    }
+    dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize);
+
+
+    // Write sample instrument headers
+    for (totalSize = instr = 0; instr < m->ninstruments; instr++)
+    {
+        JSSMODInstrument jssI;
+        JSSInstrument *pInst = m->instruments[instr];
+
+        memset(&jssI, 0, sizeof(jssI));
+
+        // Create header
+        if (pInst)
+        {
+            jssI.size         = pInst->size;
+            jssI.loopS        = pInst->loopS;
+            jssI.loopE        = pInst->loopE;
+            jssI.volume       = pInst->volume;
+            jssI.flags        = pInst->flags;
+            jssI.C4BaseSpeed  = pInst->C4BaseSpeed;
+            jssI.ERelNote     = pInst->ERelNote;
+            jssI.EFineTune    = pInst->EFineTune;
+            jssI.EPanning     = pInst->EPanning;
+            jssI.hasData      = (pInst->data != NULL) ? TRUE : FALSE;
+            jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8;
+        }
+        else 
+            JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr);
+        
+        // Write to file
+        totalSize += sizeof(jssI);
+        if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1)
+            JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
+             "Could not write JSSMOD instrument #%i to file!\n", instr);
+    }
+    dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize);
+    
+    // Write sample data
+    for (totalSize = instr = 0; instr < m->ninstruments; instr++)
+    if (m->instruments[instr])
+    {
+        JSSInstrument *inst = m->instruments[instr];
+        if (inst->data != NULL)
+        {
+            size_t res;
+            if (inst->flags & jsf16bit)
+            {
+                jssEncodeSample16(inst->data, inst->size, flags16);
+                res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile);
+            }
+            else
+            {
+                jssEncodeSample8(inst->data, inst->size, flags8);
+                res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile);
+            }
+            
+            totalSize += inst->size;
+            if (res != (size_t) inst->size)
+                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
+                 "Could not write JSSMOD sample #%i to file!\n", instr);
+        }
+    }
+    dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize);
+    
+    return DMERR_OK;
+}
+
+
+/* Optimize a given module
+ */
+JSSModule *optimizeModule(JSSModule *m)
+{
+    BOOL usedPatterns[jsetMaxPatterns + 1],
+         usedInstruments[jsetMaxInstruments + 1],
+         usedExtInstruments[jsetMaxInstruments + 1];
+    int  mapExtInstruments[jsetMaxInstruments + 1],
+         mapInstruments[jsetMaxInstruments + 1],
+         mapPatterns[jsetMaxPatterns + 1];
+    JSSModule *r = NULL;
+    int i, n8, n16;
+
+    // Allocate a new module
+    if ((r = jssAllocateModule()) == NULL)
+        return NULL;
+
+    // Allocate tables
+    
+    // Copy things
+    r->moduleType       = m->moduleType;
+    r->moduleName       = dm_strdup(m->moduleName);
+    r->trackerName      = dm_strdup(m->trackerName);
+    r->defSpeed         = m->defSpeed;
+    r->defTempo         = m->defTempo;
+    r->defFlags         = m->defFlags;
+    r->defRestartPos    = m->defRestartPos;
+    r->intVersion       = m->intVersion;
+    r->nchannels        = m->nchannels;
+    r->norders          = m->norders;
+    for (i = 0; i < jsetNChannels; i++)
+        r->defPanning[i] = m->defPanning[i];
+    
+    // Initialize values
+    for (i = 0; i <= jsetMaxInstruments; i++)
+    {
+        usedExtInstruments[i] = FALSE;
+        usedInstruments[i] = FALSE;
+        mapExtInstruments[i] = jsetNotSet;
+        mapInstruments[i] = jsetNotSet;
+    }
+    
+    for (i = 0; i <= jsetMaxPatterns; i++)
+    {
+        usedPatterns[i] = FALSE;
+        mapPatterns[i] = jsetNotSet;
+    }
+
+    // Find out all used patterns and ext.instruments
+    for (i = 0; i < m->norders; i++)
+    {
+        int pattern = m->orderList[i];
+        if (pattern >= 0 && pattern < m->npatterns)
+        {
+            JSSPattern *p = m->patterns[pattern];
+            if (p != NULL)
+            {
+                int row, channel;
+                JSSNote *n = p->data;
+                
+                // Mark pattern as used
+                usedPatterns[pattern] = TRUE;
+                
+                // Check all notes
+                for (row = 0; row < p->nrows; row++)
+                for (channel = 0; channel < p->nchannels; channel++, n++)
+                {
+                    if (n->instrument != jsetNotSet)
+                    {
+                        if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments))
+                            usedExtInstruments[n->instrument] = TRUE;
+                        else
+                            dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n",
+                            pattern, row, channel, n->instrument);
+                    }
+                }
+            }
+            else
+            {
+                dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n",
+                pattern, i);
+            }
+        }
+        else
+        if (pattern != jsetMaxPatterns)
+        {
+            dmError("Order 0x%x has invalid pattern number 0x%x!\n",
+            i, pattern);
+        }
+    }
+    
+    // Find out used instruments
+    for (i = 0; i <= jsetMaxInstruments; i++)
+    if (usedExtInstruments[i] && m->extInstruments[i] != NULL)
+    {
+        int note;
+        JSSExtInstrument *e = m->extInstruments[i];
+        
+        for (note = 0; note < jsetNNotes; note++)
+        if (e->sNumForNotes[note] != jsetNotSet)
+        {
+            int q = e->sNumForNotes[note];
+            if (q >= 0 && q < m->ninstruments)
+            {
+                usedInstruments[q] = TRUE;
+            }
+            else
+            {
+                dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n",
+                i, m->ninstruments, q);
+            }
+        }
+    }
+    
+    // Create pattern mappings
+    r->npatterns = 0;
+    dmMsg(1, "Unused patterns: ");
+        
+    for (i = 0; i <= jsetMaxPatterns; i++)
+    if (m->patterns[i] != NULL)
+    {
+        if (!usedPatterns[i])
+        {
+            dmPrint(2, "0x%x, ", i);
+        }
+        else
+        {
+            if (i >= m->npatterns)
+                dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns);
+            
+            mapPatterns[i] = r->npatterns;
+            r->patterns[r->npatterns] = m->patterns[i];
+            (r->npatterns)++;
+        }
+    }
+    dmPrint(2, "\n");
+    
+    dmMsg(1, "%d used patterns, %d unused.\n",
+    r->npatterns, m->npatterns - r->npatterns);
+    
+    
+    // Re-map instruments
+    dmMsg(1, "Unused instruments: ");
+    for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++)
+    if (m->instruments[i] != NULL)
+    {
+        if (!usedInstruments[i] && !optStripInstr)
+        {
+            dmPrint(2, "0x%x, ", i);
+        }
+        else
+        {
+            JSSInstrument *ip = m->instruments[i];
+            if (i >= m->ninstruments)
+                dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments);
+            
+            mapInstruments[i] = r->ninstruments;
+            r->instruments[r->ninstruments] = ip;
+            (r->ninstruments)++;
+
+            if (ip->flags & jsf16bit)
+                n16++;
+            else
+                n8++;
+        }
+    }
+    dmPrint(2, "\n");
+    dmMsg(1, "Total of (%d)  16-bit, (%d) 8-bit samples, (%d) instruments.\n",
+    n16, n8, r->ninstruments);
+    
+    // Re-map ext.instruments
+    dmMsg(1, "Unused ext.instruments: ");
+    for (i = 0; i < jsetMaxInstruments; i++)
+    if (usedExtInstruments[i])
+    {
+        if (i >= m->nextInstruments && !optStripExtInstr)
+        {
+            dmError("Ext.instrument 0x%x >= 0x%x, but used!\n",
+            i, m->nextInstruments);
+        }
+        else
+        if (m->extInstruments[i] != NULL)
+        {
+            JSSExtInstrument *e = m->extInstruments[i];
+            int note;
+            
+            mapExtInstruments[i] = r->nextInstruments;
+            r->extInstruments[r->nextInstruments] = e;
+            (r->nextInstruments)++;
+            
+            // Re-map sNumForNotes
+            for (note = 0; note < jsetNNotes; note++)
+            {
+                int q = e->sNumForNotes[note];
+                if (q != jsetNotSet)
+                {
+                    int map;
+                    if (q >= 0 && q <= jsetMaxInstruments)
+                    {
+                        map = mapInstruments[q];
+                    }
+                    else
+                    {
+                        map = jsetNotSet;
+                        dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments);
+                    }
+                    e->sNumForNotes[note] = map;
+                }
+            }
+        }
+        else
+        {
+            dmPrint(2, "[0x%x==NULL], ", i);
+            mapExtInstruments[i] = jsetNotSet;
+        }
+    }
+    else
+    {
+        if (i < m->nextInstruments && m->extInstruments[i] != NULL)
+        {
+            dmPrint(2, "0x%x, ", i);
+        }
+    }
+    dmPrint(2, "\n");
+    dmMsg(1, "%d extended instruments.\n", r->nextInstruments);
+    
+    
+    // Remap pattern instrument data
+    for (i = 0; i < r->npatterns; i++)
+    {
+        int row, channel;
+        JSSPattern *p = r->patterns[i];
+        JSSNote *n = p->data;
+        
+        for (row = 0; row < p->nrows; row++)
+        for (channel = 0; channel < p->nchannels; channel++, n++)
+        {
+            char effect;
+
+            if (!optStripExtInstr)
+            {
+                if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments)
+                    n->instrument = mapExtInstruments[n->instrument];
+
+                if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL)
+                    dmError("Non-existing instrument used #%d.\n", n->instrument);
+            }
+
+            JMPGETEFFECT(effect, n->effect);
+            
+            switch (effect)
+            {
+                case 'C': // Cxx = Set volume
+                    if (n->volume == jsetNotSet)
+                    {
+                        n->volume = n->param;
+                        n->effect = jsetNotSet;
+                        n->param = jsetNotSet;
+                    }
+                    break;
+            }
+        }
+    }
+    
+    // Remap orders list
+    for (i = 0; i < m->norders; i++)
+    {
+        r->orderList[i] = mapPatterns[m->orderList[i]];
+    }
+
+    return r;
+}
+
+
+int main(int argc, char *argv[])
+{
+    DMResource *sfile = NULL;
+    FILE *dfile = NULL;
+    JSSModule *sm, *dm;
+    int result;
+
+    dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL);
+    dmVerbosity = 0;
+
+    // Parse arguments
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Check arguments
+    if (optInFilename == NULL || optOutFilename == NULL)
+    {
+        dmError("Input or output file not specified. Try --help.\n");
+        return 1;
+    }
+
+    // Read the source file
+    if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL)
+    {
+        dmError("Error opening input file '%s', %d: %s\n",
+            optInFilename, errno, strerror(errno));
+        return 1;
+    }
+
+    // Initialize miniJSS
+    jssInit();
+
+    // Read file
+    dmMsg(1, "Reading XM-format file ...\n");
+    result = jssLoadXM(sfile, &sm);
+    dmf_close(sfile);
+    if (result != 0)
+    {
+        dmError("Error while loading XM file (%i), ", result);
+        if (optIgnoreErrors)
+            fprintf(stderr, "ignoring. This may cause problems.\n");
+        else
+        {
+            fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n");
+            return 2;
+        }
+    }
+
+    // Check stripping settings
+    if (optStripExtInstr) optStripInstr = TRUE;
+    if (optStripInstr) optStripSamples = TRUE;
+    
+    // Remove samples
+    if (optStripSamples)
+    {
+        int i;
+        
+        dmMsg(1, "Stripping samples...\n");
+        for (i = 0; i < sm->ninstruments; i++)
+        {
+            dmFree(sm->instruments[i]->data);
+            sm->instruments[i]->data = NULL;
+        }
+    }
+
+    // Remove instruments
+    if (optStripInstr)
+    {
+        int i;
+        
+        dmMsg(1, "Stripping instruments...\n");
+        for (i = 0; i < sm->ninstruments; i++)
+        {
+            dmFree(sm->instruments[i]);
+            sm->instruments[i] = NULL;
+        }
+        sm->ninstruments = 0;
+    }
+
+    // Remove ext.instruments
+    if (optStripExtInstr)
+    {
+        int i;
+        
+        dmMsg(1, "Stripping ext.instruments...\n");
+        for (i = 0; i < sm->nextInstruments; i++)
+        {
+            dmFree(sm->extInstruments[i]);
+            sm->extInstruments[i] = NULL;
+        }
+        sm->nextInstruments = 0;
+    }
+    // Run the optimization procedure
+    if (optOptimize)
+    {
+        dmMsg(1, "Optimizing module data...\n");
+        dm = optimizeModule(sm);
+    } else
+        dm = sm;
+
+    // Write output file
+    if ((dfile = fopen(optOutFilename, "wb")) == NULL)
+    {
+        dmError("Error creating output file '%s', %d: %s\n",
+            optOutFilename, errno, strerror(errno));
+        return 1;
+    }
+
+    dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n",
+        optPatternMode, optSampMode8, optSampMode16);
+    
+    result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16);
+    
+    fclose(dfile);
+    
+    if (result != 0)
+    {
+        dmError("Error while saving JSSMOD file, %d: %s\n",
+            result, dmErrorStr(result));
+        dmError("WARNING: The resulting file may be broken!\n");
+    }
+    else
+    {
+        dmMsg(1, "Conversion complete.\n");
+    }
+    return 0;
+}
--- a/utils/data2inc.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,404 +0,0 @@
-/*
- * data2inc - Convert binary data to "C"-source or XA-compatible include file
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include <errno.h>
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmmutex.h"
-
-#define RA_LINEBUF    (16)
-
-enum
-{
-    FMT_AUTO = 0,
-    FMT_C,
-    FMT_ASM
-};
-
-char    *optInFilename = NULL,
-        *optOutFilename = NULL,
-        *optObjName = "default_object",
-        *optDataType = NULL,
-        *optAddLine = NULL;
-
-int     optIndentation = -1;
-int     optFormat = FMT_AUTO;
-BOOL    optHexMode = FALSE,
-        optQuiet = FALSE,
-        optExtraData = FALSE,
-        optFormatting = TRUE;
-
-
-void (*writeHeader) (FILE *, char *) = NULL;
-void (*writeDecl) (FILE *, size_t, char *) = NULL;
-void (*writeData) (FILE *, Uint8 *, size_t) = NULL;
-void (*writeFooter) (FILE *, size_t, char *) = NULL;
-
-
-static DMOptArg optList[] =
-{
-    {  0, '?', "help",           "Show this help", OPT_NONE },
-    {  4, 'A', "format-asm",     "Output in XA-compatible asm", OPT_NONE },
-    {  5, 'C', "format-c",       "Output in ANSI C", OPT_NONE },
-    {  1, 'n', "name",           "Set object name", OPT_ARGREQ },
-    {  2, 't', "type",           "Set datatype (unsigned char/byte)", OPT_ARGREQ },
-    {  3, 'a', "add-line",       "Add this line to start of file", OPT_ARGREQ },
-    {  6, 'x', "hexadecimal",    "Use hexadecimal output", OPT_NONE },
-    {  7, 'q', "quiet",          "Do not add comments", OPT_NONE },
-    {  8, 'f', "no-formatting",  "Disable additional output formatting", OPT_NONE },
-    {  9, 'i', "indentation",    "Set indentation (negative value = tab)", OPT_ARGREQ },
-    { 10, 'e', "extra-data",     "Add object end labels and size in asm output", OPT_NONE },
-};
-
-static const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName,
-        "[options] [sourcefile] [destfile]");
-
-    dmArgsPrintHelp(stdout, optList, optListN);
-    
-    printf(
-    "\n"
-    "To convert a data file to a C structure using 'Uint8' as type:\n"
-    "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n"
-    "\n"
-    );
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            optObjName = optArg;
-            break;
-
-        case 2:
-            optDataType = optArg;
-            break;
-
-        case 3:
-            optAddLine = optArg;
-            break;
-
-        case 4:
-            optFormat = FMT_ASM;
-            break;
-        case 5:
-            optFormat = FMT_C;
-            break;
-        case 6:
-            optHexMode = TRUE;
-            break;
-        case 7:
-            optQuiet = TRUE;
-            break;
-        case 8:
-            optFormatting = FALSE;
-            break;
-
-        case 9:
-            optIndentation = atoi(optArg);
-            break;
-
-        case 10:
-            optExtraData = TRUE;
-            break;
-
-        default:
-            dmError("Unknown option '%s'.\n", currArg);
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char * currArg)
-{
-    if (!optInFilename)
-        optInFilename = currArg;
-    else
-    if (!optOutFilename)
-        optOutFilename = currArg;
-    else
-        dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg);
-
-    return TRUE;
-}
-
-
-/* Assembler include data output functions
- */
-void writeHeader_ASM(FILE * f, char *name)
-{
-    if (name)
-        fprintf(f, "; '%s'", name);
-    else
-        fprintf(f, "; Generated");
-    fprintf(f, " by %s v%s\n",
-        dmProgName, dmProgVersion);
-}
-
-void writeDecl_ASM(FILE * f, size_t len, char *name)
-{
-    if (optExtraData)
-        fprintf(f, "%s_size = %u\n", name, len);
-    fprintf(f, "%s:\n", name);
-}
-
-void writeData_ASM(FILE * f, Uint8 * buf, size_t len)
-{
-    size_t i;
-
-    fprintf(f, "%s ", optDataType);
-    for (i = 0; i < len; i++)
-    {
-        if (optFormatting)
-        {
-            if (optHexMode)
-                fprintf(f, "$%.2x", buf[i]);
-            else
-                fprintf(f, "%3d", buf[i]);
-        }
-        else
-        {
-            if (optHexMode)
-                fprintf(f, "$%x", buf[i]);
-            else
-                fprintf(f, "%d", buf[i]);
-        }
-
-        if (i < (len - 1))
-            fprintf(f, ",");
-    }
-}
-
-void writeFooter_ASM(FILE * f, size_t len, char *name)
-{
-    (void) len;
-    if (optExtraData)
-        fprintf(f, "%s_end: \n", name);
-    else
-        fprintf(f, "\n");
-}
-
-
-/* ANSI-C include data output functions
- */
-void writeHeader_C(FILE * f, char *name)
-{
-    if (name)
-        fprintf(f, "/* '%s' generated", name);
-    else
-        fprintf(f, "/* Generated");
-
-    fprintf(f, " by %s v%s\n" " */\n",
-        dmProgName, dmProgVersion);
-}
-
-void writeDecl_C(FILE * f, size_t len, char *name)
-{
-    fprintf(f, "%s %s[%u] = {\n",
-        optDataType, name, len);
-
-    printf("extern %s %s[%u];\n",
-        optDataType, name, len);
-}
-
-void writeData_C(FILE * f, Uint8 * buf, size_t len)
-{
-    size_t i;
-
-    for (i = 0; i < len; i++)
-    {
-        if (optFormatting)
-        {
-            if (optHexMode)
-                fprintf(f, "0x%.2x", buf[i]);
-            else
-                fprintf(f, "%3d", buf[i]);
-        }
-        else
-        {
-            if (optHexMode)
-                fprintf(f, "0x%x", buf[i]);
-            else
-                fprintf(f, "%d", buf[i]);
-        }
-
-        fprintf(f, ",");
-    }
-}
-
-void writeFooter_C(FILE * f, size_t len, char *name)
-{
-    (void) len;
-    (void) name;
-    fprintf(f, "};\n");
-}
-
-
-off_t dmGetFileSize(FILE *f)
-{
-    off_t len, pos = ftell(f);
-    fseeko(f, 0, SEEK_END);
-    len = ftell(f);
-    fseek(f, pos, SEEK_SET);
-    return len;
-}
-
-
-int main(int argc, char *argv[])
-{
-    FILE *sfile = NULL, *dfile = NULL;
-    off_t inSize;
-    Uint8 inBuf[RA_LINEBUF];
-    int tmpRes;
-
-    /* Initialize */
-    dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL);
-    dmVerbosity = 0;
-
-    /* Parse arguments */
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    /* Determine output type, if not specified */
-    if (optFormat == FMT_AUTO)
-    {
-        char *dext;
-
-        if (optOutFilename == NULL)
-        {
-            dmError("Output format not specified and no output filename given (try --help)\n");
-            exit(1);
-        }
-
-        /* Check filename extension */
-        dext = strrchr(optOutFilename, '.');
-        if (dext)
-        {
-            dext++;
-            if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") ||
-                !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") ||
-                !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++"))
-                optFormat = FMT_C;
-            else
-                optFormat = FMT_ASM;
-        } else
-            optFormat = FMT_ASM;
-    }
-
-    /* Set functions */
-    switch (optFormat)
-    {
-        case FMT_ASM:
-            if (!optDataType)
-                optDataType = ".byte";
-
-            writeHeader = writeHeader_ASM;
-            writeDecl = writeDecl_ASM;
-            writeData = writeData_ASM;
-            writeFooter = writeFooter_ASM;
-            break;
-
-        case FMT_C:
-            if (!optDataType)
-                optDataType = "unsigned char";
-
-            writeHeader = writeHeader_C;
-            writeDecl = writeDecl_C;
-            writeData = writeData_C;
-            writeFooter = writeFooter_C;
-            break;
-
-        case FMT_AUTO:
-        default:
-            dmError("Internal error, FMT_AUTO at output function init.\n");
-            exit(2);
-    }
-
-    /* Open the files */
-    if (optInFilename == NULL)
-        sfile = stdin;
-    else
-    if ((sfile = fopen(optInFilename, "rb")) == NULL)
-    {
-        tmpRes = errno;
-        dmError("Error opening input file '%s'. (%s)\n",
-            optInFilename, strerror(tmpRes));
-        exit(3);
-    }
-
-    if (optOutFilename == NULL)
-        dfile = stdout;
-    else
-    if ((dfile = fopen(optOutFilename, "wa")) == NULL)
-    {
-        tmpRes = errno;
-        dmError("Error creating output file '%s'. (%s)\n",
-            optOutFilename, strerror(tmpRes));
-        exit(4);
-    }
-
-    /* Get sourcefile size */
-    inSize = dmGetFileSize(sfile);
-
-    /* Output header */
-    if (!optQuiet)
-        writeHeader(dfile, optOutFilename);
-
-    if (optAddLine)
-        fprintf(dfile, "%s\n", optAddLine);
-
-    /* Output declaration */
-    writeDecl(dfile, inSize, optObjName);
-
-    /* Output data */
-    while (!feof(sfile))
-    {
-        tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile);
-        if (tmpRes > 0)
-        {
-            if (optIndentation < 0)
-                fprintf(dfile, "\t");
-            else
-            if (optIndentation > 0)
-            {
-                int i;
-                for (i = 0; i < optIndentation; i++)
-                    fputs(" ", dfile);
-            }
-
-            writeData(dfile, inBuf, tmpRes);
-
-            fprintf(dfile, "\n");
-        }
-    }
-
-
-    /* Output footer */
-    writeFooter(dfile, inSize, optObjName);
-
-    /* Exit */
-    fclose(sfile);
-    fclose(dfile);
-
-    exit(0);
-    return 0;
-}
--- a/utils/gentab.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-#include "dmlib.h"
-#include "dmargs.h"
-#include <math.h>
-
-enum
-{
-    MT_SIN,
-    MT_COS,
-    MT_SMOOTH1,
-    MT_SCURVE,
-    MT_SMOOTH1_CLAMP,
-    MT_SCURVE_CLAMP,
-    MT_SIN_SCURVE,
-
-    MT_LAST
-};
-
-
-typedef struct
-{
-    char *name;
-    char *desc;
-} DMTransType;
-
-static DMTransType dmTransTypes[MT_LAST] =
-{
-    { "sin", "Sine" },
-    { "cos", "Cosine" },
-    { "smooth1", "Smoothstep1 LERP" },
-    { "scurve", "S-curve LERP" },
-    { "smooth1-clamp", "Clamped smoothstep1 LERP" },
-    { "scurve-clamp", "Clamped S-curve LERP" },
-    { "sin-scurve", "Sine S-curve" },
-};
-
-
-DMFloat
-    optSOffset     = 0.0f,
-    optSAmplitude  = 1.0f,
-    optSOmega      = 1.0f,
-    optStartValue  = 0.0f,
-    optEndValue    = 1.0f;
-
-int optNSteps      = 64,
-    optPerLine     = 16,
-    optTransType   = -1;
-
-char
-    *optObjectName = NULL,
-    *optOutFilename = NULL;
-
-
-static DMOptArg optList[] =
-{
-    {  0, '?', "help",        "Show this help", OPT_NONE },
-    {  1, 'v', "verbose",     "Increase verbosity", OPT_NONE },
-    {  2, 'o', "output",      "Set output file (default stdout)", OPT_ARGREQ },
-    {  3, 'n', "name",        "Set output object name", OPT_ARGREQ },
-
-    {  4, 's', "steps",       "Number of steps/values in output table", OPT_ARGREQ },
-    {  5, 't', "type",        "Curve/interpolation type (see list)", OPT_ARGREQ },
-
-    {  6, 'O', "offset",      "Output data offset", OPT_ARGREQ },
-    {  7, 'A', "amplitude",   "Output amplitude scale", OPT_ARGREQ },
-    {  8, 'W', "omega",       "Omega (w) multiplier", OPT_ARGREQ },
-
-    {  9, 'S', "start",       "Start value (only smooth/scurve)", OPT_ARGREQ },
-    { 10, 'E', "end",         "End value (only smooth/scurve)", OPT_ARGREQ },
-};
-
-static const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    int index;
-    dmPrintBanner(stdout, dmProgName, "[options]");
-    dmArgsPrintHelp(stdout, optList, optListN);
-
-    printf("\nAvailable types:\n");
-    for (index = 0; index < MT_LAST; index++)
-    {
-        DMTransType *tm = &dmTransTypes[index];
-        printf("%-15s | %s\n", tm->name, tm->desc);
-    }
-    printf("\n");
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            dmVerbosity++;
-            break;
-        
-        case 2:
-            optOutFilename = optArg;
-            break;
-        
-        case 3:
-            optObjectName = optArg;
-            break;
-        
-        case 4:
-            {
-                int tmp;
-                if (sscanf(optArg, "%d", &tmp) != 1)
-                {
-                    dmError("Invalid number of steps argument '%s'.\n", optArg);
-                    return FALSE;
-                }
-                optNSteps = tmp;
-            }
-            break;
-
-        case 5:
-            {
-                int index;
-                for (index = 0; index < MT_LAST; index++)
-                {
-                    DMTransType *tm = &dmTransTypes[index];
-                    if (strcasecmp(tm->name, optArg) == 0)
-                    {
-                        optTransType = index;
-                        return TRUE;
-                    }
-                }
-                dmError("Invalid transformation type option '%s'.\n",
-                    optArg);
-                return FALSE;
-            }
-            break;
-
-        case 6:
-        case 7:
-        case 8:
-        case 9:
-        case 10:
-            {
-                DMFloat tmp;
-                if (sscanf(optArg, "%f", &tmp) != 1)
-                {
-                    dmError("Invalid %s option argument '%s', expected a floating point value.\n",
-                        currArg, optArg);
-                    return FALSE;
-                }
-                switch (optN)
-                {
-                    case  6: optSOffset = tmp; break;
-                    case  7: optSAmplitude = tmp; break;
-                    case  8: optSOmega = tmp; break;
-                    case  9: optStartValue = tmp; break;
-                    case 10: optEndValue = tmp; break;
-                }
-            }
-            break;
-
-        default:
-            dmError("Unknown argument '%s'.\n", currArg);
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-int main(int argc, char *argv[])
-{
-    FILE *outFile;
-    DMLerpContext ctx;
-    int step, n;
-
-    dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL);
-    dmVerbosity = 1;
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, NULL, TRUE))
-        exit(1);
-
-    // Check settings
-    if (optTransType < 0)
-    {
-        dmError("No transformation type set, perhaps try --help\n");
-        return -1;
-    }
-    
-    if (optObjectName == NULL)
-    {
-        dmError("Object name not specified, try --help\n");
-        return -2;
-    }
-
-    if (optOutFilename == NULL)
-        outFile = stdout;
-    else
-    if ((outFile = fopen(optOutFilename, "w")) == NULL)
-    {
-        int err = dmGetErrno();
-        dmError("Could not open output file '%s', %d: %s\n",
-            optOutFilename, err, dmErrorStr(err));
-        return -2;
-    }
-    
-
-    // Generate table
-    dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps);
-
-    fprintf(outFile,
-        "cnt_%s = %d\n"
-        "vtab_%s: ",
-        optObjectName,
-        optNSteps,
-        optObjectName
-        );
-
-    for (n = 0, step = 0; step < optNSteps; step++)
-    {
-        DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value;
-        
-        switch (optTransType)
-        {
-            case MT_SIN:           delta = sin(t * 2 * DM_PI); break;
-            case MT_COS:           delta = cos(t * 2 * DM_PI); break;
-
-            case MT_SMOOTH1:       delta = dmLerp1(&ctx, step); break;
-            case MT_SCURVE:        delta = dmLerpSCurve(&ctx, step); break;
-            case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break;
-            case MT_SCURVE_CLAMP:  delta = dmLerpSCurveClamp(&ctx, step); break;
-            case MT_SIN_SCURVE:    delta = dmLerpSCurveClamp(&ctx, step); break;
-            
-            default: delta = 0;
-        }
-        
-        value = optSOffset + delta * optSAmplitude;
-        
-        // Print the value
-        if (n == 0)
-            fprintf(outFile, "\t.byte ");
-
-        fprintf(outFile, "%ld%s",
-            lrint(value),
-            (n < optPerLine - 1) ? "," : "");
-
-        if (++n >= optPerLine)
-        {
-            fprintf(outFile, "\n");
-            n = 0;
-        }
-    }
-    if (n > 0)
-        fprintf(outFile, "\n");
-    
-    fprintf(outFile, "\n");
-
-    return 0;
-}
--- a/utils/gfxconv.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1697 +0,0 @@
-/*
- * gfxconv - Convert various graphics formats
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmfile.h"
-#include "dmmutex.h"
-#include "libgfx.h"
-#include "lib64gfx.h"
-
-//#define UNFINISHED 1
-
-#define DM_MAX_COLORS 256
-
-#define ASC_NBITS    8
-#define ASC_NCOLORS  4
-static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#";
-
-enum
-{
-    FFMT_AUTO = 0,
-
-    FFMT_ASCII,
-    FFMT_ANSI,
-    FFMT_IMAGE,
-
-    FFMT_CHAR,
-    FFMT_SPRITE,
-    FFMT_BITMAP,
-
-    FFMT_LAST
-};
-
-
-typedef struct
-{
-    char *name;
-    char *fext;
-    BOOL in, out;
-    int format;
-    int subformat;
-} DMConvFormat;
-
-
-static DMConvFormat convFormatList[] =
-{
-    {
-        "ASCII text", "asc", FALSE, TRUE,
-        FFMT_ASCII  , 0,
-    },
-    {
-        "ANSI colored text", "ansi", FALSE, TRUE,
-        FFMT_ANSI   , 0,
-    },
-    {
-        "PNG image file", "png", TRUE, TRUE,
-        FFMT_IMAGE  , IMGFMT_PNG,
-    },
-    {
-        "PPM image file", "ppm", FALSE, TRUE,
-        FFMT_IMAGE  , IMGFMT_PPM,
-    },
-    {
-        "PCX image file", "pcx", TRUE, TRUE,
-        FFMT_IMAGE  , IMGFMT_PCX,
-    },
-    {
-        "IFF ILBM file", "lbm", TRUE, FALSE,
-        FFMT_IMAGE  , IMGFMT_ILBM,
-    },
-    {
-        "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE,
-        FFMT_IMAGE  , IMGFMT_RAW,
-    },
-    {
-        "IFFMaster RAW image file", "araw", FALSE, TRUE,
-        FFMT_IMAGE  , IMGFMT_ARAW,
-    },
-
-    {
-        "C64 bitmap image file", NULL, TRUE, TRUE,
-        FFMT_BITMAP , -1,
-    },
-
-    {
-        "C64 character/font data", "chr", TRUE, TRUE,
-        FFMT_CHAR   , 0
-    },
-    {
-        "C64 sprite data", "spr", TRUE, TRUE,
-        FFMT_SPRITE , 0
-    },
-};
-
-static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]);
-
-
-typedef struct
-{
-    BOOL triplet, alpha;
-    DMColor color;
-    int from, to;
-} DMMapValue;
-
-
-
-char    *optInFilename = NULL,
-        *optOutFilename = NULL;
-int     optInFormat = FFMT_AUTO,
-        optOutFormat = FFMT_ASCII,
-        optInSubFormat = IMGFMT_PNG,
-        optOutSubFormat = IMGFMT_PNG,
-        optItemCount = -1,
-        optPlanedWidth = 1,
-        optForcedFormat = -1;
-int     optInSkip = 0;
-BOOL    optInMulticolor = FALSE,
-        optSequential = FALSE,
-        optRemapColors = FALSE,
-        optRemapRemove = FALSE;
-int     optNRemapTable = 0;
-DMMapValue optRemapTable[DM_MAX_COLORS];
-int     optColors[C64_MAX_COLORS];
-
-DMImageSpec optSpec =
-{
-    .scale = 1,
-    .nplanes = 4,
-    .interleave = FALSE,
-    .paletted = FALSE,
-    .format = 0,
-};
-
-static DMOptArg optList[] =
-{
-    {  0, '?', "help",         "Show this help", OPT_NONE },
-    { 15, 'v', "verbose",      "Increase verbosity", OPT_NONE },
-    {  3, 'o', "output",       "Output filename", OPT_ARGREQ },
-    {  1, 'i', "informat",     "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ },
-    {  2, 'm', "multicolor",   "Input is multicolor / output in multicolor", OPT_NONE },
-    {  4, 's', "skip",         "Skip bytes in input", OPT_ARGREQ },
-    {  5, 'f', "format",       "Output format (see --formats)", OPT_ARGREQ },
-    { 17, 'F', "formats",      "Output format (see list below)", OPT_NONE },
-    {  8, 'q', "sequential",   "Output sequential files (image output only)", OPT_NONE },
-    {  6, 'c', "colormap",     "Color mappings (see below for information)", OPT_ARGREQ },
-    {  7, 'n', "numitems",     "How many 'items' to view (default: all)", OPT_ARGREQ },
-    {  9, 'S', "scale",        "Scale output by x (image output only)", OPT_ARGREQ },
-    { 10, 'b', "bformat",      "Force input bitmap format (see below)", OPT_ARGREQ },
-    { 11, 'w', "width",        "Item width (number of items per row, min 1)", OPT_ARGREQ },
-    { 12, 'P', "paletted",     "Use indexed/paletted output (png, pcx output only)", OPT_NONE },
-    { 13, 'B', "bplanes",      "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ },
-    { 14, 'I', "interleave",   "Interleave scanlines (default: output whole planes)", OPT_NONE },
-    { 16, 'R', "remap",        "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ },
-    { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE },
-};
-
-static const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowFormats()
-{
-    int i;
-
-    printf(
-    "Available input/output formats:\n"
-    "  Ext | I | O | Description\n"
-    "------+---+---+-----------------------------------------------\n"
-    );
-    
-    for (i = 0; i < nconvFormatList; i++)
-    {
-        DMConvFormat *fmt = &convFormatList[i];
-        printf("%-5s | %c | %c | %s\n",
-            fmt->fext ? fmt->fext : "",
-            fmt->in ? 'X' : ' ',
-            fmt->out ? 'X' : ' ',
-            fmt->name);
-    }
-
-    printf(
-    "\n"
-    "(Not all input->output combinations are actually supported.)\n"
-    "\n"
-    "Available bitmap formats:\n"
-    "  Ext | Type            | Description\n"
-    "------+-----------------+-------------------------------------\n"
-    );
-
-    for (i = 0; i < ndmC64ImageFormats; i++)
-    {
-        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
-        char buf[64];
-        printf("%-5s | %-15s | %s\n",
-            fmt->fext,
-            dmC64GetImageTypeString(buf, sizeof(buf), fmt->type),
-            fmt->name);
-    }
-}
-
-
-void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName, "[options] <input file>");
-    dmArgsPrintHelp(stdout, optList, optListN);
-
-    printf(
-    "\n"
-    "Color map definitions are used for ANSI and image output, to declare what\n"
-    "output colors of the C64 palette are used for each single color/multi color\n"
-    "bit-combination. For example, if the input is multi color sprite or char,\n"
-    "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n"
-    "The numbers are palette indexes, and the order is for bit(pair)-values\n"
-    "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n"
-    "special color that can be used for transparency.\n"
-    );
-}
-
-
-int dmGetConvFormat(int format, int subformat)
-{
-    int i;
-    for (i = 0; i < nconvFormatList; i++)
-    {
-        DMConvFormat *fmt = &convFormatList[i];
-        if (fmt->format == format &&
-            fmt->subformat == subformat)
-            return i;
-    }
-    return -1;
-}
-
-
-BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat)
-{
-    int i;
-    if (fext == NULL)
-        return FALSE;
-
-    for (i = 0; i < nconvFormatList; i++)
-    {
-        DMConvFormat *fmt = &convFormatList[i];
-        if (fmt->fext != NULL &&
-            strcasecmp(fext, fmt->fext) == 0)
-        {
-            *format = fmt->format;
-            *subformat = fmt->subformat;
-            return TRUE;
-        }
-    }
-
-    for (i = 0; i < ndmC64ImageFormats; i++)
-    {
-        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
-        if (fmt->fext != NULL &&
-            strcasecmp(fext, fmt->fext) == 0)
-        {
-            *format = FFMT_BITMAP;
-            *subformat = i;
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-
-static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg)
-{
-    char *end, *split, *opt = dm_strdup(popt);
-
-    if (opt == NULL)
-        goto error;
-
-    if ((end = split = strchr(opt, ':')) == NULL)
-    {
-        dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt);
-        goto error;
-    }
-
-    // Trim whitespace
-    *end = 0;
-    for (end--; end > opt && *end && isspace(*end); end--)
-        *end = 0;
-
-    // Parse either a hex triplet color definition or a normal value
-    if (*opt == '#' || *opt == '%')
-    {
-        int colR, colG, colB, colA;
-
-        if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 ||
-            sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4)
-        {
-            value->alpha = TRUE;
-            value->color.a = colA;
-        }
-        else
-        if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 &&
-            sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3)
-        {
-            dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1);
-            goto error;
-        }
-
-        value->color.r = colR;
-        value->color.g = colG;
-        value->color.b = colB;
-        value->triplet = TRUE;
-    }
-    else
-    {
-        if (!dmGetIntVal(opt, &value->from))
-        {
-            dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt);
-            goto error;
-        }
-        value->triplet = FALSE;
-    }
-    
-    // Trim whitespace
-    split++;
-    while (*split && isspace(*split)) split++;
-    
-    // Parse destination value
-    if (!dmGetIntVal(split, &value->to))
-    {
-        dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split);
-        goto error;
-    }
-
-    if (!value->triplet && (value->from < 0 || value->from > 255))
-    {
-        dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from);
-        goto error;
-    }
-
-    if (value->to < 0 || value->to > nmax)
-    {
-        dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax);
-        goto error;
-    }
-
-    dmFree(opt);
-    return TRUE;
-
-error:
-    dmFree(opt);
-    return FALSE;
-}
-
-
-static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg)
-{
-    // Trim whitespace
-    if (end != NULL)
-    {
-        *end = 0;
-        for (end--; end > opt && *end && isspace(*end); end--)
-            *end = 0;
-    }
-    while (*opt && isspace(*opt)) opt++;
-
-    // Parse item based on mode
-    if (requireIndex)
-    {
-        DMMapValue *value = (DMMapValue *) pvalue;
-        if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg))
-            return FALSE;
-    }
-    else
-    {
-        int *value = (int *) pvalue;
-        char *split = strchr(opt, ':');
-        if (split != NULL)
-        {
-            dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt);
-            return FALSE;
-        }
-
-        if (!dmGetIntVal(opt, &value[index]))
-        {
-            dmError("Invalid %s value '%s', could not parse.\n", msg, opt);
-            return FALSE;
-        }
-    }
-    
-    return TRUE;
-}
-
-
-BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg)
-{
-    char *end, *start = opt;
-
-    *nvalues = 0;
-    while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL)
-    {
-        if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg))
-            return FALSE;
-
-        start = end + 1;
-        (*nvalues)++;
-    }
-    
-    if (*start && *nvalues < nmax)
-    {
-        if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg))
-            return FALSE;
-
-        (*nvalues)++;
-    }
-
-    return TRUE;   
-}
-
-
-int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax)
-{
-    FILE *fp;
-    char line[512];
-    int res = DMERR_OK;
-
-    if ((fp = fopen(filename, "r")) == NULL)
-    {
-        res = dmGetErrno();
-        dmError("Could not open color remap file '%s' for reading, %d: %s\n",
-            res, dmErrorStr(res));
-        return res;
-    }
-
-    while (fgets(line, sizeof(line), fp))
-    {
-        char *start = line;
-        while (*start && isspace(*start)) start++;
-        
-        if (*start != 0 && *start != ';')
-        {
-            if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file"))
-                goto error;
-            else
-            {
-                (*nvalue)++;
-                if (*nvalue >= nmax)
-                {
-                    dmError("Too many mapping pairs in '%s', maximum is %d.\n",
-                        filename, nmax);
-                    goto error;
-                }
-            }
-        }
-    }
-
-error:
-    fclose(fp);
-    return res;
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 17:
-            argShowFormats();
-            exit(0);
-            break;
-
-        case 15:
-            dmVerbosity++;
-            break;
-
-        case 1:
-            switch (tolower(optArg[0]))
-            {
-                case 's':
-                    optInFormat = FFMT_SPRITE;
-                    break;
-                case 'c':
-                    optInFormat = FFMT_CHAR;
-                    break;
-                case 'b':
-                    optInFormat = FFMT_BITMAP;
-                    break;
-                case 'i':
-                    optInFormat = FFMT_IMAGE;
-                    break;
-                default:
-                    dmError("Invalid input format '%s'.\n", optArg);
-                    return FALSE;
-            }
-            break;
-        
-        case 2:
-            optInMulticolor = TRUE;
-            break;
-
-        case 3:
-            optOutFilename = optArg;
-            break;
-        
-        case 4:
-            if (!dmGetIntVal(optArg, &optInSkip))
-            {
-                dmError("Invalid skip value argument '%s'.\n", optArg);
-                return FALSE;
-            }
-            break;
-
-        case 5:
-            if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat))
-            {
-                dmError("Invalid output format '%s'.\n", optArg);
-                return FALSE;
-            }
-            break;
-
-        case 6:
-            {
-                int index, ncolors;
-                if (!dmParseMapOptionString(optArg, optColors,
-                    &ncolors, C64_MAX_COLORS, FALSE, "color table option"))
-                    return FALSE;
-
-                dmMsg(1, "Set color table: ");
-                for (index = 0; index < ncolors; index++)
-                {
-                    dmPrint(1, "[%d:%d]%s",
-                        index, optColors[index],
-                        (index < ncolors) ? ", " : "");
-                }
-                dmPrint(1, "\n");
-            }
-            break;
-
-        case 7:
-            if (sscanf(optArg, "%d", &optItemCount) != 1)
-            {
-                dmError("Invalid count value argument '%s'.\n", optArg);
-                return FALSE;
-            }
-            break;
-
-        case 8:
-            optSequential = TRUE;
-            break;
-
-        case 9:
-            {
-                int tmp = atoi(optArg);
-                if (tmp < 1 || tmp > 50)
-                {
-                    dmError("Invalid scale value '%s'.\n", optArg);
-                    return FALSE;
-                }
-                optSpec.scale = tmp;
-            }
-            break;
-
-        case 11:
-            {
-                int tmp = atoi(optArg);
-                if (tmp < 1 || tmp > 512)
-                {
-                    dmError("Invalid width value '%s'.\n", optArg);
-                    return FALSE;
-                }
-                optPlanedWidth = tmp;
-            }
-            break;
-
-        case 12:
-            optSpec.paletted = TRUE;
-            break;
-
-        case 13:
-            {
-                int tmp = atoi(optArg);
-                if (tmp < 1 || tmp > 8)
-                {
-                    dmError("Invalid bitplanes/bpp value '%s'.\n", optArg);
-                    return FALSE;
-                }
-                optSpec.nplanes = tmp;
-            }
-            break;
-
-        case 14:
-            optSpec.interleave = TRUE;
-            break;
-
-
-        case 16:
-            if (optArg[0] == '@')
-            {
-                if (optArg[1] != 0)
-                {
-                    int res;
-                    if ((res = dmParseColorRemapFile(optArg + 1,
-                        optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK)
-                        return FALSE;
-                }
-                else
-                {
-                    dmError("No remap filename given.\n");
-                    return FALSE;
-                }
-            }
-            else
-            {
-                if (!dmParseMapOptionString(optArg, optRemapTable,
-                    &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option"))
-                    return FALSE;
-            }
-
-            optRemapColors = TRUE;
-            break;
-
-        case 18:
-            optRemapRemove = TRUE;
-            break;
-
-        default:
-            dmError("Unknown option '%s'.\n", currArg);
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    if (!optInFilename)
-        optInFilename = currArg;
-    else
-    {
-        dmError("Source filename already specified, extraneous argument '%s'.\n",
-             currArg);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor)
-{
-    int i;
-    
-    if (multicolor)
-    {
-        for (i = ASC_NBITS; i; i -= 2)
-        {
-            int val = (byte & (3ULL << (i - 2))) >> (i - 2);
-            char ch;
-            switch (format)
-            {
-                case FFMT_ASCII:
-                    ch = dmASCIIPalette[val];
-                    fprintf(out, "%c%c", ch, ch);
-                    break;
-                case FFMT_ANSI:
-                    fprintf(out, "%c[0;%d;%dm##%c[0m",
-                        0x1b,
-                        1,
-                        31 + optColors[val],
-                        0x1b);
-                    break;
-            }
-        }
-    }
-    else
-    {
-        for (i = ASC_NBITS; i; i--)
-        {
-            int val = (byte & (1ULL << (i - 1))) >> (i - 1);
-            char ch;
-            switch (format)
-            {
-                case FFMT_ASCII:
-                    ch = val ? '#' : '.';
-                    fputc(ch, out);
-                    break;
-                case FFMT_ANSI:
-                    fprintf(out, "%c[0;%d;%dm %c[0m",
-                        0x1b,
-                        1,
-                        31 + optColors[val],
-                        0x1b);
-                    break;
-            }
-        }
-    }
-}
-
-
-void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor)
-{
-    int yc;
-
-    for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
-    {
-        fprintf(outFile, "%04x : ", *offs);
-        dmPrintByte(outFile, buf[yc], format, multicolor);
-        fprintf(outFile, "\n");
-        (*offs)++;
-    }
-}
-
-
-void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor)
-{
-    int bufOffs, xc, yc;
-
-    for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++)
-    {
-        fprintf(outFile, "%04x : ", *offs);
-        for (xc = 0; xc < C64_SPR_WIDTH; xc++)
-        {
-            dmPrintByte(outFile, buf[bufOffs], format, multicolor);
-            fprintf(outFile, " ");
-            bufOffs++;
-            (*offs)++;
-        }
-        fprintf(outFile, "\n");
-    }
-    (*offs)++;
-}
-
-
-#ifdef UNFINISHED
-int dmConvertBMP2(DMImage *screen, const DM64Image *img)
-{
-    int yc;
-    Uint8 *dp = screen->data;
-    
-    for (yc = 0; yc < screen->height; yc++)
-    {
-        Uint8 *d = dp;
-        const int y = yc / 8, yb = yc & 7;
-        const int scroffsy = y * C64_SCR_CH_WIDTH;
-        const int bmoffsy = y * C64_SCR_WIDTH;
-        int xc;
-
-        for (xc = 0; xc < screen->width / 2; xc++)
-        {
-            const int x = xc / 4;
-            const int scroffs = scroffsy + x;
-            const int b = img->bitmap[0][bmoffsy + (x * 8) + yb];
-            const int v = 6 - ((xc * 2) & 6);
-            Uint8 c;
-
-            switch ((b >> v) & 3)
-            {
-                case 0: c = img->bgcolor; break;
-                case 1: c = img->screen[0][scroffs] >> 4; break;
-                case 2: c = img->screen[0][scroffs] & 15; break;
-                case 3: c = img->color[0][scroffs] & 15; break;
-            }
-            
-            *d++ = c;
-            *d++ = c;
-        }
-
-        dp += screen->pitch;
-    }
-    
-    return 0;
-}
-#endif
-
-
-int dmRemapImageColors(DMImage *image)
-{
-    DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor));
-    int  *mapping = dmMalloc(image->ncolors * sizeof(int));
-    BOOL *mapped  = dmMalloc(image->ncolors * sizeof(BOOL));
-    BOOL *used    = dmMalloc(image->ncolors * sizeof(BOOL));
-    int n, index, xc, yc, ncolors;
-
-    dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors);
-
-    if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL)
-    {
-        dmError("Could not allocate memory for reused palette.\n");
-        return DMERR_MALLOC;
-    }
-
-    for (index = 0; index < image->ncolors; index++)
-    {
-        mapping[index] = -1;
-        mapped[index] = used[index] = FALSE;
-    }
-
-    // Find used colors
-    dmMsg(2, "Scanning image for used colors...\n");
-    for (ncolors = yc = 0; yc < image->height; yc++)
-    {
-        Uint8 *dp = image->data + image->pitch * yc;
-        for (xc = 0; xc < image->width; xc++)
-        {
-            Uint8 col = dp[xc];
-            if (col < image->ncolors && !used[col])
-            {
-                used[col] = TRUE;
-                ncolors++;
-            }
-        }
-    }
-    dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors);
-
-    // Match and mark mapped colors
-    for (index = 0; index < optNRemapTable; index++)
-    {
-        DMMapValue *map = &optRemapTable[index];
-        if (map->triplet)
-        {
-            BOOL found = FALSE;
-            for (n = 0; n < image->ncolors; n++)
-            {
-                if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha))
-                {
-                    dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n",
-                        map->color.r, map->color.g, map->color.b, map->color.a,
-                        n,
-                        map->to);
-
-                    mapping[n] = map->to;
-                    mapped[map->to] = TRUE;
-                    found = TRUE;
-                }
-            }
-            
-            if (!found)
-            {
-                dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n",
-                    index,
-                    map->color.r, map->color.g, map->color.b, map->color.a);
-            }
-        }
-        else
-        {
-            dmMsg(3, "Map index: %d -> %d\n",
-                map->from, map->to);
-
-            mapping[map->from] = map->to;
-            mapped[map->to] = TRUE;
-        }
-    }
-
-    
-    // Fill in the rest
-    if (optRemapRemove)
-    {
-        dmMsg(2, "Removing unused colors.\n");
-        for (index = 0; index < image->ncolors; index++)
-        if (mapping[index] < 0 && used[index])
-        {
-            for (n = 0; n < image->ncolors; n++)
-            if (!mapped[n])
-            {
-                mapping[index] = n;
-                mapped[n] = TRUE;
-                break;
-            }
-        }
-    }
-    else
-    {
-        for (index = 0; index < image->ncolors; index++)
-        if (mapping[index] < 0)
-        {
-            for (n = 0; n < image->ncolors; n++)
-            if (!mapped[n])
-            {
-                mapping[index] = n;
-                mapped[n] = TRUE;
-                break;
-            }
-        }
-    }
-
-    // Calculate final number of palette colors
-    ncolors = 0;
-    for (index = 0; index < image->ncolors; index++)
-    {
-        if (mapping[index] + 1 > ncolors)
-            ncolors = mapping[index] + 1;
-    }
-    
-    // Copy palette entries
-    for (index = 0; index < image->ncolors; index++)
-    {
-        if (mapping[index] >= 0)
-        {
-            memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor));
-        }
-    }
-
-    // Remap image
-    dmMsg(1, "Remapping image to %d colors...\n", ncolors);
-    for (yc = 0; yc < image->height; yc++)
-    {
-        Uint8 *dp = image->data + image->pitch * yc;
-        for (xc = 0; xc < image->width; xc++)
-        {
-            Uint8 col = dp[xc];
-            if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors)
-                dp[xc] = mapping[col];
-            else
-                dp[xc] = 0;
-        }
-    }
-
-    // Set new palette, free memory
-    dmFree(image->pal);
-    image->pal = npal;
-    image->ncolors = ncolors;
-
-    dmFree(mapping);
-    dmFree(mapped);
-    dmFree(used);
-    return DMERR_OK;
-}
-
-
-int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps)
-{
-    FILE *outFile = NULL;
-    Uint8 *buf = NULL;
-    size_t bufSize;
-    int res = DMERR_OK;
-    const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat];
-
-    dmMsg(1, "Converting to %s format bitmap.\n", fmt->name);
-    if (image->type != fmt->type && enableFixUps)
-    {
-        // Try to do some simple fixups
-        if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0)
-        {
-            dmMsg(1, "Upconverting multicolor to FLI.\n");
-            int i;
-            for (i = 1; i < C64_SCR_MAX_BANK; i++)
-            {
-                memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE);
-                memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE);
-            }
-        }
-    }
-
-
-    if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK)
-        goto error;
-
-    dmMsg(2, "Result: %d bytes\n", bufSize);
-
-    if ((outFile = fopen(filename, "wb")) == NULL)
-    {
-        res = dmGetErrno();
-        dmError("Error opening output file '%s', %d: %s\n",
-            filename, res, dmErrorStr(res));
-        goto error;
-    }
-
-    if (!dm_fwrite_str(outFile, buf, bufSize))
-    {
-        res = dmGetErrno();
-        dmError("Error writing image data to '%s', %d: %s\n",
-            filename, res, dmErrorStr(res));
-    }
-
-error:
-    if (outFile != NULL)
-        fclose(outFile);
-    dmFree(buf);
-    return res;
-}
-
-
-int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info)
-{
-    if (info)
-    {
-        dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n",
-            dmImageFormatList[iformat].fext,
-            image->width, image->height,
-            image->width * spec->scale, image->height * spec->scale,
-            spec->scale);
-    }
-
-    // Perform color remapping
-    if (optRemapColors)
-    {
-        int res;
-        if ((res = dmRemapImageColors(image)) != DMERR_OK)
-            return res;
-    }
-
-    switch (iformat)
-    {
-#ifdef DM_USE_LIBPNG
-        case IMGFMT_PNG:
-            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA");
-            spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA;
-            return dmWritePNGImage(filename, image, spec);
-#endif
-
-        case IMGFMT_PPM:
-            if (info) dmMsg(2, "24bit RGB output.\n");
-            spec->format = DM_IFMT_RGB;
-            return dmWritePPMImage(filename, image, spec);
-
-        case IMGFMT_PCX:
-            if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB");
-            return dmWritePCXImage(filename, image, spec);
-
-        case IMGFMT_RAW:
-        case IMGFMT_ARAW:
-            {
-                FILE *fp;
-                char *dataFilename, *fext, *tmpFilename = dm_strdup(filename);
-                
-                // Form data file filename
-                if (tmpFilename == NULL)
-                    return DMERR_MALLOC;
-
-                fext = strrchr(tmpFilename, '.');
-                if (fext != NULL)
-                    *fext = 0;
-                dataFilename = dm_strdup_printf("%s.inc", tmpFilename);
-                dmFree(tmpFilename);
-
-                // Open data file for writing
-                if ((fp = fopen(dataFilename, "w")) == NULL)
-                    dmError("Could not create '%s'.\n", dataFilename);
-                dmFree(dataFilename);
-
-                if (fp != NULL)
-                {
-                    // Strip extension
-                    int i;
-                    char *palID = dm_strdup_printf("img_%s", filename);
-                    char *fext = strrchr(palID, '.');
-                    if (fext != NULL)
-                        *fext = 0;
-
-                    // Replace any non-alphanumerics
-                    for (i = 0; palID[i]; i++)
-                    {
-                        if (isalnum(palID[i]))
-                            palID[i] = tolower(palID[i]);
-                        else
-                            palID[i] = '_';
-                    }
-
-                    if (iformat == IMGFMT_ARAW)
-                    {
-                        fprintf(fp,
-                        "%s_width: dw.w %d\n"
-                        "%s_height: dw.w %d\n"
-                        "%s_nplanes: dw.w %d\n"
-                        "%s_ncolors: dw.w %d\n"
-                        "%s_palette:\n",
-                        palID, image->width,
-                        palID, image->height,
-                        palID, spec->nplanes,
-                        palID, image->ncolors,
-                        palID);
-
-                        dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL);
-
-                        fprintf(fp,
-                        "%s: incbin \"%s\"\n",
-                        palID, filename);
-                    }
-                    else
-                    {
-                        fprintf(fp,
-                        "%s_width: dw.w %d\n"
-                        "%s_height: dw.w %d\n"
-                        "%s_nplanes: dw.w %d\n",
-                        palID, image->width,
-                        palID, image->height,
-                        palID, spec->nplanes);
-                    }
-
-                    fclose(fp);
-                    dmFree(palID);
-                }
-
-                if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without");
-                return dmWriteRAWImage(filename, image, spec);
-            }
-            break;
-
-        default:
-            return DMERR_INVALID_DATA;
-    }
-}
-
-
-static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor)
-{
-    Uint8 byte = 0;
-    int xc;
-
-    if (multicolor)
-    {
-        for (xc = 0; xc < 8 / 2; xc++)
-        {
-            Uint8 pixel = sp[xc * 2] & 3;
-            byte |= pixel << (6 - (xc * 2));
-        }
-    }
-    else
-    {
-        for (xc = 0; xc < 8; xc++)
-        {
-            Uint8 pixel = sp[xc] == 0 ? 0 : 1;
-            byte |= pixel << (7 - xc);
-        }
-    }
-
-    return byte;
-}
-
-
-BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image,
-    const int xoffs, const int yoffs, const BOOL multicolor)
-{
-    int yc;
-
-    if (xoffs < 0 || yoffs < 0 ||
-        xoffs + C64_CHR_WIDTH_PX > image->width ||
-        yoffs + C64_CHR_HEIGHT > image->height)
-        return FALSE;
-
-    for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
-    {
-        const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs;
-        buf[yc] = dmConvertByte(sp, multicolor);
-    }
-
-    return TRUE;
-}
-
-
-BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image,
-    const int xoffs, const int yoffs, const BOOL multicolor)
-{
-    int yc, xc;
-
-    if (xoffs < 0 || yoffs < 0 ||
-        xoffs + C64_SPR_WIDTH_PX > image->width ||
-        yoffs + C64_SPR_HEIGHT > image->height)
-        return FALSE;
-
-    for (yc = 0; yc < C64_SPR_HEIGHT; yc++)
-    {
-        for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++)
-        {
-            const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs;
-            buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor);
-        }
-    }
-
-    return TRUE;
-}
-
-
-int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor)
-{
-    int outBlockW, outBlockH, bx, by;
-    FILE *outFile = NULL;
-    Uint8 *buf = NULL;
-    size_t bufSize;
-    char *outType;
-
-    switch (outFormat)
-    {
-        case FFMT_CHAR:
-            bufSize = C64_CHR_SIZE;
-            outBlockW = image->width / C64_CHR_WIDTH_PX;
-            outBlockH = image->height / C64_CHR_HEIGHT;
-            outType = "char";
-            break;
-
-        case FFMT_SPRITE:
-            bufSize = C64_SPR_SIZE;
-            outBlockW = image->width / C64_SPR_WIDTH_PX;
-            outBlockH = image->height / C64_SPR_HEIGHT;
-            outType = "sprite";
-            break;
-
-        default:
-            dmError("Invalid output format %d, internal error.\n", outFormat);
-            goto error;
-    }
-
-    if (outBlockW <= 0 || outBlockH <= 0)
-    {
-        dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n",
-            outBlockW, outBlockH);
-        goto error;
-    }
-
-    if ((outFile = fopen(filename, "wb")) == NULL)
-    {
-        int err = dmGetErrno();
-        dmError("Could not open '%s' for writing, %d: %s.\n",
-            filename, err, dmErrorStr(err));
-        goto error;
-    }
-
-    if ((buf = dmMalloc(bufSize)) == NULL)
-    {
-        dmError("Could not allocate %d bytes for conversion buffer.\n",
-            bufSize);
-        goto error;
-    }
-
-    dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n",
-        outBlockW, outBlockH, outBlockW * outBlockH, outType);
-
-    for (by = 0; by < outBlockH; by++)
-    for (bx = 0; bx < outBlockW; bx++)
-    {
-        switch (outFormat)
-        {
-            case FFMT_CHAR:
-                if (!dmConvertImage2Char(buf, image,
-                    bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT,
-                    multicolor))
-                    goto error;
-                break;
-
-            case FFMT_SPRITE:
-                if (!dmConvertImage2Sprite(buf, image,
-                    bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT,
-                    multicolor))
-                    goto error;
-        }
-
-        if (!dm_fwrite_str(outFile, buf, bufSize))
-        {
-            int err = dmGetErrno();
-            dmError("Error writing data block %d,%d to '%s', %d: %s\n",
-                bx, by, filename, err, dmErrorStr(err));
-            goto error;
-        }
-    }
-
-    fclose(outFile);
-    dmFree(buf);
-    return 0;
-
-error:
-    if (outFile != NULL)
-        fclose(outFile);
-    dmFree(buf);
-    return -1;
-}
-
-
-int dmDumpSpritesAndChars(FILE *inFile)
-{
-    int dataOffs, itemCount, outWidth, outWidthPX, outHeight;
-    size_t bufSize;
-    Uint8 *bufData;
-
-    switch (optInFormat)
-    {
-        case FFMT_CHAR:
-            bufSize = C64_CHR_SIZE;
-            outWidth = C64_CHR_WIDTH;
-            outWidthPX = C64_CHR_WIDTH_PX;
-            outHeight = C64_CHR_HEIGHT;
-            break;
-
-        case FFMT_SPRITE:
-            bufSize = C64_SPR_SIZE;
-            outWidth = C64_SPR_WIDTH;
-            outWidthPX = C64_SPR_WIDTH_PX;
-            outHeight = C64_SPR_HEIGHT;
-            break;
-
-        default:
-            dmError("Invalid input format %d, internal error.\n", optInFormat);
-            return -1;
-    }
-
-    if ((bufData = dmMalloc(bufSize)) == NULL)
-    {
-        dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize);
-        return -2;
-    }
-
-
-    dataOffs = optInSkip;
-    itemCount = 0;
-
-    if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII)
-    {
-        BOOL error = FALSE;
-        FILE *outFile;
-
-        if (optOutFilename == NULL)
-            outFile = stdout;
-        else
-        if ((outFile = fopen(optOutFilename, "w")) == NULL)
-        {
-            int res = dmGetErrno();
-            dmError("Error opening output file '%s', %d: %s\n",
-                  optOutFilename, res, dmErrorStr(res));
-            goto error;
-        }
-
-        while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount))
-        {
-            memset(bufData, 0, bufSize);
-
-            if (fread(bufData, 1, bufSize, inFile) != bufSize)
-            {
-                dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
-                    bufSize, dataOffs);
-                error = TRUE;
-            }
-            
-            fprintf(outFile, "---- : -------------- #%d\n", itemCount);
-
-            switch (optInFormat)
-            {
-                case FFMT_CHAR:
-                    dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
-                    break;
-                case FFMT_SPRITE:
-                    dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
-                    break;
-            }
-            itemCount++;
-        }
-
-        fclose(outFile);
-    }
-    else
-    if (optOutFormat == FFMT_IMAGE)
-    {
-        DMImage *outImage = NULL;
-        char *outFilename = NULL;
-        int outX = 0, outY = 0, err;
-
-        if (optSequential)
-        {
-            if (optOutFilename == NULL)
-            {
-                dmError("Sequential image output requires filename template.\n");
-                goto error;
-            }
-
-            outImage = dmImageAlloc(outWidthPX, outHeight);
-            dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n",
-                optItemCount,
-                outImage->width, outImage->height,
-                outImage->width * optSpec.scale, outImage->height * optSpec.scale);
-        }
-        else
-        {
-            int outIWidth, outIHeight;
-            if (optItemCount <= 0)
-            {
-                dmError("Single-image output requires count to be set (-n).\n");
-                goto error;
-            }
-            
-            outIWidth = optPlanedWidth;
-            outIHeight = (optItemCount / optPlanedWidth);
-            if (optItemCount % optPlanedWidth)
-                outIHeight++;
-            
-            outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight);
-        }
-
-        outImage->constpal = TRUE;
-        outImage->pal      = dmC64Palette;
-        outImage->ncolors  = C64_NCOLORS;
-        outImage->ctransp  = 255;
-        
-        while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount))
-        {
-            memset(bufData, 0, bufSize);
-
-            if (fread(bufData, 1, bufSize, inFile) != bufSize)
-            {
-                dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
-                    bufSize, dataOffs);
-                break;
-            }
-
-            if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight,
-                bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK)
-            {
-                dmError("Internal error in conversion of raw data to bitmap: %d.\n", err);
-                break;
-            }
-
-            if (optSequential)
-            {
-                outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext);
-                if (outFilename == NULL)
-                {
-                    dmError("Could not allocate memory for filename template?\n");
-                    goto error;
-                }
-                
-                dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
-                dmFree(outFilename);
-            }
-            else
-            {
-                if (++outX >= optPlanedWidth)
-                {
-                    outX = 0;
-                    outY++;
-                }
-            }
-            
-            itemCount++;
-        }
-
-        if (!optSequential)
-        {
-            dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
-        }
-        
-        dmImageFree(outImage);
-    }
-    else
-    if (optOutFormat == FFMT_BITMAP)
-    {
-        if (optSequential)
-        {
-            dmError("Sequential output not supported for spr/char -> bitmap conversion.\n");
-            goto error;
-        }
-    }
-
-    dmFree(bufData);
-    return 0;
-
-error:
-    dmFree(bufData);
-    return -1;
-}
-
-
-int main(int argc, char *argv[])
-{
-    FILE *inFile;
-    const DMC64ImageFormat *cfmt;
-    DMC64Image cimage;
-    Uint8 *dataBuf = NULL;
-    size_t dataSize;
-    int i;
-
-    // Default colors
-    for (i = 0; i < C64_MAX_COLORS; i++)
-        optColors[i] = i;
-
-    // Initialize and parse commandline
-    dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL);
-
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-#ifndef DM_USE_LIBPNG
-    if (optOutFormat == IMGFMT_PNG)
-    {
-        dmError("PNG output format support not compiled in, sorry.\n");
-        goto error;
-    }
-#endif
-
-    // Determine input format, if not specified'
-    if (optInFormat == FFMT_AUTO && optInFilename != NULL)
-    {
-        char *dext = strrchr(optInFilename, '.');
-        dmMsg(4, "Trying to determine file format by extension.\n");
-        if (dext)
-        {
-            dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat);
-        }
-    }
-
-    if (optInFilename == NULL)
-    {
-        if (optInFormat == FFMT_AUTO)
-        {
-            dmError("Standard input cannot be used without specifying input format.\n");
-            dmError("Perhaps you should try using --help\n");
-            goto error;
-        }
-        inFile = stdin;
-    }
-    else
-    if ((inFile = fopen(optInFilename, "rb")) == NULL)
-    {
-        int res = dmGetErrno();
-        dmError("Error opening input file '%s', %d: %s\n",
-              optInFilename, res, dmErrorStr(res));
-        goto error;
-    }
-
-    if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0)
-        goto error;
-
-    if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP)
-    {
-        // Probe for format
-        const DMC64ImageFormat *forced = NULL;
-        int res;
-
-        if (optForcedFormat >= 0)
-        {
-            forced = &dmC64ImageFormats[optForcedFormat];
-            dmMsg(0,"Forced %s format image, type %d, %s\n",
-                forced->name, forced->type, forced->fext);
-        }
-
-        res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced);
-        if (forced == NULL && cfmt != NULL)
-        {
-            dmMsg(1,"Probed %s format image, type %d, %s\n",
-                cfmt->name, cfmt->type, cfmt->fext);
-        }
-        
-        if (res == 0)
-            optInFormat = FFMT_BITMAP;
-    }
-
-    if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE)
-    {
-        DMImageFormat *ifmt = NULL;
-        int index;
-        dmMsg(4, "Trying to probe image formats.\n");
-        if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0)
-        {
-            optInFormat = FFMT_IMAGE;
-            optInSubFormat = index;
-            dmMsg(2, "Probed %s format image.\n", ifmt->fext);
-        }
-    }
-
-    if (optInFormat == FFMT_AUTO)
-    {
-        dmError("No input format specified, and could not be determined automatically.\n");
-        exit(1);
-    }
-
-    // Skip, if needed
-    if (fseek(inFile, optInSkip, SEEK_SET) != 0)
-    {
-        int res = dmGetErrno();
-        dmError("Could not seek to file position %d (0x%x): %s\n",
-            optInSkip, optInSkip, dmErrorStr(res));
-        goto error;
-    }
-    
-    int inFormat = dmGetConvFormat(optInFormat, optInSubFormat),
-        outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat);
-    
-    if (inFormat != -1 && outFormat != -1)
-    {
-        char *inFmtName = convFormatList[inFormat].name,
-             *inFmtExt = convFormatList[inFormat].fext,
-             *outFmtName = convFormatList[outFormat].name,
-             *outFmtExt = convFormatList[outFormat].fext;
-
-        if (optInFormat == FFMT_BITMAP)
-            inFmtExt = cfmt->name;
-
-        dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n",
-            inFmtName, inFmtExt, outFmtName, outFmtExt);
-    }
-
-    switch (optInFormat)
-    {
-        case FFMT_SPRITE:
-        case FFMT_CHAR:
-            dmDumpSpritesAndChars(inFile);
-            break;
-        
-        case FFMT_BITMAP:
-            {
-                DMImage *outImage = NULL;
-                int res = DMERR_OK;
-
-                if (optOutFilename == NULL)
-                {
-                    dmError("Output filename not set, required for image formats.\n");
-                    goto error;
-                }
-
-                switch (optOutFormat)
-                {
-                    case FFMT_IMAGE:
-                        res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE);
-
-                        if (res != DMERR_OK || outImage == NULL)
-                        {
-                            dmError("Error in bitmap to image conversion.\n");
-                            goto error;
-                        }
-
-                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
-                        break;
-
-
-                    case FFMT_BITMAP:
-                        res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE);
-                        break;
-
-                    case FFMT_CHAR:
-                    case FFMT_SPRITE:
-                        res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor);
-                        break;
-
-                    default:
-                        dmError("Unsupported output format for bitmap/image conversion.\n");
-                        break;
-                }
-                
-                dmImageFree(outImage);
-            }
-            break;
-
-        case FFMT_IMAGE:
-            {
-                DMImage *outImage = NULL;
-                int res = DMERR_OK;
-
-                if (optOutFilename == NULL)
-                {
-                    dmError("Output filename not set, required for image formats.\n");
-                    goto error;
-                }
-
-                // Read input
-                DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat];
-                if (ifmt->readFILE != NULL)
-                    res = ifmt->readFILE(inFile, &outImage);
-                else
-                    dmError("Unsupported input image format for bitmap/image conversion.\n");
-
-                if (res != DMERR_OK || outImage == NULL)
-                    break;
-                
-                switch (optOutFormat)
-                {
-                    case FFMT_IMAGE:
-                        res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
-                        break;
-
-                    case FFMT_CHAR:
-                    case FFMT_SPRITE:
-                        res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor);
-                        break;
-
-                    default:
-                        dmError("Unsupported output format for bitmap/image conversion.\n");
-                        break;
-                }
-                
-                dmImageFree(outImage);
-            }
-            break;
-    }
-
-    fclose(inFile);
-
-    dmFree(dataBuf);
-    exit(0);
-    return 0;
-
-error:
-    dmFree(dataBuf);
-    return -3;
-    exit(3);
-}
--- a/utils/mod2wav.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,314 +0,0 @@
-/*
- * mod2wav - Render XM/JSSMOD module to WAV waveform file
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2007 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include "jss.h"
-#include "jssmod.h"
-#include "jssmix.h"
-#include "jssplr.h"
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmwav.h"
-#include "dmmutex.h"
-
-
-char    *optInFilename = NULL, *optOutFilename = NULL;
-int     optOutFormat = JSS_AUDIO_S16,
-        optOutChannels = 2,
-        optOutFreq = 44100,
-        optMuteOChannels = -1,
-        optStartOrder = -1;
-BOOL    optUsePlayTime = FALSE;
-size_t  optPlayTime;
-
-
-DMOptArg optList[] =
-{
-    {  0, '?', "help",     "Show this help", OPT_NONE },
-    {  2, 'v', "verbose",  "Be more verbose", OPT_NONE },
-    {  3, '1', "16bit",    "16-bit output", OPT_NONE },
-    {  4, '8', "8bit",     "8-bit output", OPT_NONE },
-    {  5, 'm', "mono",     "Mono output", OPT_NONE },
-    {  6, 's', "stereo",   "Stereo output", OPT_NONE },
-    {  7, 'f', "freq",     "Output frequency", OPT_ARGREQ },
-    {  8, 'M', "mute",     "Mute other channels than #", OPT_ARGREQ },
-    {  9, 'o', "order",    "Start from order #", OPT_ARGREQ },
-    { 10, 't', "time",     "Play for # seconds", OPT_ARGREQ },
-//    {10, 'l', "loop",    "Loop for # times", OPT_ARGREQ },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    (void) optArg;
-    
-    switch (optN)
-    {
-        case 0:
-            dmPrintBanner(stdout, dmProgName,
-                "[options] [sourcefile] [destfile]");
-                
-            dmArgsPrintHelp(stdout, optList, optListN);
-            exit(0);
-            break;
-
-        case 2:
-            dmVerbosity++;
-            break;
-        
-        case 3:
-            optOutFormat = JSS_AUDIO_S16;
-            break;
-
-        case 4:
-            optOutFormat = JSS_AUDIO_U8;
-            break;
-
-        case 5:
-            optOutChannels = JSS_AUDIO_MONO;
-            break;
-
-        case 6:
-            optOutChannels = JSS_AUDIO_STEREO;
-            break;
-
-        case 7:
-            optOutFreq = atoi(optArg);
-            break;
-
-        case 8:
-            optMuteOChannels = atoi(optArg);
-            break;
-
-        case 9:
-            optStartOrder = atoi(optArg);
-            break;
-
-        case 10:
-            optPlayTime = atoi(optArg);
-            optUsePlayTime = TRUE;
-            break;
-
-        default:
-            dmError("Unknown argument '%s'.\n", currArg);
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    if (!optInFilename)
-        optInFilename = currArg;
-    else
-    if (!optOutFilename)
-        optOutFilename = currArg;
-    else
-    {
-        dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg);
-        return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-int main(int argc, char *argv[])
-{
-    DMResource *inFile = NULL;
-    FILE *outFile = NULL;
-    JSSModule *mod = NULL;
-    JSSMixer *dev = NULL;
-    JSSPlayer *plr = NULL;
-    int result = -1;
-    size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize;
-    Uint8 *mb = NULL;
-
-    dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL);
-    dmVerbosity = 1;
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    // Check arguments
-    if (optInFilename == NULL || optOutFilename == NULL)
-    {
-        dmError("Input or output file not specified. Try --help.\n");
-        return 1;
-    }
-    
-    // Initialize miniJSS
-    jssInit();
-    
-    // Open the source file
-    if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL)
-    {
-        dmError("Error opening input file '%s', %d: %s\n",
-            optInFilename, errno, strerror(errno));
-        return 1;
-    }
-
-    // Read module file
-    fprintf(stderr, "Reading file: %s\n", optInFilename);
-#ifdef JSS_SUP_XM
-    fprintf(stderr, "* Trying XM...\n");
-    result = jssLoadXM(inFile, &mod);
-#endif
-#ifdef JSS_SUP_JSSMOD
-    if (result != 0)
-    {
-        size_t bufgot, bufsize = dmfsize(inFile);
-        Uint8 *buf = dmMalloc(bufsize);
-        dmfseek(inFile, 0L, SEEK_SET);
-        fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
-        if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize)
-        {
-            fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n",
-                bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile)));
-            return 2;
-        }
-        result = jssLoadJSSMOD(buf, bufsize, &mod);
-        dmFree(buf);
-    }
-#endif
-    dmf_close(inFile);
-    if (result != DMERR_OK)
-    {
-        dmError("Error loading module file, %d: %s\n",
-            result, dmErrorStr(result));
-        return 3;
-    }
-
-    // Try to convert it
-    if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK)
-    {
-        dmError("Could not convert module for playing, %d: %s\n",
-            result, dmErrorStr(result));
-        return 3;
-    }
-
-    // Open mixer
-    dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO);
-    if (dev == NULL)
-    {
-        dmError("jvmInit() returned NULL\n");
-        return 4;
-    }
-
-    sampSize = jvmGetSampleSize(dev);
-    if ((mb = dmMalloc(bufLen * sampSize)) == NULL)
-    {
-        dmError("Could not allocate mixing buffer\n");
-        return 5;
-    }
-    
-    dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n",
-        optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq,
-        sampSize);
-    
-    // Initialize player
-    if ((plr = jmpInit(dev)) == NULL)
-    {
-        dmError("jmpInit() returned NULL.\n");
-        return 6;
-    }
-    
-    // Set callback
-    jvmSetCallback(dev, jmpExec, plr);
-    
-    // Initialize playing
-    jmpSetModule(plr, mod);
-    if (optStartOrder >= 0)
-    { 
-        dmMsg(1, "Starting from song order #%d\n", optStartOrder);
-    } else
-        optStartOrder = 0;
-
-    jmpPlayOrder(plr, optStartOrder);
-    jvmSetGlobalVol(dev, 150);
-    
-    if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels)
-    {
-        int i;
-        for (i = 0; i < mod->nchannels; i++)
-            jvmMute(dev, i, TRUE);
-        jvmMute(dev, optMuteOChannels - 1, FALSE);
-    }
-    
-    // Open output file
-    if ((outFile = fopen(optOutFilename, "wb")) == NULL)
-    {
-        dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno));
-        return 7;
-    }
-
-    // Write initial header
-    dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024);
-
-    // Render audio data and output to file
-    if (optUsePlayTime)
-        dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime);
-    else
-        dmMsg(1, "Rendering module ...\n");
-    
-    optPlayTime *= optOutFreq;
-    dataTotal = 0;
-    dataWritten = 1;
-    while (plr->isPlaying && dataWritten > 0)
-    {
-        size_t writeLen = bufLen;
-        if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime)
-            writeLen = optPlayTime - dataTotal;
-        
-        if (writeLen > 0)
-        {
-            jvmRenderAudio(dev, mb, writeLen);
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-            jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess);
-#endif
-            dataWritten = fwrite(mb, sampSize, writeLen, outFile);
-            if (dataWritten < writeLen)
-            {
-                dmError("Error writing data!\n");
-                fclose(outFile);
-                return 8;
-            }
-            dataTotal += dataWritten;
-        }
-        
-        if (optUsePlayTime && dataTotal >= optPlayTime)
-            break;
-    }
-    
-    // Write the correct header
-    if (fseek(outFile, 0L, SEEK_SET) != 0)
-    {
-        dmError("Error rewinding to header position!\n");
-        return 9;
-    }
-    
-    dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal);
-    
-    // Done!
-    fclose(outFile);
-
-    jmpClose(plr);
-    jvmClose(dev);
-    jssFreeModule(mod);
-    jssClose();
-
-    dmMsg(1, "OK.\n");
-    return 0;
-}
--- a/utils/objlink.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,990 +0,0 @@
-/*
- * objlink - Link files (RAW and PRG) into one PRG object
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2002-2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include <errno.h>
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmfile.h"
-#include "dmmutex.h"
-
-#define MAX_FILENAMES    (128)
-#define MAX_MEMBLOCKS    (128)
-
-
-/* Typedefs
- */
-typedef struct
-{
-    ssize_t start, end;	// Start and end address
-    int type;           // Type
-    char *name;         // Name of the block
-    int placement;
-} DMMemBlock;
-
-typedef struct
-{
-    char *name;         // Description of memory model
-    char *desc;
-    ssize_t size;        // Total addressable memory size
-    ssize_t nmemBlocks;  // Defined memory areas
-    DMMemBlock memBlocks[MAX_MEMBLOCKS];
-} DMMemModel;
-
-typedef struct
-{
-    char *filename;
-    int type;
-    int placement;
-    ssize_t addr;
-} DMSourceFile;
-
-// Source file type
-enum
-{
-    STYPE_RAW = 1,
-    STYPE_PRG,
-    STYPE_PRGA
-};
-
-// How to determine block placement / address
-enum
-{
-    PLACE_STATIC = 1,  // Already known
-    PLACE_ARGUMENT,   // Commandline argument
-    PLACE_FILE,       // From file
-};
-
-enum
-{
-    FMT_GENERIC = 1,
-    FMT_PLAIN,
-    FMT_DECIMAL
-};
-
-enum
-{
-    MTYPE_NONE = 0,
-    MTYPE_ROM,        // Hard ROM
-    MTYPE_ROM_WT,     // Write to RAM through ROM
-    MTYPE_IO,         // I/O lines
-    MTYPE_RES         // RESERVED
-};
-
-enum
-{
-    LA_NONE = -2,
-    LA_AUTO = -1
-};
-
-/* Memory models
- */
-const DMMemModel memoryModels[] = {
-    { "C64 unrestricted", "$01 = $34", (64*1024), 0, {
-    { 0, 0, 0, NULL, 0 }
-    }},
-
-    { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, {
-    { 0xA000, 0xBFFF,    MTYPE_ROM_WT,    "Basic ROM",  PLACE_STATIC },
-    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
-    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM",  PLACE_STATIC },
-    }},
-
-    { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, {
-    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
-    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM",  PLACE_STATIC },
-    }},
-
-    { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, {
-    { 0xD000, 0xDFFF,    MTYPE_IO,        "I/O",  PLACE_STATIC },
-    }},
-
-    { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, {
-    { 0xA000, 0xBFFF,    MTYPE_ROM_WT,    "Basic ROM",  PLACE_STATIC },
-    { 0xD000, 0xDFFF,    MTYPE_ROM,       "Char ROM", PLACE_STATIC },
-    { 0xE000, 0xFFFF,    MTYPE_ROM_WT,    "Kernal ROM", PLACE_STATIC },
-    }},
-
-/*
-    { "C64 normal", "$01 = $37", (64*1024), 0, {
-    { 0x0000, 0x0000,    MTYPE_RAM,    "" },
-    }},
-*/
-};
-
-static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]);
-
-
-/* Global variables
- */
-int           nsrcFiles = 0;              // Number of source files
-DMSourceFile  srcFiles[MAX_FILENAMES];    // Source file names
-
-int        nmemBlocks = 0;
-DMMemBlock memBlocks[MAX_FILENAMES];
-
-char       *optLinkFileName = NULL;
-int        optLinkFileFormat = FMT_GENERIC;
-
-BOOL       optDescribe = FALSE,
-           optAllowOverlap = FALSE;
-
-Uint32     optInitValue = 0;
-int        optInitValueType = 1;
-ssize_t    optCropStart, optCropEnd;
-BOOL       optCropOutput = FALSE;
-
-ssize_t    optLoadAddress = LA_AUTO;
-
-int        optMemModel = 0;
-const DMMemModel *memModel = NULL;
-Uint8      *memory = NULL;
-
-char       *optDestName = NULL;
-
-
-/* Arguments
- */
-static DMOptArg optList[] = {
-    {  0, '?', "help",        "Show this help", OPT_NONE },
-    {  1, 'r', "input-raw",   "RAW input: -r <file>:<addr>", OPT_ARGREQ },
-    {  2, 'p', "input-prg",   "PRG input: -p <file>[:<addr>]", OPT_ARGREQ },
-    { 12, 's', "section",     "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ },
-    {  5, 'o', "output",      "Specify output file, -o <file>", OPT_ARGREQ },
-    {  6, 'O', "overlap",     "Allow overlapping memory areas", OPT_NONE },
-    {  7, 'm', "model",       "Set memory model", OPT_ARGREQ },
-    {  8, 'l', "link-file",   "Output addresses and labels into file", OPT_ARGREQ },
-    {  9, 'f', "format",      "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ },
-    { 10, 'i', "initvalue",   "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ },
-    { 11, 'd', "describe",    "Output ASCII memory map description", OPT_NONE },
-    { 13, 'c', "crop",        "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ },
-    { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ },
-};
-
-static const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    int i;
-
-    dmPrintBanner(stdout, dmProgName, "[options]");
-    dmArgsPrintHelp(stdout, optList, optListN);
-
-    printf(
-    "\n"
-    "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n"
-    "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n"
-    "\n"
-    "Available memory models:\n");
-
-    for (i = 0; i < nmemoryModels; i++)
-    {
-        const DMMemModel *m = &memoryModels[i];
-        printf("  %d = %-40s [%s] (%d kB)\n",
-            i, m->name, m->desc, m->size / 1024);
-    }
-}
-
-
-off_t dmGetFileSize(FILE *f)
-{
-    off_t len, pos = ftell(f);
-    fseeko(f, 0, SEEK_END);
-    len = ftell(f);
-    fseek(f, pos, SEEK_SET);
-    return len;
-}
-
-
-/* Memory block handling
- */
-void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType)
-{
-    if (startAddr > endAddr)
-    {
-        dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n",
-            blockName, startAddr, endAddr);
-        exit(4);
-    }
-
-    if (nmemBlocks < MAX_FILENAMES)
-    {
-        memBlocks[nmemBlocks].start = startAddr;
-        memBlocks[nmemBlocks].end   = endAddr;
-        memBlocks[nmemBlocks].name  = dm_strdup(blockName);
-        memBlocks[nmemBlocks].type  = blockType;
-        nmemBlocks++;
-    }
-    else
-    {
-        dmError("Maximum number of memBlock definitions (%d) exceeded!\n",
-            MAX_FILENAMES);
-        exit(4);
-    }
-}
-
-
-int compareMemBlock(const void *cva, const void *cvb)
-{
-    const DMMemBlock *a = cva, *b = cvb;
-    return a->start - b->start;
-}
-
-
-BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName)
-{
-    char sectMode, *sep, *str, *namesep;
-    ssize_t tmpi;
-
-    // Define reserved section
-    // Create a copy of the argument
-    if ((str = dm_strdup(arg)) == NULL)
-    {
-        dmError("Could not allocate temporary string!\n");
-        exit(128);
-    }
-
-    // Get start address
-    if ((sep = strchr(str, '-')) == NULL &&
-        (sep = strchr(str, ':')) == NULL)
-    {
-        dmError("Section definition '%s' invalid.\n", arg);
-        goto error;
-    }
-    sectMode = *sep;
-    *sep = 0;
-
-    // Get value
-    if (!dmGetIntVal(str, sectStart))
-    {
-        dmError("Section start address '%s' in '%s' invalid.\n", str, arg);
-        goto error;
-    }
-    
-    // Check for name
-    namesep = strchr(sep + 1, ',');
-    if (canHasName && namesep != NULL)
-    {
-        *namesep = 0;
-        namesep++;
-        if (*namesep == 0)
-        {
-            dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n",
-                arg);
-            goto error;
-        }
-        *sectName = dm_strdup(namesep);
-    }
-    else
-    if (namesep != NULL)
-    {
-        dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n",
-            arg, namesep);
-        goto error;
-    }
-
-    // Get end address or length
-    if (!dmGetIntVal(sep + 1, &tmpi))
-    {
-        dmError("Section %s '%s' in '%s' invalid.\n",
-            sectMode == '-' ? "end address" : "length",
-            sep + 1, arg);
-        goto error;
-    }
-
-    if (sectMode == ':')
-    {
-        *sectEnd = *sectStart + tmpi - 1;
-    }
-    else
-    {
-        if (tmpi < *sectStart)
-        {
-            dmError("Section start address > end address in '%s'.\n",
-                arg);
-            goto error;
-        }
-        *sectEnd = tmpi;
-    }
-
-    dmFree(str);
-    return TRUE;
-
-error:
-    dmFree(str);
-    return FALSE;
-}
-
-
-BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr)
-{
-    ssize_t tmpi = 0;
-    BOOL hasAddr = FALSE;
-    char *sep;
-
-    if ((sep = strrchr(arg, ':')) != NULL)
-    {
-        *sep = 0;
-        if (!dmGetIntVal(sep + 1, &tmpi))
-        {
-            dmError("Invalid %s address '%s' specified for '%s'.\n",
-                desc, sep + 1, arg);
-            return FALSE;
-        }
-        hasAddr = TRUE;
-    }
-    else
-    if (requireAddr)
-    {
-        dmError("No %s loading address specified for '%s'.\n", desc, arg);
-        return FALSE;
-    }
-
-    srcFiles[nsrcFiles].filename = arg;
-    srcFiles[nsrcFiles].type = hasAddr ? type1 : type2;
-    srcFiles[nsrcFiles].addr = tmpi;
-    nsrcFiles++;
-    return TRUE;
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    char *p;
-    ssize_t tmpi;
-
-    switch (optN) {
-    case 0:
-        argShowHelp();
-        exit(0);
-        break;
-
-    case 1:
-        // Add RAW
-        if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE))
-            return FALSE;
-        break;
-
-    case 2:
-        // Add PRG
-        if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE))
-            return FALSE;
-        break;
-
-    case 5:
-        // Set output file name
-        optDestName = optArg;
-        break;
-
-    case 6:
-        // Allow overlapping segments
-        optAllowOverlap = TRUE;
-        dmError("Warning, allowing overlapping data.\n");
-        break;
-
-    case 7:
-        // Set memory model
-        optMemModel = atoi(optArg);
-        if (optMemModel < 0 || optMemModel >= nmemoryModels)
-        {
-            dmError("Invalid memory model number %i!\n", optMemModel);
-            return FALSE;
-        }
-        break;
-
-    case 8:
-        // Linker file
-        optLinkFileName = optArg;
-        break;
-
-    case 9:
-        // Linker file format
-        switch (tolower(optArg[0]))
-        {
-            case 'g':
-                optLinkFileFormat = FMT_GENERIC;
-                break;
-            case 'p':
-                optLinkFileFormat = FMT_PLAIN;
-                break;
-            case 'd':
-                optLinkFileFormat = FMT_DECIMAL;
-                break;
-
-            default:
-                dmError("Invalid/unknown linker file format '%s'!\n",
-                    optArg);
-                return FALSE;
-        }
-        break;
-
-    case 10:
-        // Initialization value
-        optInitValueType = 1;
-        if ((p = strrchr(optArg, ':')) != NULL)
-        {
-            *p = 0;
-            switch (tolower(p[1]))
-            {
-                case 'b': optInitValueType = 1; break;
-                case 'w': optInitValueType = 2; break;
-                case 'd': optInitValueType = 4; break;
-                default:
-                    dmError("Invalid init value type '%c' specified for '%s'.\n",
-                        p[1], optArg);
-                    return FALSE; 
-            }
-        }
-        if (!dmGetIntVal(optArg, &tmpi))
-        {
-            dmError("Invalid initvalue '%s'.\n", optArg);
-            return FALSE;
-        }
-        optInitValue = tmpi;
-        break;
-
-    case 11:
-        // Set describe mode
-        optDescribe = TRUE;
-        break;
-
-    case 12:
-        {
-            char *sectName = "Clear";
-            ssize_t sectStart, sectEnd, sectLen;
-            if (!dmParseSection(optArg, &sectStart, &sectEnd, &sectName, TRUE))
-                return FALSE;
-
-            // Allocate memory block
-            sectLen = sectEnd - sectStart + 1;
-            dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n",
-                sectStart, sectEnd, sectLen, sectLen, sectName);
-
-            reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES);
-        }
-        break;
-
-    case 13:
-        {
-            size_t cropLen;
-            if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE))
-                return FALSE;
-
-            cropLen = optCropEnd - optCropEnd + 1;
-            dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n",
-                optCropStart, optCropEnd, cropLen, cropLen);
-
-            optCropOutput = TRUE;
-        }
-        break;
-
-    case 14:
-        // Set loading address
-        if (strcasecmp(optArg, "none") == 0)
-            optLoadAddress = LA_NONE;
-        else
-        {
-            if (!dmGetIntVal(optArg, &tmpi))
-            {
-                dmError("Invalid loading address '%s'.\n", optArg);
-                return FALSE;
-            }
-            if (tmpi < 0 || tmpi >= 64*1024)
-            {
-                dmError("Invalid or insane loading address %d/$%x!\n",
-                    tmpi);
-                return FALSE;
-            }
-            optLoadAddress = tmpi;
-        }
-        break;
-
-    default:
-        dmError("Unknown argument '%s'.\n", currArg);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr)
-{
-    FILE *f;
-    ssize_t dataSize, loadAddr, endAddr;
-    Uint16 tmpAddr;
-
-    // Open the input file
-    if ((f = fopen(filename, "rb")) == NULL)
-    {
-        dmError("Error opening input file '%s' (%s).\n",
-            filename, strerror(errno));
-        return 1;
-    }
-
-    // Get filesize
-    if ((dataSize = dmGetFileSize(f) - 2) < 0)
-    {
-        dmError("Error getting file size for '%s'.\n", filename);
-        return 6;
-    }
-
-    // Get loading address
-    if (!dm_fread_le16(f, &tmpAddr))
-    {
-        dmError("Error reading input file '%s' (%s).\n",
-            filename, strerror(errno));
-        return 2;
-    }
-
-    // Show information
-    loadAddr = forceAddr ? destAddr : tmpAddr;
-    endAddr = loadAddr + dataSize - 1;
-
-    dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x",
-        filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr);
-
-    if (endAddr >= memModel->size)
-    {
-        dmPrint(1, " .. Does not fit into the memory!\n");
-        return 5;
-    }
-
-    // Load data
-    if (fread(&memory[loadAddr], dataSize, 1, f) < 1)
-    {
-        dmPrint(1, " .. Error: %s.\n",
-            strerror(errno));
-        return 4;
-    }
-
-    dmPrint(1, " .. OK\n");
-
-    // Add to list of blocks
-    reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES);
-
-    return 0;
-}
-
-
-int dmLoadRAW(const char *filename, const ssize_t destAddr)
-{
-    FILE *f;
-    ssize_t dataSize, endAddr;
-
-    // Open the input file
-    if ((f = fopen(filename, "rb")) == NULL)
-    {
-        dmError("Error opening input file '%s' (%s).\n",
-            filename, strerror(errno));
-        return 1;
-    }
-
-    // Get filesize
-    if ((dataSize = dmGetFileSize(f)) < 0)
-    {
-        dmError("Error getting file size for '%s'.\n", filename);
-        return 6;
-    }
-
-    // Show information
-    endAddr = destAddr + dataSize - 1;
-    dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x",
-        filename, destAddr, endAddr);
-
-    if (endAddr >= memModel->size)
-    {
-        dmPrint(1, " .. Does not fit into the memory!\n");
-        return 5;
-    }
-
-    // Load data
-    if (fread(&memory[destAddr], dataSize, 1, f) < 1)
-    {
-        dmPrint(1, " .. Error: %s.\n",
-            strerror(errno));
-        return 4;
-    }
-
-    dmPrint(1, " .. OK\n");
-
-    // Add info to list
-    reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES);
-
-    return 0;
-}
-
-
-int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd)
-{
-    char *tmpStr, *s, *t;
-    int blockSize;
-
-    blockSize = (blockEnd - blockStart + 1);
-
-    // Create label name from filename
-    tmpStr = dm_strdup(blockName);
-    if (tmpStr == NULL)
-    {
-        dmError("Could not allocate memory for string '%s'!\n",
-            blockName);
-        return -1;
-    }
-
-    if ((t = strrchr(tmpStr, '/')))
-        s = (t + 1);
-    else if ((t = strrchr(tmpStr, '\\')))
-        s = (t + 1);
-    else
-        s = tmpStr;
-
-    if ((t = strrchr(s, '.')))
-        *t = 0;
-
-    for (t = s; *t; t++)
-    {
-        if (!isalnum(*t))
-            *t = '_';
-    }
-
-    // Print the label line
-    switch (optLinkFileFormat)
-    {
-        case FMT_PLAIN:
-            fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart);
-            break;
-
-        case FMT_DECIMAL:
-            fprintf(dfile, "%s = %d\n", tmpStr, blockStart);
-            break;
-
-        case FMT_GENERIC:
-        default:
-            fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n",
-                blockName, blockStart, blockEnd, blockSize, blockSize);
-            fprintf(dfile, "%s = $%.4x\n", s, blockStart);
-            break;
-    }
-
-    dmFree(tmpStr);
-    return 0;
-}
-
-
-/* Print out an ASCII presentation of memory map
- */
-void memPrintLine(FILE *f)
-{
-    fprintf(f, "              +------------------------------------------+\n");
-}
-
-void memPrintEmpty(FILE *f, ssize_t n)
-{
-    ssize_t i;
-    for (i = 0; i < n; i++)
-    fprintf(f, "              |                                          |\n");
-}
-
-void dmDescribeMemory(FILE *f)
-{
-    int i;
-    DMMemBlock *prev = NULL;
-
-    memPrintLine(f);
-
-    for (i = 0; i < nmemBlocks; i++)
-    {
-        DMMemBlock *curr = &memBlocks[i];
-        char desc[512], *s;
-        ssize_t siz, kz;
-
-        // Check for empty, unreserved areas
-        siz = (curr->start - 1) - (prev->end + 1) + 1;
-        if (prev != NULL && siz > 1)
-        {
-            kz = siz / (1024 * 2);
-
-            if (kz > 1) memPrintEmpty(f, kz);
-
-            snprintf(desc, sizeof(desc), "EMPTY (%d)", siz);
-            fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc);
-
-            if (kz > 1) memPrintEmpty(f, kz);
-            memPrintLine(f);
-        }
-        prev = curr;
-
-        // Print current block
-        switch (curr->type)
-        {
-            case MTYPE_NONE:   s = "N/A (NC)"; break;
-            case MTYPE_ROM:    s = "ROM"; break;
-            case MTYPE_ROM_WT: s = "ROM/WT"; break;
-            case MTYPE_IO:     s = "I/O"; break;
-            case MTYPE_RES:    s = "RSVD"; break;
-            default:           s = "????"; break;
-        }
-
-        siz = curr->end - curr->start + 1;
-        kz = siz / (1024 * 2);
-
-        if (kz > 1) memPrintEmpty(f, kz);
-        snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz);
-        fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc);
-        if (kz > 1) memPrintEmpty(f, kz);
-        memPrintLine(f);
-
-    }
-
-    fprintf(f,
-    "\n"
-    "NC     = Not Connected\n"
-    "RSVD   = Reserved\n"
-    "ROM/WT = RAM under 'write-through' ROM\n"
-    "\n"
-    );
-}
-
-
-/*
- * The main program
- */
-int main(int argc, char *argv[])
-{
-    FILE *dfile = NULL;
-    BOOL hasOverlaps;
-    int i, j;
-    ssize_t startAddr, endAddr, dataSize, totalSize;
-
-    dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL);
-    dmVerbosity = 1;
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, NULL, TRUE))
-        exit(1);
-
-    if (nsrcFiles < 1)
-    {
-        dmError("Nothing to do. (try --help)\n");
-        exit(0);
-    }
-
-    // Allocate memory
-    memModel = &memoryModels[optMemModel];
-    dmMsg(1, "Using memory model #%d '%s', %d bytes.\n",
-        optMemModel, memModel->name, memModel->size);
-
-    memory = (Uint8 *) dmMalloc(memModel->size + 32);
-    if (memory == NULL)
-    {
-        dmError("Could not allocate memory.\n");
-        exit(2);
-    }
-
-    // Initialize memory
-    dmMsg(1, "Initializing memory with ");
-
-    if (optInitValueType == 1 || optInitValue <= 0xff)
-    {
-        dmPrint(1, "BYTE 0x%.2x\n", optInitValue);
-        memset(memory, optInitValue, memModel->size);
-    }
-    else
-    if (optInitValueType == 2 || optInitValue <= 0xffff)
-    {
-        uint16_t *mp = (uint16_t *) memory;
-        dmPrint(1, "WORD 0x%.4x\n", optInitValue);
-        for (i = memModel->size / sizeof(*mp); i; i--)
-        {
-            *mp++ = optInitValue;
-        }
-    }
-    else
-    {
-        Uint32 *mp = (Uint32 *) memory;
-        dmPrint(1, "DWORD 0x%.8x\n", optInitValue);
-        for (i = memModel->size / sizeof(*mp); i; i--)
-        {
-            *mp++ = optInitValue;
-        }
-    }
-
-    // Load the datafiles
-    for (i = 0; i < nsrcFiles; i++)
-    switch (srcFiles[i].type)
-    {
-        case STYPE_RAW:
-            dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr);
-            break;
-
-        case STYPE_PRG:
-            dmLoadPRG(srcFiles[i].filename, FALSE, 0);
-            break;
-
-        case STYPE_PRGA:
-            dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr);
-            break;
-    }
-
-    // Add memory model blocks
-    dmMsg(1, "Applying memory model restrictions...\n");
-    for (i = 0; i < memModel->nmemBlocks; i++)
-    {
-        reserveMemBlock(
-            memModel->memBlocks[i].start,
-            memModel->memBlocks[i].end,
-            memModel->memBlocks[i].name,
-            memModel->memBlocks[i].type);
-    }
-
-    // Sort the blocks
-    qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock);
-
-    // Check for overlapping conflicts
-    hasOverlaps = FALSE;
-    for (i = 0; i < nmemBlocks; i++)
-    for (j = 0; j < nmemBlocks; j++)
-    if (j != i && memBlocks[i].type == MTYPE_RES)
-    {
-        DMMemBlock *mbi = &memBlocks[i],
-                   *mbj = &memBlocks[j];
-
-        // Check for per-file conflicts
-        if ((mbj->start >= mbi->start && mbj->start <= mbi->end) ||
-            (mbj->end >= mbi->start && mbj->end <= mbi->end))
-        {
-            dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x  vs  $%.4x-$%.4x)\n",
-                mbi->name, mbj->name, mbi->start,
-                mbi->end, mbj->start, mbj->end);
-            hasOverlaps = TRUE;
-        }
-    }
-
-    if (!optAllowOverlap && hasOverlaps)
-    {
-        dmError("Error occured, overlaps not allowed.\n");
-        exit(5);
-    }
-
-    // Find out start and end-addresses
-    startAddr = memModel->size;
-    totalSize = endAddr = 0;
-    for (i = 0; i < nmemBlocks; i++)
-    {
-        DMMemBlock *mbi = &memBlocks[i];
-        if (mbi->type == MTYPE_RES)
-        {
-            if (mbi->start < startAddr)
-                startAddr = mbi->start;
-
-            if (mbi->end > endAddr)
-                endAddr = mbi->end;
-
-            totalSize += (mbi->end - mbi->start + 1);
-        }
-    }
-
-    if (startAddr >= memModel->size || endAddr < startAddr)
-    {
-        dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr);
-        exit(8);
-    }
-
-    // Output linkfile
-    if (optLinkFileName)
-    {
-        dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName);
-        if ((dfile = fopen(optLinkFileName, "wb")) == NULL)
-        {
-            dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno));
-            exit(1);
-        }
-
-        switch (optLinkFileFormat)
-        {
-            case FMT_GENERIC:
-            default:
-                fprintf(dfile, "; Definitions generated by %s v%s\n",
-                    dmProgName, dmProgVersion);
-                break;
-        }
-
-        for (i = 0; i < nmemBlocks; i++)
-        {
-            DMMemBlock *mbi = &memBlocks[i];
-            outputLinkData(dfile, mbi->name, mbi->start, mbi->end);
-        }
-
-        fclose(dfile);
-    }
-
-    // Show some information
-    if (optCropOutput)
-    {
-        startAddr = optCropStart;
-        endAddr = optCropEnd;
-    }
-
-    dataSize = endAddr - startAddr + 1;
-
-    if (dataSize - totalSize > 0)
-    {
-        dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n",
-            dataSize - totalSize, dataSize - totalSize);
-    }
-
-    dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ",
-        startAddr, endAddr, dataSize, dataSize);
-
-
-    // Open the destination file
-    if (optDestName == NULL)
-    {
-        dfile = stdout;
-        dmPrint(1, "...\n");
-    }
-    else if ((dfile = fopen(optDestName, "wb")) == NULL)
-    {
-        dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno));
-        exit(1);
-    }
-    else
-        dmPrint(1, "to '%s'\n", optDestName);
-
-    // Save loading address
-    if (optLoadAddress >= 0)
-    {
-        dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress);
-        dm_fwrite_le16(dfile, optLoadAddress);
-    }
-    else
-    if (optLoadAddress == LA_AUTO)
-    {
-        dmMsg(1, "Using automatic loading address $%.4x\n", startAddr);
-        dm_fwrite_le16(dfile, startAddr);
-    }
-    else
-    {
-        dmMsg(1, "Writing raw output, without loading address.\n");
-    }
-
-    // Save the data
-    if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1)
-    {
-        dmError("Error writing to file (%s)\n", strerror(errno));
-    }
-
-    fclose(dfile);
-
-    // Describe
-    if (optDescribe)
-        dmDescribeMemory(stdout);
-
-    exit(0);
-    return 0;
-}
--- a/utils/packed.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,465 +0,0 @@
-/*
- * PACKed - PACKfile EDitor
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmpack.h"
-#include "dmpackutil.h"
-#include "dmres.h"
-#include "dmmutex.h"
-#include <errno.h>
-
-#define	SET_MAX_FILES	  (4096)
-#define SET_DEFAULT_PACK  "data.pak"
-
-enum
-{
-    CMD_NONE = 0,
-    CMD_CREATE,
-    CMD_ADD,
-    CMD_LIST,
-    CMD_EXTRACT
-} DCOMMAND;
-
-enum
-{
-    PACK_EXTRACTED = 0x0001,
-};
-
-int    nsrcFilenames = 0;
-char * srcFilenames[SET_MAX_FILES];
-char * optPackFilename = NULL;
-BOOL   optCompress = TRUE;
-int    optCommand = CMD_NONE;
-int    optDefResFlags = 0;
-
-
-static DMOptArg optList[] =
-{
-    { 0, '?', "help",        "Show this help", OPT_NONE },
-    { 1, 'p', "pack",        "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ },
-    { 2, 'c', "create",      "Create and add files to PACK", OPT_NONE },
-    { 3, 'a', "add",         "Add files to PACK", OPT_NONE },
-    { 4, 'l', "list",        "List files in PACK", OPT_NONE },
-    { 5, 'e', "extract",     "Extract files from PACK", OPT_NONE },
-    { 6, 'n', "nocompress",  "No compression", OPT_NONE },
-    { 7, 'v', "verbose",     "Increase verbosity", OPT_NONE },
-    { 8, 'f', "resflags",    "Set default resource flags (-f 0xff)", OPT_ARGREQ },
-};
-
-static const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]");
-    dmArgsPrintHelp(stdout, optList, optListN);
-    fprintf(stdout,
-    "\n"
-    "Examples:\n"
-    "$ %s -p test.pak -l         -- list files in test.pak\n"
-    "$ %s -a foobar.jpg          -- add foobar.jpg in " SET_DEFAULT_PACK "\n"
-    "$ %s -x foobar.jpg          -- extract foobar.jpg from " SET_DEFAULT_PACK "\n",
-    dmProgName, dmProgName, dmProgName);
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    (void) optArg;
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            optPackFilename = optArg;
-            break;
-        case 2:
-            optCommand = CMD_CREATE;
-            break;
-        case 3:
-            optCommand = CMD_ADD;
-            break;
-        case 4:
-            optCommand = CMD_LIST;
-            break;
-        case 5:
-            optCommand = CMD_EXTRACT;
-            break;
-
-        case 6:
-            optCompress = FALSE;
-            break;
-
-        case 7:
-            dmVerbosity++;
-            break;
-
-        case 8:
-            {
-                int i;
-                if (!dmGetIntVal(optArg, &i))
-                {
-                    dmError("Invalid flags value '%s'.\n", optArg);
-                    return FALSE;
-                }
-                optDefResFlags = i;
-            }
-            break;
-
-        default:
-            dmError("Unknown argument '%s'.\n", currArg);
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    if (nsrcFilenames < SET_MAX_FILES)
-    {
-        srcFilenames[nsrcFilenames] = currArg;
-        nsrcFilenames++;
-    }
-    else
-    {
-        dmError("Maximum number of input files (%d) exceeded!\n",
-              SET_MAX_FILES);
-        return FALSE;
-    }
-    return TRUE;
-}
-
-
-/* Compare a string to a pattern. Case-SENSITIVE version.
- * The matching pattern can consist of any normal characters plus
- * wildcards ? and *. "?" matches any character and "*" matches
- * any number of characters.
- */
-BOOL dm_strmatch(const char *str, const char *pattern)
-{
-    BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE;
-    const char *tmpPattern = NULL;
-
-    // Check given pattern and string
-    if (str == NULL || pattern == NULL)
-        return FALSE;
-
-    // Start comparision
-    do {
-        didMatch = FALSE;
-        switch (*pattern)
-        {
-        case '?':
-            // Any single character matches
-            if (*str)
-            {
-                didMatch = TRUE;
-                pattern++;
-                str++;
-            }
-            break;
-
-        case '*':
-            didMatch = TRUE;
-            pattern++;
-            if (!*pattern)
-                isEnd = TRUE;
-            isAnyMode = TRUE;
-            tmpPattern = pattern;
-            break;
-
-        case 0:
-            if (isAnyMode)
-            {
-                if (*str)
-                    str++;
-                else
-                    isEnd = TRUE;
-            }
-            else
-            {
-                if (*str)
-                {
-                    if (tmpPattern)
-                    {
-                        isAnyMode = TRUE;
-                        pattern = tmpPattern;
-                    }
-                    else
-                        didMatch = FALSE;
-                }
-                else
-                    isEnd = TRUE;
-            }
-            break;
-        default:
-            if (isAnyMode)
-            {
-                if (*pattern == *str)
-                {
-                    isAnyMode = FALSE;
-                    didMatch = TRUE;
-                }
-                else
-                {
-                    if (*str)
-                    {
-                        didMatch = TRUE;
-                        str++;
-                    }
-                }
-            }
-            else
-            {
-                if (*pattern == *str)
-                {
-                    didMatch = TRUE;
-                    if (*pattern)
-                        pattern++;
-                    if (*str)
-                        str++;
-                }
-                else
-                {
-                    if (tmpPattern)
-                    {
-                        didMatch = TRUE;
-                        isAnyMode = TRUE;
-                        pattern = tmpPattern;
-                    }
-                }
-            }
-
-            if (!*str && !*pattern)
-                isEnd = TRUE;
-            break;
-
-        }        // switch
-
-    } while (didMatch && !isEnd);
-
-    return didMatch;
-}
-
-
-int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags)
-{
-    DMPackEntry *node;
-    int res = dm_pack_add_file(pack, filename, compression, resFlags, &node);
-
-    if (res != DMERR_OK)
-    {
-        dmPrint(1, "%-32s [ERROR:%d]\n",
-            filename, res);
-    }
-    else
-    {
-        char tmp[16];
-        dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags);
-        dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n",
-            filename, node->filename,
-            node->size, node->length, node->offset,
-            tmp);
-    }
-
-    return res;
-}
-
-
-int main(int argc, char *argv[])
-{
-    int i, res = 0;
-    DMPackFile *pack = NULL;
-
-#ifndef __WIN32
-    stderr = stdout;
-#endif
-
-    // Parse arguments
-    dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL);
-    dmVerbosity = 1;
-    
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    // Check PACK filename
-    if (optPackFilename == NULL)
-        optPackFilename = SET_DEFAULT_PACK;
-
-    if (optCommand == CMD_NONE)
-    {
-        argShowHelp();
-        dmError("Nothing to do.\n");
-        exit(0);
-        return 0;
-    }
-    
-    dmMsg(1, "Processing %s ...\n", optPackFilename);
-
-    // Execute command
-    switch (optCommand)
-    {
-    case CMD_CREATE:
-    case CMD_ADD:
-        switch (optCommand)
-        {
-        case CMD_CREATE:
-            dmMsg(1, "Creating new PACK\n");
-            res = dm_pack_create(optPackFilename, &pack);
-            break;
-
-        case CMD_ADD:
-            dmMsg(1, "Opening existing PACK\n");
-            res = dm_pack_open(optPackFilename, &pack, FALSE);
-            break;
-        }
-
-        // Add files into PACK
-        if (res == DMERR_OK)
-        {
-            dmMsg(1, "Adding %d files...\n", nsrcFilenames);
-
-            for (i = 0; i < nsrcFilenames; i++)
-            {
-                // Handle resource definition files
-                if (srcFilenames[i][0] == '@')
-                {
-                }
-                else
-                {
-                    dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags);
-                }
-            }
-
-            dmMsg(1, "w=%d\n", dm_pack_write(pack));
-            dmMsg(1, "c=%d\n", dm_pack_close(pack));
-        }
-        else
-        {
-            dmError("Could not open packfile, error #%d: %s\n", res,
-                  dmErrorStr(res));
-        }
-        break;
-
-    case CMD_LIST:
-        // List files in PACK
-        res = dm_pack_open(optPackFilename, &pack, TRUE);
-        if (res == DMERR_OK)
-        {
-            DMPackEntry *node;
-            for (i = 0, node = pack->entries; node; i++)
-                node = node->next;
-            dmMsg(1, "%d files total\n", i);
-
-            dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n",
-                "Name", "Size", "CSize", "Offset", "ResFlags");
-
-            for (node = pack->entries; node != NULL; node = node->next)
-            {
-                BOOL match;
-                
-                // Check for matches
-                if (nsrcFilenames > 0)
-                {
-                    match = FALSE;
-                    for (i = 0; i < nsrcFilenames && !match; i++)
-                    {
-                        match = dm_strmatch(node->filename, srcFilenames[i]);
-                    }
-                }
-                else
-                    match = TRUE;
-
-                if (match)
-                {
-                    char flags[16];
-                    dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags);
-
-                    dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n",
-                        node->filename, node->size, node->length,
-                        node->offset, flags);
-                }
-            }
-
-            dmMsg(1, "c=%d\n", dm_pack_close(pack));
-        }
-        else
-            dmError("Could not open packfile, error #%d: %s\n", res,
-                  dmErrorStr(res));
-        break;
-
-    case CMD_EXTRACT:
-        // Extract files from PACK
-        res = dm_pack_open(optPackFilename, &pack, TRUE);
-        if (res == DMERR_OK)
-        {
-            DMPackEntry *node;
-            FILE *resFile = fopen(DMRES_RES_FILE, "w");
-            if (resFile == NULL)
-            {
-                dmError("Could not create resource output file '%s' #%d: %s\n",
-                    DMRES_RES_FILE, errno, strerror(errno));
-            }
-
-            for (node = pack->entries; node != NULL; node = node->next)
-            {
-                BOOL match;
-                
-                // Check for matches
-                if (nsrcFilenames > 0)
-                {
-                    match = FALSE;
-                    for (i = 0; (i < nsrcFilenames) && !match; i++)
-                    {
-                        match = dm_strmatch(node->filename, srcFilenames[i]);
-                    }
-                }
-                else
-                    match = TRUE;
-
-                if (match && (node->privFlags & PACK_EXTRACTED) == 0)
-                {
-                    char tmp[16];
-
-                    // Mark as done
-                    node->privFlags |= PACK_EXTRACTED;
-
-                    // Print one entry
-                    dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags);
-                    dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n",
-                            node->filename, node->size, node->length,
-                            node->offset, tmp);
-
-                    dm_pack_extract_file(pack, node);
-                    
-                    if (resFile != NULL)
-                    {
-                        fprintf(resFile,
-                        "%s|%s\n", node->filename, tmp);
-                    }
-                }
-            }
-
-            dmMsg(1, "c=%d\n", dm_pack_close(pack));
-            
-            if (resFile != NULL)
-                fclose(resFile);
-        }
-        else
-            dmError("Could not open packfile, error #%d: %s\n", res,
-                  dmErrorStr(res));
-        break;
-
-    }
-
-    return 0;
-}
--- a/utils/ppl.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,932 +0,0 @@
-/*
- * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include <SDL.h>
-#include "dmlib.h"
-
-#include "jss.h"
-#include "jssmod.h"
-#include "jssmix.h"
-#include "jssplr.h"
-
-#include "dmargs.h"
-#include "dmimage.h"
-#include "dmtext.h"
-
-#include "setupfont.h"
-
-
-struct
-{
-    BOOL exitFlag;
-    SDL_Surface *screen;
-    SDL_Event event;
-    int optScrWidth, optScrHeight, optVFlags, optScrDepth;
-
-    int actChannel;
-    BOOL pauseFlag;
-
-    JSSModule *mod;
-    JSSMixer *dev;
-    JSSPlayer *plr;
-    SDL_AudioSpec afmt;
-} engine;
-
-struct
-{
-    Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel;
-} col;
-
-
-DMBitmapFont *font = NULL;
-
-char    *optFilename = NULL;
-int     optOutFormat = JSS_AUDIO_S16,
-        optOutChannels = 2,
-        optOutFreq = 48000,
-        optMuteOChannels = -1,
-        optStartOrder = 0;
-BOOL    optUsePlayTime = FALSE;
-size_t  optPlayTime;
-
-
-DMOptArg optList[] =
-{
-    {  0, '?', "help",     "Show this help", OPT_NONE },
-    {  1, 'v', "verbose",  "Be more verbose", OPT_NONE },
-    {  2,   0, "fs",       "Fullscreen", OPT_NONE },
-    {  3, 'w', "window",   "Initial window size/resolution -w 640x480", OPT_ARGREQ },
-
-    {  4, '1', "16bit",    "16-bit output", OPT_NONE },
-    {  5, '8', "8bit",     "8-bit output", OPT_NONE },
-    {  6, 'm', "mono",     "Mono output", OPT_NONE },
-    {  7, 's', "stereo",   "Stereo output", OPT_NONE },
-    {  8, 'f', "freq",     "Output frequency", OPT_ARGREQ },
-
-    {  9, 'M', "mute",     "Mute other channels than #", OPT_ARGREQ },
-    { 10, 'o', "order",    "Start from order #", OPT_ARGREQ },
-    { 11, 't', "time",     "Play for # seconds", OPT_ARGREQ },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName, "[options] <module>");
-    dmArgsPrintHelp(stdout, optList, optListN);
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    switch (optN) {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            dmVerbosity++;
-            break;
-        
-        case 2:
-            engine.optVFlags |= SDL_FULLSCREEN;
-            break;
-
-        case 3:
-            {
-                int w, h;
-                if (sscanf(optArg, "%dx%d", &w, &h) == 2)
-                {
-                    if (w < 320 || h < 200 || w > 3200 || h > 3200)
-                    {
-                        dmError("Invalid width or height: %d x %d\n", w, h);
-                        return FALSE;
-                    }
-                    engine.optScrWidth = w;
-                    engine.optScrHeight = h;
-                }
-                else 
-                {
-                    dmError("Invalid size argument '%s'.\n", optArg);
-                    return FALSE;
-                }
-            }
-            break;
-
-        case 4:
-            optOutFormat = JSS_AUDIO_S16;
-            break;
-
-        case 5:
-            optOutFormat = JSS_AUDIO_U8;
-            break;
-
-        case 6:
-            optOutChannels = JSS_AUDIO_MONO;
-            break;
-
-        case 7:
-            optOutChannels = JSS_AUDIO_STEREO;
-            break;
-
-        case 8:
-            optOutFreq = atoi(optArg);
-            break;
-
-        case 9:
-            optMuteOChannels = atoi(optArg);
-            break;
-
-        case 10:
-            optStartOrder = atoi(optArg);
-            break;
-
-        case 11:
-            optPlayTime = atoi(optArg);
-            optUsePlayTime = TRUE;
-            break;
-
-        default:
-            dmError("Unknown option '%s'.\n", currArg);
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    if (!optFilename)
-        optFilename = currArg;
-    else
-    {
-        dmError("Too many filename arguments '%s'\n", currArg);
-        return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt)
-{
-    const char *ptr = fmt;
-    DMUnscaledBlitFunc blit = NULL;
-
-    while (*ptr)
-    {
-        int ch = *ptr++;
-        SDL_Surface *glyph;
-
-        if (ch == '_')
-        {
-            xc += 4;
-            continue;
-        }
-        
-        if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL)
-        {
-            if (blit == NULL)
-                blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode);
-            
-            blit(glyph, xc, yc, screen);
-            xc += font->width;
-        }
-        else
-            xc += font->width;
-    }
-}
-
-
-void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap)
-{
-    char tmp[512];
-    vsnprintf(tmp, sizeof(tmp), fmt, ap);
-    dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp);
-}
-
-
-void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...)
-{
-    va_list ap;
-    
-    va_start(ap, fmt);
-    dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap);
-    va_end(ap);
-}
-
-
-Uint32 dmCol(float r, float g, float b)
-{
-    return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b);
-}
-
-
-BOOL dmInitializeVideo()
-{
-    SDL_FreeSurface(engine.screen);
-
-    engine.screen = SDL_SetVideoMode(
-        engine.optScrWidth, engine.optScrHeight, engine.optScrDepth,
-        engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE);
-
-    if (engine.screen == NULL)
-    {
-        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
-        return FALSE;
-    }
-
-    col.inboxBg    = dmCol(0.6, 0.5, 0.2);
-    col.boxBg      = dmCol(0.7, 0.6, 0.3);
-    col.box1       = dmCol(1.0, 0.9, 0.6);
-    col.box2       = dmCol(0.3, 0.3, 0.15);
-    col.viewDiv    = dmCol(0,0,0);
-    col.activeRow  = dmCol(0.5,0.4,0.1);
-    col.activeChannel = dmCol(0.6, 0.8, 0.2);
-
-    return TRUE;
-}
-
-
-void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn)
-{
-    int yh = y1 - y0 - 2;
-    if (yh < 10 || chn == NULL)
-        return;
-
-    int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume);
-    int pitch = screen->pitch / sizeof(Uint32);
-    int len = FP_GETH(chn->chSize);
-    DMFixedPoint offs = chn->chPos;
-    Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0);
-    Uint32 *pix = screen->pixels;
-    Sint16 *data = chn->chData;
-
-
-    dmFillBox3D(screen, x0, y0, x1, y1,
-        (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)),
-        nchannel == engine.actChannel ? colx : col.box2,
-        nchannel == engine.actChannel ? colx : col.box1);
-
-    if (chn->chData == NULL || !chn->chPlaying)
-        return;
-
-    if (chn->chDirection)
-    {
-        for (xc = x0 + 1; xc < x1 - 1; xc++)
-        {
-            if (FP_GETH(offs) >= len)
-                break;
-            Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255);
-            pix[xc + val * pitch] = coln;
-            FP_ADD(offs, chn->chDeltaO);
-        }
-    }
-    else
-    {
-        for (xc = x0 + 1; xc < x1 - 1; xc++)
-        {
-            if (FP_GETH(offs) < 0)
-                break;
-            Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255);
-            pix[xc + val * pitch] = coln;
-            FP_SUB(offs, chn->chDeltaO);
-        }
-    }
-}
-
-
-void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev)
-{
-    int nchannel, qx, qy,
-        qwidth = x1 - x0,
-        qheight = y1 - y0,
-        nwidth = jsetNChannels,
-        nheight = 1;
-    
-    if (qheight < 40)
-        return;
-    
-    while (qwidth / nwidth <= 60 && qheight / nheight >= 40)
-    {
-        nheight++;
-        nwidth /= nheight;
-    }
-
-//    fprintf(stderr, "%d x %d\n", nwidth, nheight);
-    
-    if (qheight / nheight <= 40)
-    {
-        nwidth = qwidth / 60;
-        nheight = qheight / 40;
-    }
-
-    qwidth /= nwidth;
-    qheight /= nheight;
-        
-    for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++)
-    {
-        for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++)
-        {
-            int xc = x0 + qx * qwidth,
-                yc = y0 + qy * qheight;
-
-            dmDisplayChn(screen, xc + 1, yc + 1,
-                xc + qwidth - 1, yc + qheight - 1,
-                nchannel, &dev->channels[nchannel]);
-
-            nchannel++;
-        }
-    }
-}
-
-
-static const char patNoteTable[12][3] =
-{
-    "C-", "C#", "D-",
-    "D#", "E-", "F-",
-    "F#", "G-", "G#",
-    "A-", "A#", "B-"
-};
-
-
-#define jmpNMODEffectTable (36)
-static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-static const char jmpHexTab[16] = "0123456789ABCDEF";
-
-static inline char dmHexVal(int v)
-{
-    return jmpHexTab[v & 15];
-}
-
-void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n)
-{
-    char text[32];
-    char *ptr = text;
-    
-    switch (n->note)
-    {
-        case jsetNotSet:
-            strcpy(ptr, "..._");
-            break;
-        case jsetNoteOff:
-            strcpy(ptr, "===_");
-            break;
-        default:
-            sprintf(ptr, "%s%i_",
-                patNoteTable[n->note % 12],
-                n->note / 12);
-            break;
-    }
-
-    ptr += 4;
-
-    if (n->instrument != jsetNotSet)
-    {
-        int v = n->instrument + 1;
-        *ptr++ = dmHexVal(v >> 4);
-        *ptr++ = dmHexVal(v);
-    }
-    else
-    {
-        *ptr++ = '.';
-        *ptr++ = '.';
-    }
-    *ptr++ = '_';
-
-    if (n->volume == jsetNotSet)
-    {
-        *ptr++ = '.';
-        *ptr++ = '.';
-    }
-    else
-    if (n->volume >= 0x00 && n->volume <= 0x40)
-    {
-        *ptr++ = dmHexVal(n->volume >> 4);
-        *ptr++ = dmHexVal(n->volume);
-    }
-    else
-    {
-        char c;
-        switch (n->volume & 0xf0)
-        {
-            case 0x50: c = '-'; break;
-            case 0x60: c = '+'; break;
-            case 0x70: c = '/'; break;
-            case 0x80: c = '\\'; break;
-            case 0x90: c = 'S'; break;
-            case 0xa0: c = 'V'; break;
-            case 0xb0: c = 'P'; break;
-            case 0xc0: c = '<'; break;
-            case 0xd0: c = '>'; break;
-            case 0xe0: c = 'M'; break;
-            default:   c = '?'; break;
-        }
-        *ptr++ = c;
-        *ptr++ = dmHexVal(n->volume);
-    }
-    *ptr++ = '_';
-    
-    if (n->effect >= 0 && n->effect < jmpNMODEffectTable)
-        *ptr++ = jmpMODEffectTable[n->effect];
-    else
-        *ptr++ = (n->effect == jsetNotSet ? '.' : '?');
-
-    if (n->param != jsetNotSet)
-    {
-        *ptr++ = dmHexVal(n->param >> 4);
-        *ptr++ = dmHexVal(n->param);
-    }
-    else
-    {
-        *ptr++ = '.';
-        *ptr++ = '.';
-    }
-
-    *ptr = 0;
-
-    dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text);
-}
-
-
-void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row)
-{
-    int cwidth = (font->width * 10 + 3 * 4 + 5),
-        lwidth = 6 + font->width * 3,
-        qy0 = y0 + font->height + 2,
-        qy1 = y1 - font->height - 2,
-        qwidth  = ((x1 - x0 - lwidth) / cwidth),
-        qheight = ((qy1 - qy0 - 4) / (font->height + 1)),
-        nrow, nchannel, yc, choffs,
-        midrow = qheight / 2;
-
-    if (engine.actChannel < qwidth / 2)
-        choffs = 0;
-    else
-    if (engine.actChannel >= pat->nchannels - qwidth/2)
-        choffs = pat->nchannels - qwidth;
-    else
-        choffs = engine.actChannel - qwidth/2;
-
-    dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1);
-
-    for (nchannel = 0; nchannel < qwidth; nchannel++)
-    {
-        int bx0 = x0 + lwidth + 1 + nchannel * cwidth, 
-            bx1 = bx0 + cwidth;
-            
-        if (engine.actChannel == nchannel + choffs)
-        {
-            dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel);
-        }
-        else
-        {
-            dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg);
-        }
-    }
-
-    yc = qy0 + 2 + (font->height + 1) * midrow;
-    dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow);
-
-    for (nchannel = 0; nchannel < qwidth; nchannel++)
-    {
-        int bx0 = x0 + lwidth + 1 + nchannel * cwidth, 
-            bx1 = bx0 + cwidth;
-
-        dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv);
-
-        if (jvmGetMute(engine.dev, nchannel + choffs))
-        {
-            dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT,
-                bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED");
-        }
-        
-        dmDrawBMTextQ(screen, font, DMD_TRANSPARENT,
-            bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d",
-            nchannel + choffs);
-    }
-    
-    for (nrow = 0; nrow < qheight; nrow++)
-    {
-        int crow = nrow - midrow + row;
-        yc = qy0 + 2 + (font->height + 1) * nrow;
-        
-        if (crow >= 0 && crow < pat->nrows)
-        {
-            dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow);
-
-            for (nchannel = 0; nchannel < qwidth; nchannel++)
-            {
-                if (choffs + nchannel >= pat->nchannels)
-                    break;
-
-                dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc,
-                    pat->data + (pat->nchannels * crow) + choffs + nchannel);
-            }
-        }
-    }
-}
-
-
-void audioCallback(void *userdata, Uint8 *stream, int len)
-{
-    JSSMixer *d = (JSSMixer *) userdata;
-
-    if (d != NULL)
-    {
-        jvmRenderAudio(d, stream, len / jvmGetSampleSize(d));
-    }
-}
-
-
-void dmMuteChannels(BOOL mute)
-{
-    int i;
-    for (i = 0; i < engine.mod->nchannels; i++)
-        jvmMute(engine.dev, i, mute);
-}
-
-int main(int argc, char *argv[])
-{
-    BOOL initSDL = FALSE, audioInit = FALSE;
-    DMResource *file = NULL;
-    int result = -1;
-    BOOL muteState = FALSE;
-
-    memset(&engine, 0, sizeof(engine));
-
-    engine.optScrWidth = 640;
-    engine.optScrHeight = 480;
-    engine.optScrDepth = 32;
-
-    dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL);
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    // Open the files
-    if (optFilename == NULL)
-    {
-        dmError("No filename specified.\n");
-        return 1;
-    }
-    
-    if ((file = dmf_create_stdio(optFilename, "rb")) == NULL)
-    {
-        int err = dmGetErrno();
-        dmError("Error opening file '%s', %d: (%s)\n",
-            optFilename, err, dmErrorStr(err));
-        return 1;
-    }
-
-    // Initialize miniJSS
-    jssInit();
-
-    // Read module file
-    dmMsg(1, "Reading file: %s\n", optFilename);
-#ifdef JSS_SUP_XM
-    dmMsg(2, "* Trying XM...\n");
-    result = jssLoadXM(file, &engine.mod);
-#endif
-#ifdef JSS_SUP_JSSMOD
-    if (result != 0)
-    {
-        size_t bufgot, bufsize = dmfsize(file);
-        Uint8 *buf = dmMalloc(bufsize);
-        dmfseek(file, 0L, SEEK_SET);
-        dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
-        if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize)
-        {
-            dmf_close(file);
-            dmError("Error reading file (not enough data %d), #%d: %s\n",
-                bufgot, dmferror(file), dmErrorStr(dmferror(file)));
-            goto error_exit;
-        }
-        result = jssLoadJSSMOD(buf, bufsize, &engine.mod);
-        dmFree(buf);
-    }
-#endif
-    dmf_close(file);
-
-    if (result != DMERR_OK)
-    {
-        dmError("Error loading module file, %d: %s\n",
-            result, dmErrorStr(result));
-        goto error_exit;
-    }
-
-    // Try to convert it
-    if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK)
-    {
-        dmError("Could not convert module for playing, %d: %s\n",
-            result, dmErrorStr(result));
-        goto error_exit;
-    }
-
-    // Get font
-//    file = dmf_create_stdio("fnsmall.fnt", "rb");
-    file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont));
-    if (file == NULL)
-    {
-        dmError("Error opening font file 'pplfont.fnt'.\n");
-        goto error_exit;
-    }
-    result = dmLoadBitmapFont(file, &font);
-    dmf_close(file);
-    if (result != DMERR_OK)
-    {
-        dmError("Could not load font from file, %d: %s\n",
-            result, dmErrorStr(result));
-        goto error_exit;
-    }
-
-    // Initialize SDL components
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0)
-    {
-        dmError("Could not initialize SDL: %s\n", SDL_GetError());
-        goto error_exit;
-    }
-    initSDL = TRUE;
-
-
-    // Initialize mixing device
-    dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n",
-        optOutFormat, optOutChannels, optOutFreq);
-
-    engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO);
-    if (engine.dev == NULL)
-    {
-        dmError("jvmInit() returned NULL\n");
-        goto error_exit;
-    }
-    
-    switch (optOutFormat)
-    {
-        case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break;
-        case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break;
-        case JSS_AUDIO_S8:  engine.afmt.format = AUDIO_S8; break;
-        case JSS_AUDIO_U8:  engine.afmt.format = AUDIO_U8; break;
-        default:
-            dmError("Unsupported audio format %d (could not set matching SDL format)\n",
-                optOutFormat);
-            goto error_exit;
-    }
-
-    engine.afmt.freq     = optOutFreq;
-    engine.afmt.channels = optOutChannels;
-    engine.afmt.samples  = optOutFreq / 16;
-    engine.afmt.callback = audioCallback;
-    engine.afmt.userdata = (void *) engine.dev;
-
-    // Open the audio device
-    if (SDL_OpenAudio(&engine.afmt, NULL) < 0)
-    {
-        dmError("Couldn't open SDL audio: %s\n",
-            SDL_GetError());
-        goto error_exit;
-    }
-    audioInit = TRUE;
-    
-    // Initialize player
-    if ((engine.plr = jmpInit(engine.dev)) == NULL)
-    {
-        dmError("jmpInit() returned NULL\n");
-        goto error_exit;
-    }
-    
-    jvmSetCallback(engine.dev, jmpExec, engine.plr);
-    jmpSetModule(engine.plr, engine.mod);
-    jmpPlayOrder(engine.plr, optStartOrder);
-    jvmSetGlobalVol(engine.dev, 64);
-
-    if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels)
-    {
-        dmMuteChannels(TRUE);
-        jvmMute(engine.dev, optMuteOChannels, FALSE);
-        engine.actChannel = optMuteOChannels;
-        muteState = TRUE;
-    }
-
-    // Initialize video
-    if (!dmInitializeVideo())
-        goto error_exit;
-
-    SDL_WM_SetCaption(dmProgDesc, dmProgName);
-
-    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
-
-    // okay, main loop here ... "play" module and print out info
-    SDL_LockAudio();
-    SDL_PauseAudio(0);
-    SDL_UnlockAudio();
-
-    int currTick, prevTick = 0, prevRow = -1;
-    
-    while (!engine.exitFlag)
-    {
-        currTick = SDL_GetTicks();
-        BOOL force = (currTick - prevTick > 500), updated = FALSE;
-
-        while (SDL_PollEvent(&engine.event))
-        switch (engine.event.type)
-        {
-            case SDL_KEYDOWN:
-                switch (engine.event.key.keysym.sym)
-                {
-                    case SDLK_ESCAPE:
-                        engine.exitFlag = TRUE;
-                        break;
-                    
-                    case SDLK_SPACE:
-                        engine.pauseFlag = !engine.pauseFlag;
-                        SDL_PauseAudio(engine.pauseFlag);
-                        break;
-
-                    case SDLK_LEFT:
-                        if (engine.actChannel > 0)
-                        {
-                            engine.actChannel--;
-                            force = TRUE;
-                        }
-                        break;
-
-                    case SDLK_RIGHT:
-                        if (engine.actChannel < engine.mod->nchannels)
-                        {
-                            engine.actChannel++;
-                            force = TRUE;
-                        }
-                        break;
-
-                    case SDLK_m:
-                        if (engine.event.key.keysym.mod & KMOD_SHIFT)
-                        {
-                            muteState = !muteState;
-                            dmMuteChannels(muteState);
-                        }
-                        else
-                        if (engine.event.key.keysym.mod & KMOD_CTRL)
-                        {
-                            dmMuteChannels(FALSE);
-                        }
-                        else
-                        {
-                            jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel));
-                        }
-                        force = TRUE;
-                        break;
-
-                    case SDLK_PAGEUP:
-                        JSS_LOCK(engine.dev);
-                        JSS_LOCK(engine.plr);
-                        jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders));
-                        JSS_UNLOCK(engine.plr);
-                        JSS_UNLOCK(engine.dev);
-                        force = TRUE;
-                        break;
-
-                    case SDLK_PAGEDOWN:
-                        JSS_LOCK(engine.dev);
-                        JSS_LOCK(engine.plr);
-                        jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders));
-                        JSS_UNLOCK(engine.plr);
-                        JSS_UNLOCK(engine.dev);
-                        force = TRUE;
-                        break;
-
-                    case SDLK_f:
-                        engine.optVFlags ^= SDL_FULLSCREEN;
-                        if (!dmInitializeVideo())
-                            goto error_exit;
-                        force = TRUE;
-                        break;
-
-                    default:
-                        break;
-                }
-
-                break;
-
-            case SDL_VIDEORESIZE:
-                engine.optScrWidth = engine.event.resize.w;
-                engine.optScrHeight = engine.event.resize.h;
-
-                if (!dmInitializeVideo())
-                    goto error_exit;
-
-                break;
-
-            case SDL_VIDEOEXPOSE:
-                break;
-
-            case SDL_QUIT:
-                engine.exitFlag = TRUE;
-                break;
-        }
-
-
-#if 1
-        JSS_LOCK(engine.plr);
-        JSSPattern *currPattern = engine.plr->pattern;
-        int currRow = engine.plr->row;
-        if (!engine.plr->isPlaying)
-            engine.exitFlag = TRUE;
-        JSS_UNLOCK(engine.plr);
-        
-        if (currRow != prevRow || force)
-        {
-            prevRow = currRow;
-            force = TRUE;
-        }
-        
-        // Draw frame
-        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
-        {
-            dmError("Can't lock surface.\n");
-            goto error_exit;
-        }
-
-        if (force)
-        {
-            dmClearSurface(engine.screen, col.boxBg);
-            
-            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion);
-
-            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11,
-                "Song: '%s'",
-                engine.mod->moduleName);
-
-            dmDisplayPattern(engine.screen, 5, 40,
-                engine.screen->w - 6, engine.screen->h * 0.8,
-                currPattern, currRow);
-            
-            JSS_LOCK(engine.plr);
-            dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12,
-            "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d",
-            engine.plr->tempo, engine.plr->speed,
-            engine.plr->row, engine.plr->pattern->nrows,
-            engine.plr->order, engine.mod->norders,
-            engine.plr->npattern, engine.mod->npatterns);
-            JSS_UNLOCK(engine.plr);
-            updated = TRUE;
-        }
-
-        if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20))
-        {
-            JSS_LOCK(engine.dev);
-            dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5,
-                engine.screen->w - 5, engine.screen->h - 5, engine.dev);
-            JSS_UNLOCK(engine.dev);
-            updated = TRUE;
-        }
-
-        if (force)
-            prevTick = currTick;
-
-#endif
-        // Flip screen
-        if (SDL_MUSTLOCK(engine.screen) != 0)
-            SDL_UnlockSurface(engine.screen);
-
-        if (updated)
-            SDL_Flip(engine.screen);
-
-        SDL_Delay(engine.pauseFlag ? 100 : 30);
-    }
-
-error_exit:
-    if (engine.screen)
-        SDL_FreeSurface(engine.screen);
-
-    dmMsg(0, "Audio shutdown.\n");
-    if (audioInit)
-    {
-        SDL_LockAudio();
-        SDL_PauseAudio(1);
-        SDL_UnlockAudio();
-        SDL_CloseAudio();
-    }
-
-    jmpClose(engine.plr);
-    jvmClose(engine.dev);
-    jssFreeModule(engine.mod);
-
-    dmFreeBitmapFont(font);
-
-    if (initSDL)
-        SDL_Quit();
-
-    jssClose();
-
-    return 0;
-}
--- a/utils/svg2qd.py	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-#!/usr/bin/python
-import sys
-import re
-import xml.etree.ElementTree as ET
-
-
-def bf(x) :
-   return int(round(float(x)))
-
-
-def printVertex(v) :
-   if type(v) is list :
-      return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2])
-   else :
-      return v
-
-
-def getTransform(elem) :
-   if "transform" in elem.attrib :
-      ntrans = elem.attrib["transform"]
-      tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE)
-      for trns in tmatch.finditer(ntrans) :
-         coord = trns.group(1).split(",")
-         return [float(coord[0]), float(coord[1]), 0]
-   return None
-
-
-def getStyle(elem) :
-   style = {}
-   if "style" in elem.attrib :
-      for elem in elem.attrib["style"].split(";") :
-         kv = elem.split(":")
-         style[kv[0]] = kv[1]
-   return style
-
-
-def printVertices(type, vertices, width, level) :
-   if len(vertices) > 0 :
-      list = map(lambda v:printVertex(v), vertices)
-      str = "# "+ type
-      if type == "m" :
-         str = "R"
-      elif type == "M" :
-         str = "L"
-      elif type == "c" :
-         str = "R"
-      print "{}{}{} {} {}".format("  "*level, str, len(vertices)-1, " ".join(list), width)
-
-
-def printPath(path, level) :
-   style = getStyle(path)
-   width = bf(style["stroke-width"])
-
-   trans = getTransform(path)
-   if trans :
-      print "{}G{}".format("  "*level, printVertex(trans))
-
-   vertices = []
-   type = ""
-   for elem in path.attrib["d"].split(" ") :
-      if elem == "m" or elem == "M" :
-         printVertices(type, vertices, width, level)
-         vertices = []
-         type = elem
-      elif elem == "z" :
-         vertices.append("Z")
-      elif elem == "c" or elem == "C" :
-         print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"])
-         sys.exit(0)
-      else :
-         tmp = elem.split(",")
-         px = float(tmp[0])
-         py = float(tmp[1])
-         vertices.append([px, py, 0])
-
-   printVertices(type, vertices, width, level)
-   if trans :
-      print "{}E\n".format("  "*level)
-
-
-def iterateDocument(elems, level) :
-   for elem in elems:
-      if elem.tag == "{http://www.w3.org/2000/svg}g" :
-         print "\n{}# GROUP".format("  "*level)
-         tmp = getTransform(elem)
-         if tmp :
-            print "{}G{}".format("  "*level, printVertex(getTransform(elem)))
-            iterateDocument(elem, level + 1)
-            print "{}E\n".format("  "*level)
-         else :
-            iterateDocument(elem, level)
-      elif elem.tag == "{http://www.w3.org/2000/svg}path" :
-         printPath(elem, level)
-
-
-# Ns. paaohjelma
-if len(sys.argv) != 2 :
-   print "Usage: "+sys.argv[0]+" <input.svg>"
-   sys.exit(1)
-   
-tree = ET.parse(sys.argv[1])
-iterateDocument(tree.getroot(), 0)
--- a/utils/view64.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/*
- * view64 - Display some C64 etc graphics formats via libSDL
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmfile.h"
-#include "lib64gfx.h"
-#include <SDL.h>
-
-
-char * optFilename = NULL;
-int    optVFlags = SDL_SWSURFACE | SDL_HWPALETTE;
-int    optScrWidth, optScrHeight;
-int    optForcedFormat = -1;
-
-
-static DMOptArg optList[] =
-{
-    { 0, '?', "help",       "Show this help", OPT_NONE },
-    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
-    { 2,   0, "fs",         "Fullscreen", OPT_NONE },
-    { 3, 'S', "scale",      "Scale image by factor (1-10)", OPT_ARGREQ },
-    { 4, 'f', "format",     "Force input format (see list below)", OPT_ARGREQ },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void dmSetScaleFactor(float factor)
-{
-    optScrWidth = (int) ((float) C64_SCR_WIDTH * factor * C64_SCR_PAR_XY);
-    optScrHeight = (int) ((float) C64_SCR_HEIGHT * factor);
-}
-
-
-void argShowHelp()
-{
-    int i;
-
-    dmPrintBanner(stdout, dmProgName, "[options] <input image file>");
-    dmArgsPrintHelp(stdout, optList, optListN);
-
-    printf("\nAvailable bitmap formats:\n");
-    for (i = 0; i < ndmC64ImageFormats; i++)
-    {
-        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
-        char buf[64];
-        printf("%3d | %-5s | %-15s | %s\n",
-            i, fmt->fext,
-            dmC64GetImageTypeString(buf, sizeof(buf), fmt->type),
-            fmt->name);
-    }
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            dmVerbosity++;
-            break;
-        
-        case 2:
-            optVFlags |= SDL_FULLSCREEN;
-            break;
-
-        case 3:
-            {
-                float factor;
-                if (sscanf(optArg, "%f", &factor) == 1)
-                {
-                    if (factor < 1 || factor >= 10)
-                    {
-                        dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor);
-                        return FALSE;
-                    }
-
-                    dmSetScaleFactor(factor);
-                }
-                else
-                {
-                    dmError("Invalid scale factor '%s'.\n", optArg);
-                    return FALSE;
-                }
-            }
-            break;
-
-        case 4:
-            {
-                int i;
-                if (sscanf(optArg, "%d", &i) == 1)
-                {
-                    if (i < 0 || i >= ndmC64ImageFormats)
-                    {
-                        dmError("Invalid image format index %d, see help for valid values.\n", i);
-                        return FALSE;
-                    }
-                    optForcedFormat = i;
-                }
-                else
-                {
-                    dmError("Invalid image format argument '%s'.\n", optArg);
-                    return FALSE;
-                }
-            }
-            break;
-        
-        default:
-            dmError("Unknown option '%s'.\n", currArg);
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *filename)
-{
-    if (optFilename == NULL)
-    {
-        optFilename = dm_strdup(filename);
-        return TRUE;
-    }
-    else
-    {
-        dmError("Too many filenames specified ('%s')\n", filename);
-        return FALSE;
-    }
-}
-
-
-BOOL dmInitializeVideo(SDL_Surface **screen)
-{
-    *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
-    if (*screen == NULL)
-    {
-        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
-        return FALSE;
-    }
-    return TRUE;
-}
-
-
-int main(int argc, char *argv[])
-{
-    SDL_Surface *screen = NULL, *surf = NULL;
-    DMImage bmap;
-    BOOL initSDL = FALSE, exitFlag, needRedraw;
-    const DMC64ImageFormat *fmt = NULL, *forced;
-    DMC64Image image;
-    char *windowTitle;
-    Uint8 *dataBuf = NULL;
-    size_t dataSize;
-    int ret;
-
-    dmSetScaleFactor(2.0);
-    
-    dmInitProg("view64", "Display some C64 bitmap graphics formats", "0.2", NULL, NULL);
-
-    /* Parse arguments */
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, FALSE))
-        exit(1);
-
-
-    if (optFilename == NULL)
-    {
-        dmError("No input file specified, perhaps you need some --help\n");
-        goto error;
-    }
-        
-    if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK)
-        goto error;
-
-    dmMsg(1, "Read %d bytes of input.\n", dataSize);
-
-    // Probe for format
-    if (optForcedFormat >= 0)
-    {
-        forced = &dmC64ImageFormats[optForcedFormat];
-        dmMsg(0,"Forced %s format image, type %d, %s\n",
-            forced->name, forced->type, forced->fext);
-    }
-    else
-        forced = NULL;
-
-    ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced);
-    if (forced == NULL && fmt != NULL)
-    {
-        dmMsg(0,"Probed %s format image, type %d, %s\n",
-            fmt->name, fmt->type, fmt->fext);
-    }
-
-    if (ret < 0)
-    {
-        dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret);
-        return -1;
-    }
-
-
-    // Initialize libSDL
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
-    {
-        dmError("Could not initialize SDL: %s\n", SDL_GetError());
-        goto error;
-    }
-    initSDL = TRUE;
-
-
-    // Open window/set video mode
-    screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
-    if (screen == NULL)
-    {
-        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
-        goto error;
-    }
-
-    // Create surface (we are lazy and ugly)
-    surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_HEIGHT, 8, 0, 0, 0, 0);
-    SDL_SetColors(surf, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
-    SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
-
-    // Convert bitmap (this is a bit ugly and lazy here)
-    bmap.data = surf->pixels;
-    bmap.pitch = surf->pitch;
-    bmap.width = surf->w;
-    bmap.height = surf->h;
-    bmap.constpal = TRUE;
-
-    if (fmt->convertFrom != NULL)
-        ret = fmt->convertFrom(&bmap, &image, TRUE);
-    else
-        ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE);
-
-
-    // Set window title and caption
-    windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename);
-    SDL_WM_SetCaption(windowTitle, dmProgName);
-    dmFree(windowTitle);
-
-
-    // Start main loop
-    needRedraw = TRUE;
-    exitFlag = FALSE;
-    while (!exitFlag)
-    {
-        SDL_Event event;
-        while (SDL_PollEvent(&event))
-        switch (event.type)
-        {
-            case SDL_KEYDOWN:
-                switch (event.key.keysym.sym)
-                {
-                    case SDLK_ESCAPE: exitFlag = TRUE; break;
-                    
-                    default:
-                        break;
-                }
-
-                needRedraw = TRUE;
-                break;
-            
-            case SDL_VIDEORESIZE:
-                optScrWidth = event.resize.w;
-                optScrHeight = event.resize.h;
-
-                if (!dmInitializeVideo(&screen))
-                    goto error;
-
-                needRedraw = TRUE;
-                break;
-            
-            case SDL_VIDEOEXPOSE:
-                needRedraw = TRUE;
-                break;
-
-            case SDL_QUIT:
-                exit(0);
-        }
-        
-        if (needRedraw)
-        {
-            if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0)
-            {
-                dmError("Can't lock surface.\n");
-                goto error;
-            }
-            
-            dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, screen);
-            SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
-
-            if (SDL_MUSTLOCK(screen) != 0)
-                SDL_UnlockSurface(screen);
-
-            SDL_Flip(screen);
-            needRedraw = FALSE;
-        }
-        
-        SDL_Delay(100);
-    }
-
-
-error:
-    if (screen)
-        SDL_FreeSurface(screen);
-
-    if (initSDL)
-        SDL_Quit();
-
-    return 0;
-}
--- a/utils/viewmod.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,475 +0,0 @@
-/*
- * viewmod - View information about given module file
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2006-2007 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include "jss.h"
-#include "jssmod.h"
-#include <errno.h>
-#include <string.h>
-#include "dmargs.h"
-#include "dmmutex.h"
-
-
-char    *optFilename = NULL;
-BOOL    optViewPatterns = FALSE,
-        optViewInstruments = FALSE,
-        optViewExtInstruments = FALSE,
-        optViewGeneralInfo = FALSE;
-
-
-DMOptArg optList[] =
-{
-    { 0, '?', "help", "Show this help and exit", OPT_NONE },
-    { 1, 'p', "patterns", "View patterns", OPT_NONE },
-    { 2, 'i', "instruments", "View instruments", OPT_NONE },
-    { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE },
-    { 3, 'g', "general", "General information", OPT_NONE },
-    { 4, 'v', "verbose", "Be more verbose", OPT_NONE },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName, "[options] [modfile]");
-    dmArgsPrintHelp(stdout, optList, optListN);
-}
-
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    (void) optArg;
-    
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            optViewPatterns = TRUE;
-            break;
-
-        case 2:
-            optViewInstruments = TRUE;
-            break;
-
-        case 3:
-            optViewGeneralInfo = TRUE;
-            break;
-
-        case 4:
-            dmVerbosity++;
-            break;
-
-        case 5:
-            optViewExtInstruments = TRUE;
-            break;
-
-        default:
-            dmError("Unknown argument '%s'.\n", currArg);
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    // Was not option argument
-    if (!optFilename)
-        optFilename = currArg;
-    else {
-        dmError("Gay error '%s'!\n", currArg);
-        return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-const char patNoteTable[12][3] =
-{
-    "C-", "C#", "D-",
-    "D#", "E-", "F-",
-    "F#", "G-", "G#",
-    "A-", "A#", "B-"
-};
-
-#define    jmpNMODEffectTable (36)
-static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-
-/* Print a given pattern
- */
-void printPattern(FILE *f, JSSPattern *p)
-{
-    int i, j;
-    char c;
-    JSSNote *n;
-
-    if (!p)
-        return;
-
-    n = p->data;
-
-    for (i = 0; i < p->nrows; i++)
-    {
-        fprintf(f, "%.2x: ", i);
-
-        for (j = 0; j < p->nchannels; j++)
-        {
-            switch (n->note)
-            {
-            case jsetNotSet:
-                fprintf(f, "... ");
-                break;
-            case jsetNoteOff:
-                fprintf(f, "=== ");
-                break;
-            default:
-                fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12);
-                break;
-            }
-
-            if (n->instrument != jsetNotSet)
-                fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally
-            else
-                fprintf(f, ".. ");
-            
-            if (n->volume == jsetNotSet)
-                fprintf(f, ".. ");
-            else if (n->volume >= 0x00 && n->volume <= 0x40)
-                fprintf(f, "%.2x ", n->volume);
-            else
-            {
-                switch (n->volume & 0xf0)
-                {
-                    case 0x50: c = '-'; break;
-                    case 0x60: c = '+'; break;
-                    case 0x70: c = '/'; break;
-                    case 0x80: c = '\\'; break;
-                    case 0x90: c = 'S'; break;
-                    case 0xa0: c = 'V'; break;
-                    case 0xb0: c = 'P'; break;
-                    case 0xc0: c = '<'; break;
-                    case 0xd0: c = '>'; break;
-                    case 0xe0: c = 'M'; break;
-                    default:   c = '?'; break;
-                }
-                fprintf(f, "%c%x ", c, (n->volume & 0x0f));
-            }
-            
-            if (n->effect >= 0 && n->effect < jmpNMODEffectTable)
-                fprintf(f, "%c", jmpMODEffectTable[n->effect]);
-            else if (n->effect == jsetNotSet)
-                fprintf(f, ".");
-            else
-                fprintf(f, "?");
-
-            if (n->param != jsetNotSet)
-                fprintf(f, "%.2x|", n->param);
-            else
-                fprintf(f, "..|");
-
-            n++;
-        }
-
-        fprintf(f, "\n");
-    }
-}
-
-
-/*
- * Print given extended instrument
- */
-void printEnvelope(FILE *f, JSSEnvelope *e, char *s)
-{
-    int i;
-
-    fprintf(f,
-        "\t%s-envelope:\n"
-        "\t - flags.....: %.4x", s, e->flags);
-
-    if (e->flags & jenvfUsed)
-        fprintf(f, " [used]");
-    if (e->flags & jenvfSustain)
-        fprintf(f, " [sust]");
-    if (e->flags & jenvfLooped)
-        fprintf(f, " [loop]");
-
-    fprintf(f, "\n"
-        "\t - npoints...: %i\n"
-        "\t - sustain...: %i\n"
-        "\t - loopS.....: %i\n"
-        "\t - loopE.....: %i\n",
-        e->npoints, e->sustain, e->loopS, e->loopE);
-
-    if (dmVerbosity >= 2)
-    {
-        fprintf(f, "\t - Points....:");
-        for (i = 0; i < e->npoints; i++)
-        {
-            fprintf(f, " [%i:%i]",
-            e->points[i].frame, e->points[i].value);
-        }
-
-        fprintf(f, "\n");
-    }
-}
-
-
-void printExtInstrument(FILE *f, JSSExtInstrument *i)
-{
-    if (!i)
-    {
-        fprintf(f, "\n");
-        return;
-    }
-
-#ifndef JSS_LIGHT
-    if (i->desc)
-        fprintf(f,
-        "Description: '%s'\n", i->desc);
-#endif
-    fprintf(f,
-        "nsamples.......: %i\n"
-        "vibratoType....: %i\n"
-        "vibratoSweep...: %i\n"
-        "vibratoDepth...: %i\n"
-        "vibratoRate....: %i\n"
-        "fadeOut........: %i\n",
-        i->nsamples, i->vibratoType, i->vibratoSweep,
-        i->vibratoDepth, i->vibratoRate, i->fadeOut);
-
-    if (dmVerbosity >= 1)
-    {
-        printEnvelope(f, &i->volumeEnv, "Volume");
-        printEnvelope(f, &i->panningEnv, "Panning");
-    }
-    fprintf(f, "\n");
-}
-
-
-void printInstrument(FILE *f, JSSInstrument *i)
-{
-    if (!i)
-    {
-        fprintf(f, "\n");
-        return;
-    }
-
-    if (dmVerbosity >= 1)
-    {
-#ifndef JSS_LIGHT
-        if (i->desc)
-            fprintf(f, "Description: '%s'\n", i->desc);
-#endif
-        fprintf(f,
-            "size...........: %ld (0x%lx)\n"
-            "loopStart......: %ld (0x%lx)\n"
-            "loopEnd........: %ld (0x%lx)\n"
-            "volume.........: %d (0x%x)\n"
-            "flags..........: 0x%x ",
-            (unsigned long) i->size, (unsigned long) i->size,
-            (unsigned long) i->loopS, (unsigned long) i->loopE,
-            (unsigned long) i->loopS, (unsigned long) i->loopE,
-            i->volume, i->volume,
-            i->flags);
-        
-        if (i->flags & jsfLooped)  fprintf(f, "[loop] ");
-        if (i->flags & jsfBiDi)    fprintf(f, "[bi-di] ");
-        if (i->flags & jsf16bit)   fprintf(f, "[16bit] ");
-        
-        fprintf(f,
-            "\nC4BaseSpeed....: %d (0x%x)\n"
-            "ERelNote.......: %d (%s%d)\n"
-            "EFineTune......: %d\n"
-            "EPanning,,,....: %d (0x%x)\n\n",
-            i->C4BaseSpeed, i->C4BaseSpeed,
-            i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12,
-            i->EFineTune, i->EPanning, i->EPanning);
-    }
-    else
-    {
-#ifndef JSS_LIGHT
-        if (i->desc)
-            fprintf(f, "'%s', ", i->desc);
-#endif
-        fprintf(f,
-        "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n",
-        (unsigned long) i->size, (unsigned long) i->size,
-        (unsigned long) i->loopS, (unsigned long) i->loopE,
-        (unsigned long) i->loopS, (unsigned long) i->loopE,
-        i->volume, i->volume, i->flags, i->C4BaseSpeed,
-        i->C4BaseSpeed, i->ERelNote,
-        patNoteTable[(48 + i->ERelNote) % 12],
-        (48 + i->ERelNote) / 12, i->EFineTune,
-        i->EPanning, i->EPanning);
-    }
-}
-
-
-void printGeneralInfo(FILE *f, JSSModule *m)
-{
-    int i;
-    
-    if (!m)
-        return;
-
-    fprintf(f, "Module type.....: %i\n", m->moduleType);
-#ifndef JSS_LIGHT
-    if (m->moduleName)
-        fprintf(f, "Module name.....: '%s'\n", m->moduleName);
-    if (m->trackerName)
-        fprintf(f, "Tracker name....: '%s'\n", m->trackerName);
-#endif
-    fprintf(f,
-        "Speed...........: %d ticks\n"
-        "Tempo...........: %d bpm\n"
-        "Flags...........: %x ",
-        m->defSpeed, m->defTempo, m->defFlags);
-    
-    if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] ");
-    if (m->defFlags & jmdfAmigaLimits)  fprintf(f, "[Amiga limits] ");
-    if (m->defFlags & jmdfStereo)       fprintf(f, "[stereo] ");
-    if (m->defFlags & jmdfFT2Replay)    fprintf(f, "[FT2 replay] ");
-    if (m->defFlags & jmdfST300Slides)  fprintf(f, "[ST300 slides] ");
-    if (m->defFlags & jmdfByteLStart)   fprintf(f, "[ByteStart] ");
-    
-    fprintf(f, "\n"
-        "Restart pos.....: %d (order)\n"
-        "IntVersion......: %x\n"
-        "Channels........: %d\n"
-        "Instruments.....: %d\n"
-        "Ext.instruments.: %d\n"
-        "Patterns........: %d\n"
-        "Orders..........: %d\n",
-        m->defRestartPos, m->intVersion, m->nchannels,
-        m->ninstruments, m->nextInstruments, m->npatterns,
-        m->norders);
-
-    if (dmVerbosity >= 1)
-    {
-        fprintf(f, "Orderlist: ");
-        for (i = 0; i < m->norders - 1; i++)
-            fprintf(f, "%d, ", m->orderList[i]);
-        if (i < m->norders)
-            fprintf(f, "%d", m->orderList[i]);
-        fprintf(f, "\n");
-    }
-}
-
-
-
-int main(int argc, char *argv[])
-{
-    int result = -1, i;
-    DMResource *file;
-    JSSModule *mod;
-
-    dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL);
-    dmVerbosity = 0;
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    // Initialize miniJSS
-    jssInit();
-
-    // Open the file
-    dmMsg(1, "Reading module file '%s'\n", optFilename);
-    if (optFilename == NULL)
-        file = dmf_create_stdio_stream(stdin);
-    else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL)
-    {
-        dmError("Error opening input file '%s'. (%s)\n",
-            optFilename, strerror(errno));
-        return 1;
-    }
-
-    // Read module file
-    dmMsg(1, "Reading file: %s\n", optFilename);
-#ifdef JSS_SUP_XM
-    dmMsg(1, "* Trying XM...\n");
-    result = jssLoadXM(file, &mod);
-#endif
-#ifdef JSS_SUP_JSSMOD
-    if (result != 0)
-    {
-        size_t bufgot, bufsize = dmfsize(file);
-        Uint8 *buf = dmMalloc(bufsize);
-        dmfseek(file, 0L, SEEK_SET);
-        dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
-        if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize)
-        {
-            dmError("Error reading file (not enough data %d), #%d: %s\n",
-                bufgot, dmferror(file), dmErrorStr(dmferror(file)));
-            return 2;
-        }
-        result = jssLoadJSSMOD(buf, bufsize, &mod);
-        dmFree(buf);
-    }
-#endif
-    dmf_close(file);
-    if (result != DMERR_OK)
-    {
-        dmError("Error loading module file, %d: %s\n",
-            result, dmErrorStr(result));
-        return 3;
-    }
-
-    // Print out information
-    if (optViewGeneralInfo)
-        printGeneralInfo(stdout, mod);
-
-    if (optViewPatterns)
-    {
-        for (i = 0; i < mod->npatterns; i++)
-        {
-            printf("\nPattern #%03i:\n", i);
-            printPattern(stdout, mod->patterns[i]);
-        }
-    }
-
-    if (optViewExtInstruments)
-    {
-        printf("\n"
-        "ExtInstruments:\n"
-        "---------------\n"
-        );
-        for (i = 0; i < mod->nextInstruments; i++)
-        {
-            printf("#%03i: ", i + 1);
-            printExtInstrument(stdout, mod->extInstruments[i]);
-        }
-    }
-
-    if (optViewInstruments)
-    {
-        printf("\n"
-        "Instruments:\n"
-        "------------\n"
-        );
-        for (i = 0; i < mod->ninstruments; i++)
-        {
-            printf("#%03i: ", i + 1);
-            printInstrument(stdout, mod->instruments[i]);
-        }
-    }
-
-    // Free module data
-    jssFreeModule(mod);
-    jssClose();
-
-    exit(0);
-    return 0;
-}
--- a/utils/xm2jss.c	Tue Apr 16 06:01:42 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1040 +0,0 @@
-/*
- * xm2jss - Convert XM module to JSSMOD
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2006-2009 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include <stdio.h>
-#include <errno.h>
-#include "jss.h"
-#include "jssmod.h"
-#include "jssplr.h"
-#include "dmlib.h"
-#include "dmargs.h"
-#include "dmres.h"
-#include "dmmutex.h"
-
-
-#define jmpNMODEffectTable (36)
-static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-
-char  *optInFilename = NULL, *optOutFilename = NULL;
-BOOL  optIgnoreErrors = FALSE,
-      optStripExtInstr = FALSE,
-      optStripInstr = FALSE,
-      optStripSamples = FALSE,
-      optOptimize = FALSE;
-
-int   optPatternMode = PATMODE_COMP_HORIZ,
-      optSampMode16 = jsampDelta,
-      optSampMode8 = jsampFlipSign | jsampDelta;
-
-#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta)
-
-
-static const char* patModeTable[PATMODE_LAST] =
-{
-    "Raw horizontal",
-    "Compressed horizontal (similar to XM modules)",
-    "Raw vertical",
-    "Compressed vertical",
-    "Raw vertical for each element",
-};
-
-
-DMOptArg optList[] = {
-    { 0, '?', "help",           "Show this help", OPT_NONE },
-    { 1, 'v', "verbose",        "Be more verbose", OPT_NONE },
-    { 2, 'i', "ignore",         "Ignore errors", OPT_NONE },
-    { 3, 'p', "patterns",       "Pattern storage mode", OPT_ARGREQ },
-    { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE },
-    { 5, 'I', "strip-instr",    "Strip instruments (implies -S)", OPT_NONE },
-    { 6, 'S', "strip-samples",  "Strip instr. sampledata", OPT_NONE },
-    { 7, '8', "smode8",         "8-bit sample conversion flags", OPT_ARGREQ },
-    { 8, '1', "smode16",        "16-bit sample conversion flags", OPT_ARGREQ },
-    { 9, 'O', "optimize",       "Optimize module", OPT_NONE },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-void argShowHelp()
-{
-    int i;
-
-    dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>");
-    dmArgsPrintHelp(stdout, optList, optListN);
-
-    printf("\n"
-    "Pattern storage modes:\n");
-    
-    for (i = 1; i < PATMODE_LAST; i++)
-        printf("  %d = %s\n", i, patModeTable[i-1]);
-    
-    printf(
-    "\n"
-    "Sample data conversion flags (summative):\n"
-    "  1 = Delta encoding (DEF 8 & 16)\n"
-    "  2 = Flip signedness (DEF 8)\n"
-    "  4 = Swap endianess (affects 16-bit only)\n"
-    "  8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n"
-    "\n"
-    );
-}
-
-BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    (void) optArg;
-    
-    switch (optN)
-    {
-    case 0:
-        argShowHelp();
-        exit(0);
-        break;
-
-    case 1:
-        dmVerbosity++;
-        break;
-
-    case 2:
-        optIgnoreErrors = TRUE;
-        break;
-
-    case 3:
-        optPatternMode = atoi(optArg);
-        if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST)
-        {
-            dmError("Unknown pattern conversion mode %d\n", optPatternMode);
-            return FALSE;
-        }
-        break;
-
-    case 4: optStripExtInstr = TRUE; break;
-    case 5: optStripInstr = TRUE; break;
-    case 6: optStripSamples = TRUE; break;
-
-    case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break;
-    case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break;
-
-    case 9: optOptimize = TRUE; break;
-
-    default:
-        dmError("Unknown argument '%s'.\n", currArg);
-        return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-BOOL argHandleFile(char *currArg)
-{
-    // Was not option argument
-    if (!optInFilename)
-        optInFilename = currArg;
-    else
-    if (!optOutFilename)
-        optOutFilename = currArg;
-    else
-    {
-        dmError("Too many filename arguments specified, '%s'.\n", currArg);
-        return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-/* These functions and the macro mess are meant to make the
- * conversion routines themselves clearer and simpler.
- */
-BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val)
-{
-    if (*npatBuf >= patBufSize)
-        return FALSE;
-    else
-    {
-        patBuf[*npatBuf] = val;
-        (*npatBuf)++;
-        return TRUE;
-    }
-}
-
-#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0)
-
-#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0)
-
-#define JSCOMPPUT(xf,xv,qv)  do {                       \
-    if (qflags & (xf)) {                                \
-        if ((xv) < 0 || (xv) > 255)                     \
-            JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,        \
-            "%s value out of bounds %d.\n", qv, (xv));  \
-        JSPUTBYTE(xv);                                  \
-    }                                                   \
-} while (0)
-
-#define JSCONVPUT(xv,qv)    do {                        \
-    if ((xv) != jsetNotSet) {                           \
-        if ((xv) < 0 || (xv) > 254)                     \
-            JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,        \
-            "%s value out of bounds %d.\n", qv, (xv));  \
-        JSPUTBYTE((xv) + 1);                            \
-    } else {                                            \
-        JSPUTBYTE(0);                                   \
-    }                                                   \
-} while (0)
-
-
-/* Convert a note
- */
-static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note)
-{
-    Uint8 tmp;
-    if (note->note == jsetNotSet)
-        tmp = 0;
-    else if (note->note == jsetNoteOff)
-        tmp = 127;
-    else
-        tmp = note->note + 1;
-
-    if (tmp > 0x7f)
-        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
-
-    JSPUTBYTE(tmp & 0x7f);
-    
-    JSCONVPUT(note->instrument, "Instrument");
-    JSCONVPUT(note->volume, "Volume");
-    JSCONVPUT(note->effect, "Effect");
-    
-    tmp = (note->param != jsetNotSet) ? note->param : 0;
-    JSPUTBYTE(tmp);
-    
-    return DMERR_OK;
-}
-
-
-/* Compress a note
- */
-static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note)
-{
-    Uint8 qflags = 0;
-    int qcomp = 0;
-    
-    JSCOMP(note->note,       COMP_NOTE);
-    JSCOMP(note->instrument, COMP_INSTRUMENT);
-    JSCOMP(note->volume,     COMP_VOLUME);
-    JSCOMP(note->effect,     COMP_EFFECT);
-    if (note->param != jsetNotSet && note->param != 0)
-    {
-        qflags |= COMP_PARAM;
-        qcomp++;
-    }
-    
-    if (qcomp < 4)
-    {
-        JSPUTBYTE(qflags | 0x80);
-        
-        if (note->note != jsetNotSet)
-        {
-            Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127;
-            if (tmp > 0x7f)
-                JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
-            JSPUTBYTE(tmp);
-        }
-        
-        JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument");
-        JSCOMPPUT(COMP_VOLUME, note->volume, "Volume");
-        JSCOMPPUT(COMP_EFFECT, note->effect, "Effect");
-        JSCOMPPUT(COMP_PARAM, note->param, "Param");
-    } else
-        return jssConvertNote(patBuf, patBufSize, patSize, note);
-    
-    return DMERR_OK;
-}
-
-
-/* Compress pattern
- */
-static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
-{
-    int row, channel;
-    *patSize = 0;
-    
-    for (row = 0; row < pattern->nrows; row++)
-    for (channel = 0; channel < pattern->nchannels; channel++)
-    {
-        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
-        const int res = jssCompressNote(patBuf, patBufSize, patSize, note);
-        if (res != DMERR_OK)
-        {
-            JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
-            patBuf, patBufSize, *patSize, row, channel);
-            return res;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
-{
-    int row, channel;
-    *patSize = 0;
-    
-    for (channel = 0; channel < pattern->nchannels; channel++)
-    for (row = 0; row < pattern->nrows; row++)
-    {
-        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
-        const int res = jssCompressNote(patBuf, patBufSize, patSize, note);
-        if (res != DMERR_OK)
-        {
-            JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
-            patBuf, patBufSize, *patSize, row, channel);
-            return res;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-/* Convert a pattern
- */
-static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
-{
-    int row, channel;
-    *patSize = 0;
-    
-    for (row = 0; row < pattern->nrows; row++)
-    for (channel = 0; channel < pattern->nchannels; channel++)
-    {
-        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
-        const int res = jssConvertNote(patBuf, patBufSize, patSize, note);
-        if (res != DMERR_OK)
-        {
-            JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
-            patBuf, patBufSize, *patSize, row, channel);
-            return res;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
-{
-    int row, channel;
-    *patSize = 0;
-    
-    for (channel = 0; channel < pattern->nchannels; channel++)
-    for (row = 0; row < pattern->nrows; row++)
-    {
-        const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
-        const int res = jssConvertNote(patBuf, patBufSize, patSize, note);
-        if (res != DMERR_OK)
-        {
-            JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n",
-            patBuf, patBufSize, *patSize, row, channel);
-            return res;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-#define JSFOREACHNOTE1                                                              \
-  for (channel = 0; channel < pattern->nchannels; channel++)                        \
-  for (row = 0; row < pattern->nrows; row++) {                                      \
-  const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel];
-
-#define JSFOREACHNOTE2 }
-
-static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern)
-{
-    Uint8 tmp;
-    int row, channel;
-    *patSize = 0;
-    
-    JSFOREACHNOTE1;
-    if (note->note == jsetNotSet)
-        tmp = 0;
-    else if (note->note == jsetNoteOff)
-        tmp = 127;
-    else
-        tmp = note->note + 1;
-    if (tmp > 0x7f)
-        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp);
-    JSPUTBYTE(tmp);
-    JSFOREACHNOTE2;
-    
-    JSFOREACHNOTE1;
-    JSCONVPUT(note->instrument, "Instrument");
-    JSFOREACHNOTE2;
-    
-    JSFOREACHNOTE1;
-    JSCONVPUT(note->volume, "Volume");
-    JSFOREACHNOTE2;
-    
-    JSFOREACHNOTE1;
-    JSCONVPUT(note->effect, "Effect");
-    JSFOREACHNOTE2;
-    
-    JSFOREACHNOTE1;
-    tmp = (note->param != jsetNotSet) ? note->param : 0;
-    JSPUTBYTE(tmp);
-    JSFOREACHNOTE2;
-    
-    return DMERR_OK;
-}
-
-#undef JSFOREACHNOTE1
-#undef JSFOREACHNOTE2
-
-
-static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e)
-{
-    int i;
-    
-    je->flags   = e->flags;
-    je->npoints = e->npoints;
-    je->sustain = e->sustain;
-    je->loopS   = e->loopS;
-    je->loopE   = e->loopE;
-    
-    for (i = 0; i < e->npoints; i++)
-    {
-        je->points[i].frame = e->points[i].frame;
-        je->points[i].value = e->points[i].value;
-    }
-}
-
-
-/* Save a JSSMOD file
- */
-int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16)
-{
-    JSSMODHeader jssH;
-    int i, pattern, order, instr, totalSize;
-    const size_t patBufSize = 64*1024; // 64kB pattern buffer
-    Uint8 *patBuf;
-
-    // Check the module
-    if (m == NULL)
-        JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n");
-
-    if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1))
-        JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS,
-        "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n",
-        m->nchannels, m->npatterns, m->norders);
-
-    // Create the JSSMOD header
-    jssH.idMagic[0]         = 'J';
-    jssH.idMagic[1]         = 'M';
-    jssH.idVersion          = JSSMOD_VERSION;
-    jssH.norders            = m->norders;
-    jssH.npatterns          = m->npatterns;
-    jssH.nchannels          = m->nchannels;
-    jssH.nextInstruments    = m->nextInstruments;
-    jssH.ninstruments       = m->ninstruments;
-    jssH.defFlags           = m->defFlags;
-    jssH.intVersion         = m->intVersion;
-    jssH.defRestartPos      = m->defRestartPos;
-    jssH.defSpeed           = m->defSpeed;
-    jssH.defTempo           = m->defTempo;
-    jssH.patMode            = patMode;
-    
-    // Write header
-    totalSize = sizeof(jssH);
-    if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1)
-        JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n");
-
-    dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize);
-
-    // Write orders list
-    for (totalSize = order = 0; order < m->norders; order++)
-    {
-        Uint16 tmp = m->orderList[order];
-        totalSize += sizeof(tmp);
-        if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1)
-            JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n");
-    }
-
-    dmMsg(1," * %d item orders list, %d bytes.\n",
-        m->norders, totalSize);
-
-    // Allocate pattern compression buffer
-    if ((patBuf = dmMalloc(patBufSize)) == NULL)
-        JSSERROR(DMERR_MALLOC, DMERR_MALLOC,
-        "Error allocating memory for pattern compression buffer.\n");
-
-    
-    // Write patterns
-    for (totalSize = pattern = 0; pattern < m->npatterns; pattern++)
-    {
-        JSSMODPattern patHead;
-        size_t finalSize = 0;
-        
-        switch (patMode)
-        {
-            case PATMODE_RAW_HORIZ:
-                i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
-                break;
-            case PATMODE_COMP_HORIZ:
-                i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
-                break;
-            case PATMODE_RAW_VERT:
-                i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
-                break;
-            case PATMODE_COMP_VERT:
-                i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
-                break;
-            case PATMODE_RAW_ELEM:
-                i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]);
-                break;
-            default:
-                i = DMERR_INVALID_DATA;
-                dmFree(patBuf);
-                JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA,
-                "Unsupported pattern conversion mode %d.\n", patMode);
-                break;
-        }
-
-        if (i != DMERR_OK)
-        {
-            dmFree(patBuf);
-            JSSERROR(i, i, "Error converting pattern data #%i\n", pattern);
-        }
-        else
-        {
-            dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize);
-            patHead.nrows = m->patterns[pattern]->nrows;
-            patHead.size = finalSize;
-            totalSize += finalSize + sizeof(patHead);
-
-            if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1)
-            {
-                dmFree(patBuf);
-                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
-                "Error writing pattern #%d header\n", pattern);
-            }
-
-            if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize)
-            {
-                dmFree(patBuf);
-                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
-                "Error writing pattern #%d data\n", pattern);
-            }
-        }
-    }
-    dmFree(patBuf);
-    dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize);
-
-    // Write extended instruments
-    for (totalSize = instr = 0; instr < m->nextInstruments; instr++)
-    {
-        JSSMODExtInstrument jssE;
-        JSSExtInstrument *einst = m->extInstruments[instr];
-        
-        memset(&jssE, 0, sizeof(jssE));
-
-        if (einst)
-        {
-            // Create header
-            jssE.nsamples = einst->nsamples;
-            for (i = 0; i < jsetNNotes; i++)
-            {
-                int snum = einst->sNumForNotes[i];
-                jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0;
-            }
-            
-            jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv));
-            jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv));
-            jssE.vibratoType  = einst->vibratoType;
-            jssE.vibratoSweep = einst->vibratoSweep;
-            jssE.vibratoDepth = einst->vibratoDepth;
-            jssE.fadeOut      = einst->fadeOut;
-        } else
-            JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr);
-        
-        // Write to file
-        totalSize += sizeof(jssE);
-        if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1)
-            JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
-            "Could not write JSSMOD extended instrument #%i to file!\n", instr);
-    }
-    dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize);
-
-
-    // Write sample instrument headers
-    for (totalSize = instr = 0; instr < m->ninstruments; instr++)
-    {
-        JSSMODInstrument jssI;
-        JSSInstrument *pInst = m->instruments[instr];
-
-        memset(&jssI, 0, sizeof(jssI));
-
-        // Create header
-        if (pInst)
-        {
-            jssI.size         = pInst->size;
-            jssI.loopS        = pInst->loopS;
-            jssI.loopE        = pInst->loopE;
-            jssI.volume       = pInst->volume;
-            jssI.flags        = pInst->flags;
-            jssI.C4BaseSpeed  = pInst->C4BaseSpeed;
-            jssI.ERelNote     = pInst->ERelNote;
-            jssI.EFineTune    = pInst->EFineTune;
-            jssI.EPanning     = pInst->EPanning;
-            jssI.hasData      = (pInst->data != NULL) ? TRUE : FALSE;
-            jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8;
-        }
-        else 
-            JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr);
-        
-        // Write to file
-        totalSize += sizeof(jssI);
-        if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1)
-            JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
-             "Could not write JSSMOD instrument #%i to file!\n", instr);
-    }
-    dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize);
-    
-    // Write sample data
-    for (totalSize = instr = 0; instr < m->ninstruments; instr++)
-    if (m->instruments[instr])
-    {
-        JSSInstrument *inst = m->instruments[instr];
-        if (inst->data != NULL)
-        {
-            size_t res;
-            if (inst->flags & jsf16bit)
-            {
-                jssEncodeSample16(inst->data, inst->size, flags16);
-                res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile);
-            }
-            else
-            {
-                jssEncodeSample8(inst->data, inst->size, flags8);
-                res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile);
-            }
-            
-            totalSize += inst->size;
-            if (res != (size_t) inst->size)
-                JSSERROR(DMERR_FWRITE, DMERR_FWRITE,
-                 "Could not write JSSMOD sample #%i to file!\n", instr);
-        }
-    }
-    dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize);
-    
-    return DMERR_OK;
-}
-
-
-/* Optimize a given module
- */
-JSSModule *optimizeModule(JSSModule *m)
-{
-    BOOL usedPatterns[jsetMaxPatterns + 1],
-         usedInstruments[jsetMaxInstruments + 1],
-         usedExtInstruments[jsetMaxInstruments + 1];
-    int  mapExtInstruments[jsetMaxInstruments + 1],
-         mapInstruments[jsetMaxInstruments + 1],
-         mapPatterns[jsetMaxPatterns + 1];
-    JSSModule *r = NULL;
-    int i, n8, n16;
-
-    // Allocate a new module
-    if ((r = jssAllocateModule()) == NULL)
-        return NULL;
-
-    // Allocate tables
-    
-    // Copy things
-    r->moduleType       = m->moduleType;
-    r->moduleName       = dm_strdup(m->moduleName);
-    r->trackerName      = dm_strdup(m->trackerName);
-    r->defSpeed         = m->defSpeed;
-    r->defTempo         = m->defTempo;
-    r->defFlags         = m->defFlags;
-    r->defRestartPos    = m->defRestartPos;
-    r->intVersion       = m->intVersion;
-    r->nchannels        = m->nchannels;
-    r->norders          = m->norders;
-    for (i = 0; i < jsetNChannels; i++)
-        r->defPanning[i] = m->defPanning[i];
-    
-    // Initialize values
-    for (i = 0; i <= jsetMaxInstruments; i++)
-    {
-        usedExtInstruments[i] = FALSE;
-        usedInstruments[i] = FALSE;
-        mapExtInstruments[i] = jsetNotSet;
-        mapInstruments[i] = jsetNotSet;
-    }
-    
-    for (i = 0; i <= jsetMaxPatterns; i++)
-    {
-        usedPatterns[i] = FALSE;
-        mapPatterns[i] = jsetNotSet;
-    }
-
-    // Find out all used patterns and ext.instruments
-    for (i = 0; i < m->norders; i++)
-    {
-        int pattern = m->orderList[i];
-        if (pattern >= 0 && pattern < m->npatterns)
-        {
-            JSSPattern *p = m->patterns[pattern];
-            if (p != NULL)
-            {
-                int row, channel;
-                JSSNote *n = p->data;
-                
-                // Mark pattern as used
-                usedPatterns[pattern] = TRUE;
-                
-                // Check all notes
-                for (row = 0; row < p->nrows; row++)
-                for (channel = 0; channel < p->nchannels; channel++, n++)
-                {
-                    if (n->instrument != jsetNotSet)
-                    {
-                        if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments))
-                            usedExtInstruments[n->instrument] = TRUE;
-                        else
-                            dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n",
-                            pattern, row, channel, n->instrument);
-                    }
-                }
-            }
-            else
-            {
-                dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n",
-                pattern, i);
-            }
-        }
-        else
-        if (pattern != jsetMaxPatterns)
-        {
-            dmError("Order 0x%x has invalid pattern number 0x%x!\n",
-            i, pattern);
-        }
-    }
-    
-    // Find out used instruments
-    for (i = 0; i <= jsetMaxInstruments; i++)
-    if (usedExtInstruments[i] && m->extInstruments[i] != NULL)
-    {
-        int note;
-        JSSExtInstrument *e = m->extInstruments[i];
-        
-        for (note = 0; note < jsetNNotes; note++)
-        if (e->sNumForNotes[note] != jsetNotSet)
-        {
-            int q = e->sNumForNotes[note];
-            if (q >= 0 && q < m->ninstruments)
-            {
-                usedInstruments[q] = TRUE;
-            }
-            else
-            {
-                dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n",
-                i, m->ninstruments, q);
-            }
-        }
-    }
-    
-    // Create pattern mappings
-    r->npatterns = 0;
-    dmMsg(1, "Unused patterns: ");
-        
-    for (i = 0; i <= jsetMaxPatterns; i++)
-    if (m->patterns[i] != NULL)
-    {
-        if (!usedPatterns[i])
-        {
-            dmPrint(2, "0x%x, ", i);
-        }
-        else
-        {
-            if (i >= m->npatterns)
-                dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns);
-            
-            mapPatterns[i] = r->npatterns;
-            r->patterns[r->npatterns] = m->patterns[i];
-            (r->npatterns)++;
-        }
-    }
-    dmPrint(2, "\n");
-    
-    dmMsg(1, "%d used patterns, %d unused.\n",
-    r->npatterns, m->npatterns - r->npatterns);
-    
-    
-    // Re-map instruments
-    dmMsg(1, "Unused instruments: ");
-    for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++)
-    if (m->instruments[i] != NULL)
-    {
-        if (!usedInstruments[i] && !optStripInstr)
-        {
-            dmPrint(2, "0x%x, ", i);
-        }
-        else
-        {
-            JSSInstrument *ip = m->instruments[i];
-            if (i >= m->ninstruments)
-                dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments);
-            
-            mapInstruments[i] = r->ninstruments;
-            r->instruments[r->ninstruments] = ip;
-            (r->ninstruments)++;
-
-            if (ip->flags & jsf16bit)
-                n16++;
-            else
-                n8++;
-        }
-    }
-    dmPrint(2, "\n");
-    dmMsg(1, "Total of (%d)  16-bit, (%d) 8-bit samples, (%d) instruments.\n",
-    n16, n8, r->ninstruments);
-    
-    // Re-map ext.instruments
-    dmMsg(1, "Unused ext.instruments: ");
-    for (i = 0; i < jsetMaxInstruments; i++)
-    if (usedExtInstruments[i])
-    {
-        if (i >= m->nextInstruments && !optStripExtInstr)
-        {
-            dmError("Ext.instrument 0x%x >= 0x%x, but used!\n",
-            i, m->nextInstruments);
-        }
-        else
-        if (m->extInstruments[i] != NULL)
-        {
-            JSSExtInstrument *e = m->extInstruments[i];
-            int note;
-            
-            mapExtInstruments[i] = r->nextInstruments;
-            r->extInstruments[r->nextInstruments] = e;
-            (r->nextInstruments)++;
-            
-            // Re-map sNumForNotes
-            for (note = 0; note < jsetNNotes; note++)
-            {
-                int q = e->sNumForNotes[note];
-                if (q != jsetNotSet)
-                {
-                    int map;
-                    if (q >= 0 && q <= jsetMaxInstruments)
-                    {
-                        map = mapInstruments[q];
-                    }
-                    else
-                    {
-                        map = jsetNotSet;
-                        dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments);
-                    }
-                    e->sNumForNotes[note] = map;
-                }
-            }
-        }
-        else
-        {
-            dmPrint(2, "[0x%x==NULL], ", i);
-            mapExtInstruments[i] = jsetNotSet;
-        }
-    }
-    else
-    {
-        if (i < m->nextInstruments && m->extInstruments[i] != NULL)
-        {
-            dmPrint(2, "0x%x, ", i);
-        }
-    }
-    dmPrint(2, "\n");
-    dmMsg(1, "%d extended instruments.\n", r->nextInstruments);
-    
-    
-    // Remap pattern instrument data
-    for (i = 0; i < r->npatterns; i++)
-    {
-        int row, channel;
-        JSSPattern *p = r->patterns[i];
-        JSSNote *n = p->data;
-        
-        for (row = 0; row < p->nrows; row++)
-        for (channel = 0; channel < p->nchannels; channel++, n++)
-        {
-            char effect;
-
-            if (!optStripExtInstr)
-            {
-                if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments)
-                    n->instrument = mapExtInstruments[n->instrument];
-
-                if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL)
-                    dmError("Non-existing instrument used #%d.\n", n->instrument);
-            }
-
-            JMPGETEFFECT(effect, n->effect);
-            
-            switch (effect)
-            {
-                case 'C': // Cxx = Set volume
-                    if (n->volume == jsetNotSet)
-                    {
-                        n->volume = n->param;
-                        n->effect = jsetNotSet;
-                        n->param = jsetNotSet;
-                    }
-                    break;
-            }
-        }
-    }
-    
-    // Remap orders list
-    for (i = 0; i < m->norders; i++)
-    {
-        r->orderList[i] = mapPatterns[m->orderList[i]];
-    }
-
-    return r;
-}
-
-
-int main(int argc, char *argv[])
-{
-    DMResource *sfile = NULL;
-    FILE *dfile = NULL;
-    JSSModule *sm, *dm;
-    int result;
-
-    dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL);
-    dmVerbosity = 0;
-
-    // Parse arguments
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, argHandleFile, TRUE))
-        exit(1);
-
-    // Check arguments
-    if (optInFilename == NULL || optOutFilename == NULL)
-    {
-        dmError("Input or output file not specified. Try --help.\n");
-        return 1;
-    }
-
-    // Read the source file
-    if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL)
-    {
-        dmError("Error opening input file '%s', %d: %s\n",
-            optInFilename, errno, strerror(errno));
-        return 1;
-    }
-
-    // Initialize miniJSS
-    jssInit();
-
-    // Read file
-    dmMsg(1, "Reading XM-format file ...\n");
-    result = jssLoadXM(sfile, &sm);
-    dmf_close(sfile);
-    if (result != 0)
-    {
-        dmError("Error while loading XM file (%i), ", result);
-        if (optIgnoreErrors)
-            fprintf(stderr, "ignoring. This may cause problems.\n");
-        else
-        {
-            fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n");
-            return 2;
-        }
-    }
-
-    // Check stripping settings
-    if (optStripExtInstr) optStripInstr = TRUE;
-    if (optStripInstr) optStripSamples = TRUE;
-    
-    // Remove samples
-    if (optStripSamples)
-    {
-        int i;
-        
-        dmMsg(1, "Stripping samples...\n");
-        for (i = 0; i < sm->ninstruments; i++)
-        {
-            dmFree(sm->instruments[i]->data);
-            sm->instruments[i]->data = NULL;
-        }
-    }
-
-    // Remove instruments
-    if (optStripInstr)
-    {
-        int i;
-        
-        dmMsg(1, "Stripping instruments...\n");
-        for (i = 0; i < sm->ninstruments; i++)
-        {
-            dmFree(sm->instruments[i]);
-            sm->instruments[i] = NULL;
-        }
-        sm->ninstruments = 0;
-    }
-
-    // Remove ext.instruments
-    if (optStripExtInstr)
-    {
-        int i;
-        
-        dmMsg(1, "Stripping ext.instruments...\n");
-        for (i = 0; i < sm->nextInstruments; i++)
-        {
-            dmFree(sm->extInstruments[i]);
-            sm->extInstruments[i] = NULL;
-        }
-        sm->nextInstruments = 0;
-    }
-    // Run the optimization procedure
-    if (optOptimize)
-    {
-        dmMsg(1, "Optimizing module data...\n");
-        dm = optimizeModule(sm);
-    } else
-        dm = sm;
-
-    // Write output file
-    if ((dfile = fopen(optOutFilename, "wb")) == NULL)
-    {
-        dmError("Error creating output file '%s', %d: %s\n",
-            optOutFilename, errno, strerror(errno));
-        return 1;
-    }
-
-    dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n",
-        optPatternMode, optSampMode8, optSampMode16);
-    
-    result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16);
-    
-    fclose(dfile);
-    
-    if (result != 0)
-    {
-        dmError("Error while saving JSSMOD file, %d: %s\n",
-            result, dmErrorStr(result));
-        dmError("WARNING: The resulting file may be broken!\n");
-    }
-    else
-    {
-        dmMsg(1, "Conversion complete.\n");
-    }
-    return 0;
-}