/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    main

Abstract:

    framework and utility routines for cvtres

Author:

    Sanford A. Staab (sanfords) 23-Apr-1990

Revision History:

    01-Oct-1990 mikeke
        Added support for conversion of win30 resources

    19-May-1990 Steve Wood (stevewo)
        Added the target machine switches, along with the debug switch.

    23-Apr-1990 sanfords
        Created

--*/

#include <windows.h>

#include <share.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "cvtres.h"
#include "rc.h"
#include "getmsg.h"
#include "msg.h"

//
// Globals
//

char *szInFile;
char *szOutFile;
USHORT targetMachine = IMAGE_FILE_MACHINE_UNKNOWN;
USHORT targetRelocType;
BOOL fVerbose;
BOOL fWritable = TRUE;

#if DBG
BOOL fDebug;
#endif /* DBG */


void
usage(int rc)
{
    printf(get_err(MSG_VERSION), VER_PRODUCTVERSION_STR);
    puts(get_err(MSG_COPYRIGHT));

    puts("usage: CVTRES [options] ResFile\n"
         "\n"
         "   options:\n"
         "\n"
#if DBG
         "      /DEBUG\n"
#endif /* DBG */
         "      /MACHINE:{IX86|MIPS|ALPHA|PPC}\n"
         "      /NOLOGO\n"
         "      /OUT:filename\n"
         "      /READONLY\n"
         "      /VERBOSE\n");

    exit(rc);
}


void
_CRTAPI1 main(
    IN int argc,
    IN char *argv[]
    )

/*++

Routine Description:

    Determines options
    locates and opens input files
    reads input files
    writes output files
    exits

Exit Value:

        0 on success
        1 if error

--*/

{
    int i;
    char szDrive[_MAX_DRIVE];
    char szDir[_MAX_DIR];
    char szFname[_MAX_FNAME];
    char szExt[_MAX_EXT];
    char szInPath[_MAX_PATH];
    char szOutPath[_MAX_PATH];
    FILE *fh;
    FILE *fhOut;
    char *s1;
    long lbytes;
    BOOL result;
    BOOL fNoLogo = FALSE;
    BOOL fReproducible = FALSE;
    DWORD timeDate;

    SetErrorFile("cvtres.err", _pgmptr, 1);

    if (argc == 1) {
        usage(0);
    }

    for (i = 1; i < argc; i++) {
        s1 = argv[i];

        if (*s1 == '/' || *s1 == '-') {
            s1++;

            if (!_strnicmp(s1, "machine:", 8)) {
                s1 += 8;

                if (!_stricmp(s1, "IX86") || !_stricmp(s1, "X86")) {
                    targetMachine = IMAGE_FILE_MACHINE_I386;
                    targetRelocType = IMAGE_REL_I386_DIR32NB;
                } else if (!_stricmp(s1, "MIPS")) {
                    targetMachine = IMAGE_FILE_MACHINE_R4000;
                    targetRelocType = IMAGE_REL_MIPS_REFWORDNB;
                } else if (!_stricmp(s1, "ALPHA")) {
                    targetMachine = IMAGE_FILE_MACHINE_ALPHA;
                    targetRelocType = IMAGE_REL_ALPHA_REFLONGNB;
                } else if (!_stricmp(s1, "PPC")) {
                    targetMachine = IMAGE_FILE_MACHINE_POWERPC;
                    targetRelocType = IMAGE_REL_PPC_ADDR32NB;
                } else {
                    usage(1);
                }
            } else if (!_stricmp(s1, "nologo")) {
                fNoLogo = TRUE;
            } else if (!_stricmp(s1, "o")) {
                szOutFile = argv[++i];
            } else if (!_strnicmp(s1, "out:", 4)) {
                szOutFile = s1+4;
            } else if (!_stricmp(s1, "readonly") || !_stricmp(s1, "r")) {
                fWritable = FALSE;
            } else if (!_stricmp(s1, "verbose") || !_stricmp(s1, "v")) {
                fVerbose = TRUE;
            } else if (!_stricmp(s1, "Brepro")) {
                fReproducible = TRUE;
            } else if (!_stricmp(s1, "I386")) {
                targetMachine = IMAGE_FILE_MACHINE_I386;
                targetRelocType = IMAGE_REL_I386_DIR32NB;
            } else if (!_stricmp(s1, "IX86")) {
                targetMachine = IMAGE_FILE_MACHINE_I386;
                targetRelocType = IMAGE_REL_I386_DIR32NB;
            } else if (!_stricmp(s1, "MIPS")) {
                targetMachine = IMAGE_FILE_MACHINE_R4000;
                targetRelocType = IMAGE_REL_MIPS_REFWORDNB;
            } else if (!_stricmp(s1, "ALPHA")) {
                targetMachine = IMAGE_FILE_MACHINE_ALPHA;
                targetRelocType = IMAGE_REL_ALPHA_REFLONGNB;
            } else if (!_stricmp(s1, "PPC")) {
                targetMachine = IMAGE_FILE_MACHINE_POWERPC;
                targetRelocType = IMAGE_REL_PPC_ADDR32NB;
#if DBG
            } else if (!_stricmp(s1, "debug") || !_stricmp(s1, "d")) {
                fDebug = TRUE;
                fVerbose = TRUE;
#endif /* DBG */
            } else {
                usage(1);
            }
        } else {
            szInFile = s1;
        }
    }

    //
    // Make sure that we actually got a file
    //

    if (!szInFile) {
        usage(1);
    }

    if (!fNoLogo) {
        printf(get_err(MSG_VERSION), VER_PRODUCTVERSION_STR);
        puts(get_err(MSG_COPYRIGHT));
    }

    if (targetMachine == IMAGE_FILE_MACHINE_UNKNOWN) {
        WarningPrint(WARN_NOMACHINESPECIFIED,
#if defined(_M_IX86)
            "IX86");
        targetMachine = IMAGE_FILE_MACHINE_I386;
        targetRelocType = IMAGE_REL_I386_DIR32NB;
#elif defined(_M_RX000)
            "MIPS");
        targetMachine = IMAGE_FILE_MACHINE_R4000;
        targetRelocType = IMAGE_REL_MIPS_REFWORDNB;
#elif defined(_M_ALPHA)
            "ALPHA");
        targetMachine = IMAGE_FILE_MACHINE_ALPHA;
        targetRelocType = IMAGE_REL_ALPHA_REFLONGNB;
