/************************************************************************
        Spectrum2IFF.c
            Converts ZX Spectrum Screens to IFF-ILBM
            It doesn't work from Workbench
        Usage: Spectrum2IFF SpectrumFile ILBMFile
        Version 1.0 Rev2
            14 - V - 1993
        Compilacion:
            Compiled with SAS/Lattice C 5.10a
        Bugs:
            It doesn't work from Workbench
        (c) Eduardo Delgado Buitrago
*************************************************************************/


#define NAME    "Spectrum2IFF"
#define VERSION "version 1.0"
#define DATE    "14.5.93"


/* Header files needed -------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <proto/dos.h>
#include <proto/exec.h>


/* This program's error messages ---------------------------------- */
char *ErrMsg[] = {
    "Unknown error\n" ,
    "Not enough memory\n" ,
    "Can't open file %s for input\n" ,
    "Error reading file %s\n" ,
    "Bad format. %s is not a Spectrum Screen\n" ,
    "Can't create file %s\n" ,
    "Error writing to file %s\n"
} ;
#define MaxErrNo ((sizeof(ErrMsg)/sizeof(char *))-1)


/* Used in order to remember all resources used ------------------- */
/* So you can (must!) free all of them */
ULONG RememberResources = 0 ;
#define SPECTRUMMEMORY  0x0001
    UBYTE *SpectrumBuffer ;
#define IFFMEMORY   0x0002
    UBYTE *IFFBuffer ;
#define INPUTFILE   0x0004
    BPTR ifh ;
#define OUTPUTFILE  0x0008
    BPTR ofh ;


/* function prototypes -------------------------------------------- */
void main(int argc , char **argv) ;
void Usage(void) ;
void Error(int ErrNo , char *ErrObj) ;
void FreeResources(void) ;
LONG GetFileSize(BPTR fh) ;
int CXBRK(void) { return(0); }
int chkabort(void) { return(0); }


/* global variables ----------------------------------------------- */
char *Version = "$VER: "NAME" "VERSION" "DATE"\r\n" ;


