/*===============================================================

    RC - ResCode
         Herb and Dave's code resource converter

    Herb and I started this on a crazy night in Kansas.
    I finished it shortly afterward. Basically, I was
    tired of having to use Rez and Orca while developing
    a CDev under Merlin. This was a cheap and simple
    solution to that problem.

    Released as Freeware in September, 1990 with the request
    that the source code and help file are always distributed
    with the file. Permission is hereby given to use this code
    in any manner you see fit. If included on a commercial
    work, please contact Palace Productions to let us know!

===============================================================*/



#include <stdio.h>
#include <misctool.h>
#include <locator.h>
#include <memory.h>
#include <intmath.h>
#include <gsos.h>
#include <resources.h>

/*---------------------- flag defines --------------------------*/

#define false FALSE
#define flase FALSE
#define USE_CONVERTER   1   /* on again */
#define DEBUG           1   /* debug switch */
#define C_CODE_CONVERTER 0  /* use the assembly version */

/*--------------------- special prototype ----------------------*/

extern pascal void DebugStr() inline(0x09ff,dispatcher);

/*---------------------- local prototype -----------------------*/

    int main( int argc, char *argv[] );
    boolean getInFile( char *fname, handle *inH );
    OSErr openResFile( char *fname, word *fileId );
    void addNewCode( long rez_id, handle in_fileH );
    void ShowSyntax( char *command );

#if C_CODE_CONVERTER
    pascal long RezConverter( ResRefRecPtr rezRec, IORecPtrGS io, word msg );
#else
    extern  void RezAsmConverter( void );    /* sleazoid asm assignment! */
#endif


/*----------------------- my defines ---------------------------*/

    /* parse equates */

#define COMMAND         0
#define CODE_SWITCH     (COMMAND+1)
#define CODE_FILE       (CODE_SWITCH + 1)
#define OUT_FILE        (CODE_FILE + 1)
#define REZ_ID          (OUT_FILE + 1)

/*------------------------ globals -----------------------------*/

word        mainId;
word        auxId;
word        rezFileId;
word        rezType;            /* type of resource to write */

word        ourTypes[2] = {
            0x8017,         /* rCodeResource */
            0x8018          /* rCDevCode */
            };




/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    Code here.....

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/





/*---------------------------------------------------------------------------
    main - runs this thang.

    input - number of arguments
            pointer to argument string from shell
    returns - to where it came from
---------------------------------------------------------------------------*/
int main( int argc, char *argv[] )
{
char        *c_ptr;
char        c;
boolean     go;
boolean     do_hex;
long        rez_id;
handle      in_fileH;
OSErr       err;

    do_hex = false;

    if ( argc != (REZ_ID + 1) ) {
        printf( "\nInsufficient number of parameters......\n\n" );
        ShowSyntax( argv[COMMAND] );
        return;
        }

    c_ptr = argv[CODE_SWITCH];
    c = *c_ptr;
    if ( c != '-' ) {
        ShowSyntax( argv[COMMAND] );
        return;
        }
    c_ptr++;
    c = *c_ptr;
    if ( c == 'r' ) rezType = ourTypes[0];
    else if ( c == 'c' ) rezType = ourTypes[1];
    else {
        ShowSyntax( argv[COMMAND] );
        return;
        }

    c_ptr = argv[REZ_ID];
    c = *c_ptr;

    if (( c != '$' ) && (( c > '9' ) || ( c < '0' ))) {
        ShowSyntax( argv[COMMAND] );
        return;
        }

    else if ( c == '$' ) {
        do_hex = true;
        c_ptr += 1;
        c = *c_ptr;
        if (( c > '9' ) || ( c < '0' )) {
            ShowSyntax( argv[COMMAND] );
            return;
            }
        }

    /* convert here! */

    if ( do_hex ) {
        rez_id = Hex2Long( c_ptr, strlen( c_ptr ) );
        }
    else {
        rez_id = Dec2Long( c_ptr, strlen( c_ptr ), false );
        }

    printf( "\nThe rez id: $%lx\n\n", rez_id );

    TLStartUp();
    mainId = MMStartUp();
    auxId = ( 0x0100 | mainId );

    ResourceStartUp( mainId );
    if ( toolerror() ) {
        MMShutDown(mainId);
        TLShutDown();
        printf( "\nError starting resource manager!\n" );
        return;
        }

    go = getInFile( argv[CODE_FILE], &in_fileH );
    if ( go ) {
        err = openResFile( argv[OUT_FILE], &rezFileId );
        if ( !(err) ) {
            addNewCode( rez_id, in_fileH );
            }
        else {
            printf( "\nError $%x opening resource file\n", err );
            }
        DisposeHandle( in_fileH );
        }

    else {
        printf( "\nError opening input file\n" );
        }

    ResourceShutDown();
    MMShutDown(mainId);
    TLShutDown();
    return;

} /* main */