#elif defined(_M_PPC)
            "PPC");
        targetMachine = IMAGE_FILE_MACHINE_POWERPC;
        targetRelocType = IMAGE_REL_PPC_ADDR32NB;
#else
            "unknown");
#endif
    }

    _splitpath(szInFile, szDrive, szDir, szFname, szExt);

    if (szExt[0] == '\0') {
        // If there is no extension, default to .res

        _makepath(szInPath, szDrive, szDir, szFname, ".res");

        szInFile = szInPath;
    }

    if ((fh = _fsopen(szInFile, "rb", _SH_DENYWR)) == NULL) {
        ErrorPrint(ERR_CANTREADFILE, szInFile);
        exit(1);
    }

#if DBG
    printf("Reading %s\n", szInFile);
#endif /* DBG */

    lbytes = MySeek(fh, 0L, SEEK_END);
    MySeek(fh, 0L, SEEK_SET);

    if (szOutFile == NULL) {
        // Default output file is input file with .obj extension

        _makepath(szOutPath, szDrive, szDir, szFname, ".obj");

        szOutFile = szOutPath;
    }

    if ((fhOut = _fsopen(szOutFile, "wb", _SH_DENYRW)) == NULL) {
        ErrorPrint(ERR_CANTWRITEFILE, szOutFile);
        exit(1);
    }

#if DBG
    printf("Writing %s\n", szOutFile);
#endif /* DBG */

    _tzset();
    // timeDate = (ULONG) time(NULL);
    timeDate = (ULONG) (fReproducible ? -1 : time(NULL));

    result = CvtRes(fh, fhOut, lbytes, fWritable, timeDate);

    fclose(fh);
    fclose(fhOut);

    exit(result ? 0 : 1);
}




PVOID
MyAlloc(UINT nbytes)
{
    UCHAR       *s;

    if ((s = (UCHAR*)calloc( 1, nbytes )) != NULL) {
        return s;
    }

    ErrorPrint(ERR_OUTOFMEMORY, nbytes );
    exit(1);
}