void main(int argc , char *argv[]) /* ----------------------------- */
{
    static UBYTE IFFHeader[] = {
        0x46 , 0x4F , 0x52 , 0x4D , 0x00 , 0x00 , 0x60 , 0x6C ,
        0x49 , 0x4C , 0x42 , 0x4D , 0x42 , 0x4D , 0x48 , 0x44 ,
        0x00 , 0x00 , 0x00 , 0x14 , 0x01 , 0x00 , 0x00 , 0xC0 ,
        0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 ,
        0x00 , 0x00 , 0x64 , 0x64 , 0x01 , 0x40 , 0x00 , 0xC8 ,
        0x43 , 0x41 , 0x4D , 0x47 , 0x00 , 0x00 , 0x00 , 0x04 ,
        0x00 , 0x00 , 0x60 , 0x00 , 0x43 , 0x4D , 0x41 , 0x50 ,
        0x00 , 0x00 , 0x00 , 0x30 , 0x00 , 0x00 , 0x00 , 0x00 ,
        0x00 , 0xC0 , 0xC0 , 0x00 , 0x00 , 0xC0 , 0x00 , 0xC0 ,
        0x00 , 0xC0 , 0x00 , 0x00 , 0xC0 , 0xC0 , 0xC0 , 0xC0 ,
        0x00 , 0xC0 , 0xC0 , 0xC0 , 0x00 , 0x00 , 0x00 , 0x00 ,
        0x00 , 0xF0 , 0xF0 , 0x00 , 0x00 , 0xF0 , 0x00 , 0xF0 ,
        0x00 , 0xF0 , 0x00 , 0x00 , 0xF0 , 0xF0 , 0xF0 , 0xF0 ,
        0x00 , 0xF0 , 0xF0 , 0xF0 , 0x42 , 0x4F , 0x44 , 0x59 ,
        0x00 , 0x00 , 0x60 , 0x00
    } ;
    static UBYTE ColorCodes[4][16] = {
        { 0,255, 0 ,255, 0 ,255, 0 ,255, 0 ,255, 0 ,255, 0 ,255, 0 ,255 } ,
        { 0, 0 ,255,255, 0 , 0 ,255,255, 0 , 0 ,255,255, 0 , 0 ,255,255 } ,
        { 0, 0 , 0 , 0 ,255,255,255,255, 0 , 0 , 0 , 0 ,255,255,255,255 } ,
        { 0, 0 , 0 , 0 , 0 , 0 , 0 , 0 ,255,255,255,255,255,255,255,255 }
    } ;
    char *InputFile ;
    char *OutputFile ;
    UBYTE *Disp , *Attr , *Target ;
    UBYTE Color , Ink , Paper , Bright , Pixels ;
    int i , j , k , l ;

    switch (argc) {
        case 0 : _exit(0L) ;
                 break ;
        case 3 : InputFile = argv[1] ;
                 OutputFile = argv[2] ;
                 break ;
        default: Usage() ;
                 break ;
    }

    SpectrumBuffer = AllocMem(6912 , MEMF_PUBLIC) ;
    if (SpectrumBuffer == NULL) Error(1,NULL) ;
    RememberResources |= SPECTRUMMEMORY ;

    IFFBuffer = AllocMem(24576 , MEMF_PUBLIC) ;
    if (IFFBuffer == NULL) Error(1,NULL) ;
    RememberResources |= IFFMEMORY ;

    ifh = Open(InputFile , MODE_OLDFILE) ;
    if (ifh == NULL) Error(2,InputFile) ;
    RememberResources |= INPUTFILE ;

    if (GetFileSize(ifh) != 6912) Error(4,InputFile) ;
    if (Read(ifh , SpectrumBuffer , 6912) != 6912) Error(3,InputFile) ;
    Close(ifh) ;
    RememberResources ^= INPUTFILE ;

    Disp = SpectrumBuffer ;
    Attr = SpectrumBuffer + 6144 ;
    Target = IFFBuffer ;

    for (i=0 ; i<24 ; i++) {
        for (j=0 ; j<32 ; j++) {
            Color = *Attr++ ;
            Ink = Color & 7 ;
            Paper = (Color >> 3) & 7 ;
            Bright = (Color >> 3) & 8 ;
            Ink += Bright ;
            Paper += Bright ;
            for (k=0 ; k<8 ; k++) {
                Pixels = Disp[j + 256*k] ;
                for (l=0 ; l<4 ; l++) {
                    Target[j + 32*l + 128*k] =
                        ((Pixels & ColorCodes[l][Ink]) |
                        (~Pixels & ColorCodes[l][Paper])) ;
                } /* end for-l */
            } /* end for-k */
        } /* end for-j */
        Disp += ((i%8)==7) ? 1824 : 32 ;
        Target += 1024 ;
    } /* end for-i */

    ofh = Open(OutputFile , MODE_NEWFILE) ;
    if (ofh == NULL) Error(5,OutputFile) ;
    RememberResources |= OUTPUTFILE ;

    if (Write(ofh , IFFHeader , 116) != 116) Error(6,OutputFile) ;
    if (Write(ofh , IFFBuffer , 24576) != 24576) Error(6,OutputFile) ;

    FreeResources() ;

} /* end of main() */


void Usage(void) /* ----------------------------------------------- */
{
    printf("\x1B[1m"NAME" "VERSION"\x1B[0m\n"
           "    Usage: "NAME" SpectrumFile ILBMFile\n"
           "\x1B[1m(c) Eduardo Delgado        " DATE "\x1B[0m\n" ) ;

    exit(0) ;
}


/* On error, free all resources used and exit --------------------- */
void Error(int ErrNo , char *ErrObj)
{
    if (ErrNo > MaxErrNo) printf(ErrMsg[0]) ;
    else if (ErrObj) printf(ErrMsg[ErrNo] , ErrObj) ;
         else printf(ErrMsg[ErrNo]) ;
    FreeResources() ;
    exit(10) ;
}


/* Free all resources used ---------------------------------------- */
void FreeResources(void)
{
    if (RememberResources & OUTPUTFILE)     Close(ofh) ;
    if (RememberResources & INPUTFILE)      Close(ifh) ;
    if (RememberResources & IFFMEMORY)      FreeMem(IFFBuffer , 24576) ;
    if (RememberResources & SPECTRUMMEMORY) FreeMem(SpectrumBuffer , 6912) ;
}


LONG GetFileSize(BPTR fh)
{
    register LONG Pos , Size ;

    Pos = Seek(fh , 0 , OFFSET_END) ;
    if (Pos < 0) return (-1L) ;
    Size = Seek(fh , Pos , OFFSET_BEGINNING) ;
    return(Size) ;
}