/*---------------------------------------------------------------------------
    getInFile - Open the input file

    input - pointer to file name
            handle to storage area
    returns - falg yes / no situation
---------------------------------------------------------------------------*/
boolean getInFile( char *fname, handle *inH )
{
OpenRecGS       openRec;
IORecGS         ioRec;
GSString255     path;

    path.length = (word) strlen(fname);
    BlockMove( fname, &path.text, (long) path.length );

    openRec.pCount = 12;    /*enough for eof */
    openRec.pathname = &path;
    openRec.requestAccess = 1;   /*enuf to read!*/
    openRec.resourceNumber = 0;

    OpenGS( &openRec );
    if (toolerror()) return( false );

    ioRec.refNum = openRec.refNum;

    *inH = NewHandle( openRec.eof, auxId, 0, 0L );

    if ( *inH == nil ) {
        ioRec.pCount = 1;
        CloseGS( &ioRec);
        return( false );
        }

    HLock( *inH );

    ioRec.pCount = 4;
    ioRec.dataBuffer = **inH;
    ioRec.requestCount = openRec.eof;

    ReadGS( &ioRec );
    if ( toolerror() ) {
        ioRec.pCount = 1;
        CloseGS( &ioRec);
        DisposeHandle( *inH );
        *inH = nil;
        return( false );
        }

    HUnlock( *inH );

    ioRec.pCount = 1;
    CloseGS( &ioRec);

    return( true );

} /* openInFile */



/*---------------------------------------------------------------------------
    getInFile - Open the input file

    input - pointer to file name
            pointer to storage for file id
    returns - falg yes / no situation
---------------------------------------------------------------------------*/
OSErr openResFile( char *fname, word *fileId )
{
OpenRecGS       openRec;
IORecGS         ioRec;
GSString255     path;
OSErr           err;

    path.length = strlen(fname);
    BlockMove( fname, &path.text, (long) path.length );

    CreateResourceFile( 0L, 0x5e, 0xe3, &path );
    err = toolerror();
    if ( err ) {
        if ( err != 0x1e01 )
            return( err );
        }

    *fileId = OpenResourceFile( 3, 0L, &path );
    err = toolerror();
    return( err );

} /* openResFile */




/*---------------------------------------------------------------------------
    addNewCode - add code resource to resource fork.

    input - resource id
            handle to resource
    returns - notta
---------------------------------------------------------------------------*/
void addNewCode( long rez_id, handle in_fileH )
{
word    rezAttr;
OSErr   err;

    rezAttr = GetResourceAttr( rezType, rez_id );
    err = toolerror();
    if ( err == 0 ) {
        RemoveResource( rezType, rez_id );
        err = toolerror();
        if ( err )
            printf( "\nError $%x removing old resource\n", err );
        }

#if USE_CONVERTER

    #if C_CODE_CONVERTER
        ResourceConverter( RezConverter, rezType, 3 );  /* log in! */
    #else
        ResourceConverter( RezAsmConverter, rezType, 3 );  /* log in! */
    #endif

    rezAttr = resChanged + resConverter;
    AddResource( in_fileH, rezAttr, rezType, rez_id );
    err = toolerror();
    if ( err )
        printf( "\nError $%x adding Resource\n", err );

#else

    rezAttr = resChanged;
    AddResource( in_fileH, rezAttr, rezType, rez_id );
    err = toolerror();
    if ( err )
        printf( "\nError $%x adding Resource\n", err );

    rezAttr = resConverter;
    SetResourceAttr( rezAttr, rezType, rez_id );

#endif

    CloseResourceFile( rezFileId );
    err = toolerror();
    if ( err )
        printf( "\nError $%x closing resource file\n", err );

#if USE_CONVERTER

    #if C_CODE_CONVERTER
        ResourceConverter( RezConverter, rezType, 1 );  /* log out */
    #else
        ResourceConverter( RezAsmConverter, rezType, 1 );  /* log in! */
    #endif

#endif

} /* addNewCode */




/*---------------------------------------------------------------------------
    ShowSyntax - show user the proper syntax use

    input - pointer to actual command used to invoke the puppy
    returns - notta
---------------------------------------------------------------------------*/
void ShowSyntax( char *command )
{

    printf( "Syntax: %s -switch sourcefile destfile id\n\n", command );
    printf( "Switches available in this version:\n" );
    printf( "    -c write cdev code resource (0x8018)\n" );
    printf( "    -r write generic code resource (0x8017)\n\n" );
    printf( "Valid id characters are 0 - 9 and $\n" );

} /* ShowSyntax */



#if C_CODE_CONVERTER

/*---------------------------------------------------------------------------
    RezConverter - converter routine. Doesn't really do anything here
                   but it does show the basic idea of what should be done!
                   Not called by the application, but by the tool box!

    input - pointer to resource ref record
            pointer to standard io rec
            message from resource manager
    returns - long error msg

    note: due to the way that Orca's pascal directive works, this code
          is useless. It will work under APW or MPWIIgs C.
---------------------------------------------------------------------------*/
pascal long RezConverter( ResRefRecPtr rezRec, IORecPtrGS io, word msg )
{
long                retVal;
long                size;
ptr                 fm;
SetPositionRecGS    posRec;
OSErr               err;

#if DEBUG
ptr DebugPtr;


    DebugStr( "\p We have dropped into see this... " );
    DebugPtr = (ptr) rezRec;

#endif

    retVal = 0;

    switch ( msg ) {

        case 2 :                                            /* do write! */
            HLock( rezRec->resHandle );
            fm = *rezRec->resHandle;
            posRec.pCount = 2;
            posRec.refNum = rezRec->resID;
            posRec.base = 0;
            posRec.displacement = rezRec->resOffset;
            SetMarkGS( &posRec );
            err = toolerror();
            if ( err ) {
                retVal = (long) err;
                break;
                }
            WriteGS( io );
            if ( err ) {
                retVal = (long) err;
                break;
                }
            break;

        case 4 :                                            /* get size */
            retVal = GetHandleSize( rezRec->resHandle );
            break;

        default :
            break;

        }

    return( retVal );

} /* RezConverter */

#endif