PVOID
MyFree( PVOID p )
{
    if (p)
        free( p );
    return NULL;
}


USHORT
MyReadWord(FILE *fh, USHORT*p)
{
    UINT      n1;

    if ((n1 = fread(p, 1, sizeof(USHORT), fh)) != sizeof(USHORT)) {
        ErrorPrint( ERR_FILEREADERR);
        exit(1);
    }
    else
        return 0;
}


UINT
MyRead(FILE *fh, PVOID p, UINT n )
{
    UINT      n1;

    if ((n1 = fread( p, 1, n, fh)) != n) {
        ErrorPrint( ERR_FILEREADERR );
        exit(1);
    }
    else
        return 0;
}

LONG
MyTell( FILE *fh )
{
    long pos;

    if ((pos = ftell( fh )) == -1) {
        ErrorPrint(ERR_FILETELLERR );
        exit(1);
    }

    return pos;
}


LONG
MySeek( FILE *fh, long pos, int cmd )
{
    if ((pos = fseek( fh, pos, cmd )) == -1) {
        ErrorPrint(ERR_FILESEEKERR );
        exit(1);
    }

    return MyTell(fh);
}


ULONG
MoveFilePos( FILE *fh, USHORT pos, int alignment )
{
    long newpos;

    newpos = (long)pos;
    newpos <<= alignment;
    return MySeek( fh, newpos, SEEK_SET );
}


UINT
MyWrite( FILE *fh, PVOID p, UINT n )
{
    ULONG       n1;

    if ((n1 = fwrite( p, 1, n, fh )) != n) {
        ErrorPrint(ERR_FILEWRITEERR );
        exit(1);
    }
    else
        return 0;
}

#undef BUFSIZE
#define BUFSIZE 1024

int
MyCopy( FILE *srcfh, FILE *dstfh, ULONG nbytes )
{
    static UCHAR buffer[ BUFSIZE ];
    UINT        n;
    ULONG       cb=0L;

    while (nbytes) {
        if (nbytes <= BUFSIZE)
            n = (UINT)nbytes;
        else
            n = BUFSIZE;
        nbytes -= n;

        if (!MyRead( srcfh, buffer, n )) {
            cb += n;
            MyWrite( dstfh, buffer, n );
        }
        else {
            return cb;
        }
    }
    return cb;
}


void
ErrorPrint(
    USHORT errnum,
    ...
    )
{
    va_list va;
    va_start(va, errnum);

    printf(get_err(MSG_ERROR), errnum, ' ');

    vprintf(get_err(errnum), va);
    printf("\n");

    va_end(va);
}

void
WarningPrint(
    USHORT errnum,
    ...
    )
{
    va_list va;
    va_start(va, errnum);

    printf(get_err(MSG_WARNING), errnum, ' ');

    vprintf(get_err(errnum), va);
    printf("\n");

    va_end(va);
}

#if 0

/***
*splitpath.c - break down path name into components
*
*   Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*   To provide support for accessing the individual components of an
*   arbitrary path name
*
*Revision History:
*   06-14-87  DFW   initial implementation
*   09-23-87  JCR   Removed 'const' from declarations (fixed cl warnings)
*   12-11-87  JCR   Added "_LOAD_DS" to declaration
*   11-20-89  GJF   Fixed indents, copyright. Added const attribute to
*           type of path.
*   03-15-90  GJF   Replaced _LOAD_DS with _CALLTYPE1 and added #include
*           <cruntime.h>.
*   07-25-90  SBM   Removed redundant include (stdio.h), replaced local
*           MIN macro with standard min macro
*   10-04-90  GJF   New-style function declarator.
*   01-22-91  GJF   ANSI naming.
*   11-20-92  KRS   Port _MBCS support from 16-bit tree.
*   05-12-93  KRS   Add fix for MBCS max path handling.
*
*******************************************************************************/

/***
*_splitpath() - split a path name into its individual components
*
*Purpose:
*   to split a path name into its individual components
*
*Entry:
*   path  - pointer to path name to be parsed
*   drive - pointer to buffer for drive component, if any
*   dir   - pointer to buffer for subdirectory component, if any
*   fname - pointer to buffer for file base name component, if any
*   ext   - pointer to buffer for file name extension component, if any
*
*Exit:
*   drive - pointer to drive string.  Includes ':' if a drive was given.
*   dir   - pointer to subdirectory string.  Includes leading and trailing
*       '/' or '\', if any.
*   fname - pointer to file base name
*   ext   - pointer to file extension, if any.  Includes leading '.'.
*
*Exceptions:
*
*******************************************************************************/

void _CRTAPI1 _splitpath (
    register const char *path,
    char *drive,
    char *dir,
    char *fname,
    char *ext
    )
{
    register char *p;
    char *last_slash = NULL, *dot = NULL;
    unsigned len;

    UINT uiCodePage = GetACP();

    /* we assume that the path argument has the following form, where any
     * or all of the components may be missing.
     *
     *  <drive><dir><fname><ext>
     *
     * and each of the components has the following expected form(s)
     *
     *  drive:
     *  0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
     *  ':'
     *  dir:
     *  0 to _MAX_DIR-1 characters in the form of an absolute path
     *  (leading '/' or '\') or relative path, the last of which, if
     *  any, must be a '/' or '\'.  E.g -
     *  absolute path:
     *      \top\next\last\     ; or
     *      /top/next/last/
     *  relative path:
     *      top\next\last\  ; or
     *      top/next/last/
     *  Mixed use of '/' and '\' within a path is also tolerated
     *  fname:
     *  0 to _MAX_FNAME-1 characters not including the '.' character
     *  ext:
     *  0 to _MAX_EXT-1 characters where, if any, the first must be a
     *  '.'
     *
     */

    /* extract drive letter and :, if any */

    if (*(path + _MAX_DRIVE - 2) == ':') {
    if (drive) {
        strncpy(drive, path, _MAX_DRIVE - 1);
        *(drive + _MAX_DRIVE-1) = '\0';
    }
    path += _MAX_DRIVE - 1;
    }
    else if (drive) {
    *drive = '\0';
    }

    /* extract path string, if any.  Path now points to the first character
     * of the path, if any, or the filename or extension, if no path was
     * specified.  Scan ahead for the last occurence, if any, of a '/' or
     * '\' path separator character.  If none is found, there is no path.
     * We will also note the last '.' character found, if any, to aid in
     * handling the extension.
     */

    for (last_slash = NULL, p = (char *)path; *p; p++) {
        if (IsDBCSLeadByteEx(uiCodePage, *p))
        p++;
    else {
        if (*p == '/' || *p == '\\')
        /* point to one beyond for later copy */
        last_slash = p + 1;
        else if (*p == '.')
        dot = p;
    }
    }

    if (last_slash) {

    /* found a path - copy up through last_slash or max. characters
     * allowed, whichever is smaller
     */

    if (dir) {
        len = __min((last_slash - path), (_MAX_DIR - 1));
        strncpy(dir, path, len);
        *(dir + len) = '\0';
    }
    path = last_slash;
    }
    else if (dir) {

    /* no path found */

    *dir = '\0';
    }

    /* extract file name and extension, if any.  Path now points to the
     * first character of the file name, if any, or the extension if no
     * file name was given.  Dot points to the '.' beginning the extension,
     * if any.
     */

    if (dot && (dot >= path)) {
    /* found the marker for an extension - copy the file name up to
     * the '.'.
     */
    if (fname) {
        len = __min((dot - path), (_MAX_FNAME - 1));
        strncpy(fname, path, len);
        *(fname + len) = '\0';
    }
    /* now we can get the extension - remember that p still points
     * to the terminating nul character of path.
     */
    if (ext) {
        len = __min((p - dot), (_MAX_EXT - 1));
        strncpy(ext, dot, len);
        *(ext + len) = '\0';
    }
    }
    else {
    /* found no extension, give empty extension and copy rest of
     * string into fname.
     */
    if (fname) {
        len = __min((p - path), (_MAX_FNAME - 1));
        strncpy(fname, path, len);
        *(fname + len) = '\0';
    }
    if (ext) {
        *ext = '\0';
    }
    }
}

#endif