#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
//#include <malloc.h>
#include <tchar.h>
//#include <assert.h>
//#include <sys\types.h>
//#include <sys\stat.h>
#include <fcntl.h>

#ifdef RLDOS
#include "dosdefs.h"
#else  //RLDOS
#include <windows.h>
#include "windefs.h"
#endif //RLDOS

#include "resread.h"
#include "restok.h"
#include "custres.h"
#ifdef RLRES32
#include "exentres.h"
#include "reswin16.h"
#else  //RLRES32
#include "exe2res.h"
#endif //RLRES32


UCHAR szDHW[ DHWSIZE];         //... Common temporary buffer

char * gszTmpPrefix = "$RLT";   //... Temporary name prefix

BOOL gbMaster       = FALSE;    //... TRUE if Working in Master project
BOOL gfReplace      = TRUE;     //... FALSE if appending new language to exe
BOOL gbShowWarnings = FALSE;    //... Display warnining messages if TRUE

#ifdef _DEBUG
PMEMLIST pMemList = NULL;
#endif


static BOOL ShouldBeAnExe( CHAR *);
static BOOL NotExistsOrIsEmpty( PCHAR szTargetTokFile);


/**
  *
  *
  *  Function: DWORDfpUP
  * Move the file pointer to the next 32 bit boundary.
  *
  *
  *  Arguments:
  * Infile: File pointer to seek
  * plSize: Address of Resource size var
  *
  *  Returns:
  * Number of padding to next 32 bit boundary, and addjusts resource size var
  *
  *  Errors Codes:
  * -1, fseek failed
  *
  *  History:
  * 10/11/91    Implemented      TerryRu
  *
  *
  **/


DWORD DWORDfpUP(FILE * InFile, DWORD *plSize)
{
    DWORD tPos;
    DWORD Align;
    tPos = (ftell(InFile));
    Align = DWORDUP(tPos);
    
    *plSize -= (Align - tPos);
    fseek( InFile, Align,   SEEK_SET);
    
    return( Align - tPos);
}

/*
 *
 * Function GetName,
 *  Copies a name from the OBJ file into the ObjInfo Structure.
 *
 */
void GetName( FILE *infile, TCHAR *szName , DWORD *lSize)
{
    WORD i = 0;

    do
    {

#ifdef RLRES16

        szName[ i ] = GetByte( infile, lSize);

#else

        szName[ i ] = GetWord( infile, lSize);

#endif
    
    } while ( szName[ i++ ] != TEXT('\0') );
}



/*
 *
 * Function MyAlloc:
 *  Memory allocation routine with error checking.
 *
 */

#ifdef _DEBUG
PBYTE MyAlloc( DWORD dwSize, LPSTR pszFile, WORD wLine)
#else
PBYTE MyAlloc( DWORD dwSize)
#endif
{
    PBYTE   ptr  = NULL;
    HGLOBAL hMem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, 
                                (size_t)((dwSize > 0) ? dwSize : sizeof( TCHAR)));
    
    if ( hMem == NULL )
    {
        QuitT( IDS_ENGERR_11, NULL, NULL);
    }
    else
    {
        ptr = GlobalLock( hMem);
    }

#ifdef _DEBUG
    {
        PMEMLIST pTmpMem = (PMEMLIST)GlobalAlloc( GPTR, sizeof( MEMLIST));

        pTmpMem->pNext = pMemList;
        pMemList = pTmpMem;

        lstrcpyA( pMemList->szMemFile, pszFile);
        pMemList->wMemLine = wLine;
        pMemList->pMem     = ptr;
    }

#endif // _DEBUG

    return( ptr);   // memory allocation okay.
}

//..........................................................................

//ppc cause access violation
void MyFree( void *UNALIGNED*p)
{
    if ( p && *p )
    {

#ifdef _DEBUG

        FreeMemListItem( *p, NULL);
#else
        HGLOBAL hMem = GlobalHandle( (HANDLE)*p);
        GlobalUnlock( hMem);
        GlobalFree( hMem);

#endif // _DEBUG

        *p = NULL;
    }
}


#ifdef _DEBUG

void FreeMemList( FILE *pfMemFile)
{
    while ( pMemList )
    {
        FreeMemListItem( pMemList->pMem, pfMemFile);
    }
}


void FreeMemListItem( void *p, FILE *pfMemFile)
{                                  
    if ( pMemList && p )
    {
        PMEMLIST pThisMem = NULL;
        PMEMLIST pNextMem = NULL;
        PMEMLIST pPrevMem = NULL;

        for ( pThisMem = pMemList; pThisMem; pThisMem = pNextMem )
        {
            pNextMem = pThisMem->pNext;

            if ( pThisMem->pMem == p )
            {
                HGLOBAL hMem = NULL;

                if ( pfMemFile )
                {
                    fprintf( pfMemFile, 
                             "%u\t%s\n", 
                             pThisMem->wMemLine, 
                             pThisMem->szMemFile);
                }
                hMem = GlobalHandle( p);
                GlobalUnlock( hMem);
                GlobalFree( hMem);

                GlobalFree( pThisMem);

                if ( pPrevMem )
                {
                    pPrevMem->pNext = pNextMem;
                }
                else
                {
                    pMemList = pNextMem;
                }
                break;
            }
            pPrevMem = pThisMem;
        }
    }
}

#endif // _DEBUG

/*
 *
 * Function MyReAlloc
 *
 * Re-allocate memory with error checking.
 *
 * History:
 *      01/21/93  MHotchin      Implemented.
 *
 */

#ifdef _DEBUG
PBYTE MyReAlloc(
PBYTE pOldMem,  //... Current ptr to buffer
DWORD cSize,    //... New size for buffer
LPSTR pszFile,
WORD wLine)
#else
PBYTE MyReAlloc(
PBYTE pOldMem,  //... Current ptr to buffer
DWORD cSize)    //... New size for buffer
#endif // _DEBUG
{
    PBYTE    ptr      = NULL;
    HGLOBAL  hMem     = NULL;

	
	hMem = GlobalHandle( pOldMem);
    
    if ( hMem == NULL )
    {
        QuitT( IDS_ENGERR_11, NULL, NULL);
    }

    if ( GlobalUnlock( hMem) || GetLastError() != NO_ERROR )
    {
        QuitT( IDS_ENGERR_11, NULL, NULL);
    }
    hMem = GlobalReAlloc( hMem, cSize, GMEM_MOVEABLE | GMEM_ZEROINIT);
    
    if ( hMem == NULL )
    {
        QuitT( IDS_ENGERR_11, NULL, NULL);
    }
	ptr = GlobalLock( hMem);

#ifdef _DEBUG

	if ( ptr != pOldMem )
	{
        PMEMLIST pThisMem = NULL;
        PMEMLIST pNextMem = NULL;

    	for ( pThisMem = pMemList; pThisMem; pThisMem = pThisMem->pNext )
    	{
    	    if ( pThisMem->pMem == pOldMem )
        	{
        		pThisMem->pMem = ptr;
				break;
			}
		}
	}

#endif // _DEBUG

    return( ptr);
}


/*
 *
 * Function GetByte:
 *  Reads a byte from the input file stream, and checks for EOF.
 *
 */
BYTE GetByte(FILE *pInFile, DWORD *pdwSize)
{
    register int n;
    
    if ( pdwSize )
    {
        (*pdwSize)--;
    }
    n = fgetc( pInFile);

    if ( n == EOF )
    {
    	if ( feof( pInFile) )
    	{
        	exit(-1);
		}
    }
    return( (BYTE)n);
}


/*
 *
 * Function UnGetByte:
 *
 *   Returns the character C into the input stream, and updates the Record Length.
 *
 * Calls:
 *   ungetc, To return character
 *   DiffObjExit, If unable to insert the character into the input stream
 *
 * Caller:
 *   GetFixUpP,
 *
 */

void UnGetByte(FILE *infile, BYTE c, DWORD *lSize)
{
    if (lSize)
    {
        (*lSize)++;
    }
    
    
    if (ungetc(c, infile)== EOF)
    {
        exit (-1);
    }
    
    // c put back into input stream
}

/*
 *
 * Function UnGetWord:
 *
 *   Returns the word C into the input stream, and updates the Record Length.
 *
 * Calls:
 *
 * Caller:
 *
 */

void UnGetWord(FILE *infile, WORD c, DWORD *lSize)
{
    long lCurrentOffset;
    
    if (lSize)
    {
        (*lSize) += 2;
    }
    
    lCurrentOffset = ftell(infile);
    
    if (fseek(infile, (lCurrentOffset - 2L) , SEEK_SET))
    {
        exit (-1);
    }
}


/*
 *
 * Function SkipBytes:
 *  Reads and ignores n bytes from the input stream
 *
 */


void SkipBytes(FILE *infile, DWORD *pcBytes)
{
    if (fseek(infile, (DWORD) *pcBytes, SEEK_CUR) == -1L)
    {
        exit (-1);
    }
    *pcBytes=0;
}



/*
 * Function GetWord:
 *  Reads a WORD from the RES file.
 *
 */

WORD GetWord(FILE *infile, DWORD *lSize)
{
    // Get low order byte
    register WORD lobyte;

    lobyte = GetByte(infile, lSize);
    return(lobyte + (GetByte(infile, lSize) << BYTELN));
}


/*
 *
 * Function GetDWORD:
 *   Reads a Double WORD from the OBJ file.
 *
 */

DWORD GetdWord(FILE *infile, DWORD *lSize)
{
    DWORD dWord = 0;
    
    dWord = (DWORD) GetWord(infile, lSize);
    // Get low order word
    // now get high order word, shift into upper word and or in low order word
    dWord |= ((DWORD) GetWord(infile, lSize) << WORDLN);
    
    return (dWord);
    // return complete double word
}



void  PutByte(FILE *Outfile, TCHAR b, DWORD *plSize)
{
    if (plSize)
    {
        (*plSize) ++;
    }
    
    if (fputc(b, Outfile) == EOF)
    {
        exit(-1);
    }
}

void PutWord(FILE *OutFile, WORD w, DWORD *plSize)
{
    PutByte(OutFile, (BYTE) LOBYTE(w), plSize);
    PutByte(OutFile, (BYTE) HIBYTE(w), plSize);
}

void PutdWord (FILE *OutFile, DWORD l, DWORD *plSize)
{
    PutWord(OutFile, LOWORD(l), plSize);
    PutWord(OutFile, HIWORD(l), plSize);
}


void PutString( FILE *OutFile, TCHAR *szStr , DWORD *plSize)
{
    WORD i = 0;


    do
    {

#ifdef RLRES16

        PutByte( OutFile , szStr[ i ], plSize);

#else

        PutWord( OutFile , szStr[ i ], plSize);

#endif

    } while ( szStr[ i++ ] != TEXT('\0') );
}


/**
  *  Function: MyGetTempFileName
  *    Generic funciton to create a unique file name,
  *    using the API GetTempFileName. This
  *    function is necessary because of the parameters
  *    differences betweenLWIN16, and WIN32.
  *
  *
  *  Arguments:
  *    BYTE   hDriveLetter
  *    LPCSTR lpszPrefixString
  *    UINT   uUnique
  *    LPSTR  lpszTempFileName
  *
  *  Returns:
  *    lpszFileNameTempFileName
  *
  *
  *  Error Codes:
  *    0 - invalid path returned
  *    1 - valid path returned
  *
  *  History:
  *    3/92, Implemented    TerryRu
  */


int MyGetTempFileName(BYTE    hDriveLetter,
                      LPSTR   lpszPrefixString, 
                      WORD    wUnique,
                      LPSTR   lpszTempFileName)
{
    
#ifdef RLWIN16

    return(GetTempFileName(hDriveLetter,
                           (LPCSTR)lpszPrefixString,
                           (UINT)wUnique,
                           lpszTempFileName));
#else //RLWIN16
#ifdef RLWIN32

    UINT uRC;
    CHAR szPathName[ MAX_PATH+1];
    
    if (! GetTempPathA((DWORD)sizeof(szPathName), (LPSTR)szPathName))
    {
        szPathName[0] = '.';
        szPathName[1] = '\0';
    }
    
    uRC = GetTempFileNameA((LPSTR)szPathName,
                           lpszPrefixString,
                           wUnique,
                           lpszTempFileName);
    return((int)uRC);
    
#else  //RLWIN32
    
    return(tmpnam(lpszTempFileName) == NULL ? 0 : 1);
    
#endif // RLWIN32
#endif // RLWIN16
}



/**
  *  Function GenerateImageFile:
  *     builds a resource from the token and rdf files
  *
  *  History:
  *     2/92, implemented       SteveBl
  *     7/92, modified to always use a temporary file   SteveBl
  */


int GenerateImageFile(

CHAR * szTargetImage,
CHAR * szSrcImage,
CHAR * szTOK,
CHAR * szRDFs,
WORD   wFilter)
{
    CHAR szTmpInRes[ MAXFILENAME];
    CHAR szTmpOutRes[ MAXFILENAME];
    CHAR szTmpTargetImage[ MAXFILENAME];
    BOOL bTargetExe = FALSE;
    BOOL bSrcExe  = FALSE;
    int  nExeType = NOTEXE;
    int  rc;
    FILE *fIn  = NULL;
    FILE *fOut = NULL;


    if ( IsRes( szTOK) )
    {    
        // The given szTOK file is really a localized resource file,
        // place these resources into outputimage file

        MyGetTempFileName( 0, "TMP", 0, szTmpTargetImage);

        if ( IsWin32Res( szTOK) )
        {    
            rc = BuildExeFromRes32A( szTmpTargetImage, szTOK, szSrcImage);
        }
        else
        {
            rc = BuildExeFromRes16A( szTmpTargetImage, szTOK, szSrcImage);
        }

        if ( rc != 1 )
        {
            remove( szTmpTargetImage);
            QuitT( IDS_ENGERR_16, (LPTSTR)IDS_NOBLDEXERES, NULL);
        }

        if ( ! CopyFileA( szTmpTargetImage, szTargetImage, FALSE) )
        {
            remove( szTmpTargetImage);
            QuitA( IDS_COPYFILE_FAILED, szTmpTargetImage, szTargetImage);
        }
        remove( szTmpTargetImage);
        return( rc);
    }


    // We're going to now do this EVERY time.  Even if the target doesn't
    // exist.  This will enable us to always work, even if we get two different
    // paths that resolve to the same file.
    
    MyGetTempFileName(0, "TMP", 0, szTmpTargetImage);
    
    rc = IsExe( szSrcImage);

    if ( rc == NTEXE || rc == WIN16EXE )
    {
                                //... resources contained in image file
        nExeType = rc;
        MyGetTempFileName( 0, "RES", 0, szTmpInRes);

        if ( nExeType == NTEXE )
        {
            ExtractResFromExe32A( szSrcImage, szTmpInRes, wFilter);
        }
        else
        {
            ExtractResFromExe16A( szSrcImage, szTmpInRes, wFilter);
        }
        bSrcExe = TRUE;
    }
    else if ( rc == -1 )
    {
        QuitA( IDS_ENGERR_01, "original source", szSrcImage);
    }
    else if ( rc == NOTEXE )
    {
        if ( ShouldBeAnExe( szSrcImage) )
        {
            QuitA( IDS_ENGERR_18, szSrcImage, NULL);
        }
    }
    else
    {
        QuitA( IDS_ENGERR_18, szSrcImage, NULL);
    }

    if ( IsRes( szTargetImage) )
    {
        bTargetExe = FALSE;
    }
    else
    {
        bTargetExe = TRUE;
    }
    
    // check for valid input files
    
    if ( bSrcExe == TRUE && bTargetExe == FALSE )
    {
        if ( nExeType == NTEXE )
        {
            GenerateRESfromRESandTOKandRDFs( szTargetImage,
                                             szTmpInRes,
                                             szTOK,
                                             szRDFs,
                                             FALSE);
            return 1;
        }
        else
        {
            return -1;  //... Can not generate a win16 .RES  (yet)
        }
    }
    
    if ( bSrcExe == FALSE && bTargetExe == TRUE )
    {
        // can not go from res to exe
        return -1;
    }
    
    // okay we have valid file inputs, generate image file
    
    if ( bSrcExe )
    {
        // create name for temporary localized resource file
        MyGetTempFileName(0, "RES", 0, szTmpOutRes);
        
        GenerateRESfromRESandTOKandRDFs( szTmpOutRes,
                                         szTmpInRes,
                                         szTOK,
                                         szRDFs,
                                         FALSE);
        
        // now szTmpOutRes file is a localized resource file,
        // place these resources into outputimage file
        // BUGBUG: do we make sure szTargetImage does not exist?

        if ( nExeType == NTEXE )
        {
            rc = BuildExeFromRes32A( szTmpTargetImage, szTmpOutRes, szSrcImage);
        }
        else
        {
//            rc = BuildExeFromRes16A( szTmpTargetImage, szTmpOutRes, szSrcImage);

            remove( szTmpInRes);
            remove( szTmpOutRes);
            remove( szTmpTargetImage);

            QuitT( IDS_ENGERR_16, (LPTSTR)IDS_NOBLDEXERES, NULL);
        }

                                // now clean up temporary files        
        remove( szTmpInRes);
        remove( szTmpOutRes);
        
        if ( rc != 1 )
        {
            remove( szTmpTargetImage);
            QuitT( IDS_ENGERR_16, (LPTSTR)IDS_NOBLDEXERES, NULL);
        }

        if ( ! CopyFileA( szTmpTargetImage, szTargetImage, FALSE) )
        {
            remove( szTmpTargetImage);
            QuitA( IDS_COPYFILE_FAILED, szTmpTargetImage, szTargetImage);
        }
        remove( szTmpTargetImage);

                                // szTargetImage is now generated,
        return 1;
    }
    
    if ( ! bSrcExe )
    {
        // image files are resource files
        if ( szTmpTargetImage[0] )
        {
            GenerateRESfromRESandTOKandRDFs( szTmpTargetImage,
                                             szSrcImage,
                                             szTOK,
                                             szRDFs,
                                             FALSE);
        }
        
        if ( ! CopyFileA( szTmpTargetImage, szTargetImage, FALSE) )
        {
            remove( szTmpTargetImage);
            QuitA( IDS_COPYFILE_FAILED, szTmpTargetImage, szTargetImage);
        }
        remove( szTmpTargetImage);
        
        // sztarget Image is now generated,
        
        return 1;
    }
}




/**
  *  Function GenerateRESfromRESandTOKandRDFs:
  * builds a resource from the token and rdf files
  *
  *  History:
  * 2/92, implemented       SteveBl
  */
void GenerateRESfromRESandTOKandRDFs(

CHAR * szTargetRES,     //... Output exe/res file name
CHAR * szSourceRES,     //... Input  exe/res file name
CHAR * szTOK,           //... Input token file name
CHAR * szRDFs,          //... Custom resource definition file name
WORD wFilter)
{
    FILE * fTok       = NULL;
    FILE * fSourceRes = NULL;
    FILE * fTargetRes = NULL;
    
    LoadCustResDescriptions( szRDFs);
    
    if ( (fTargetRes = FOPEN( szTargetRES, "wb")) != NULL )
    {
        if ( (fSourceRes = FOPEN( szSourceRES, "rb")) != NULL )
        {
            if ( (fTok = FOPEN( szTOK, "rt")) != NULL )
            {
                ReadWinRes( fSourceRes,
                            fTargetRes,
                            fTok,
                            TRUE,        //... Building res/exe file
                            FALSE,       //... Not building token file
                            wFilter);

                FCLOSE( fTok);
                FCLOSE( fSourceRes);
                FCLOSE( fTargetRes);

                ClearResourceDescriptions();
            }
            else
            {
                FCLOSE( fSourceRes);
                FCLOSE( fTargetRes);

                ClearResourceDescriptions();
                QuitA( IDS_ENGERR_01, "token", szTOK);
            }
        }
        else
        {
            FCLOSE( fTargetRes);

            ClearResourceDescriptions();
            QuitA( IDS_ENGERR_20, (LPSTR)IDS_INPUT, szSourceRES);
        }
    }
    else
    {
        ClearResourceDescriptions();
        QuitA( IDS_ENGERR_20, (LPSTR)IDS_OUTPUT, szSourceRES);
    }
}




int GenerateTokFile(

char *szTargetTokFile,      //... Target token file, created or updated here
char *szSrcImageFile,       //... File from which tokens are to be made
BOOL *pbTokensChanged,      //... Set TRUE here if any token changes
WORD  wFilter)
{
    BOOL  bExeFile    = FALSE;
    int   rc          = 0;
    FILE *fTokFile    = NULL;
    FILE *fResFile    = NULL;
    FILE *fTmpTokFile = NULL;
    FILE *fCurTokFile = NULL;
    FILE *fNewTokFile = NULL;
    static char *pchTRes   = NULL;
    static char *pchTTok   = NULL;
    static char *pchTMerge = NULL;


    *pbTokensChanged = FALSE;   //... Assume nothing is changed
    
    rc = IsExe( szSrcImageFile);
    
    if ( rc == NOTEXE )
    {
        if ( ShouldBeAnExe( szSrcImageFile) )
        {
            QuitA( IDS_ENGERR_18, szSrcImageFile, NULL);
        }
        else
        {                       //... Src file must be a .RES file
            bExeFile = FALSE;
            pchTRes  = szSrcImageFile;
        }   
    }
    else
    {
        if ( rc == NTEXE || rc == WIN16EXE )
        {
                                //... Resources are stored in a exe file
                                //... extract resources out of exe file into
                                //... a temporary file.
        
            pchTRes = _tempnam( "", gszTmpPrefix);

            if ( rc == NTEXE )
            {
                rc = ExtractResFromExe32A( szSrcImageFile,
                                           pchTRes,
                                           wFilter);
            }
            else
            {
                QuitA( IDS_ENGERR_19, szSrcImageFile, "16");
//                rc = ExtractResFromExe16A( szSrcImageFile,
//                                           pchTRes,
//                                           wFilter);
            }
           
            if ( rc  != 0 )
            {
                return( 1);
            }
            bExeFile = TRUE;
        }
        else if ( rc == -1 )
        {
            QuitA( IDS_ENGERR_01, "source image", szSrcImageFile);
        }
        else
        {
            QuitA( IDS_ENGERR_18, szSrcImageFile, NULL);
        }
    }

                                //... now extract tokens out of resource file
    
                                //... Open res file

    if ( (fResFile = FOPEN( pchTRes, "rb")) == NULL )
    {
        QuitA( IDS_ENGERR_01, 
               bExeFile ? "temporary resource" : "resource", 
               pchTRes);
    }
                                //... Does the token file already exist?

    if ( NotExistsOrIsEmpty( szTargetTokFile) )
    {
                                //... No, token file does not exist.

        if ( (fTokFile = FOPEN( szTargetTokFile, "wt")) == NULL )
        {
            FCLOSE( fResFile);
            QuitA( IDS_ENGERR_02, szTargetTokFile, NULL);
        }
        ReadWinRes( fResFile,
                    NULL,
                    fTokFile,
                    FALSE,      //... Not building res/exe file
                    TRUE,       //... Building token file
                    wFilter);

        FCLOSE( fResFile);
        FCLOSE( fTokFile);
    }
    else
    {
                                //... token file exists
                                //... create a temporary file, and try to
                                //... merge with existing one

        pchTTok   = _tempnam( "", gszTmpPrefix);
        pchTMerge = _tempnam( "", gszTmpPrefix);
        
                                //... open temporary file name

        if ( (fTmpTokFile = FOPEN( pchTTok, "wt")) == NULL )
        {
            FCLOSE( fResFile);
            QuitA( IDS_ENGERR_02, pchTTok, NULL);
        }
        
                                //... write tokens to temporary file

        ReadWinRes( fResFile,
                    NULL,
                    fTmpTokFile,
                    FALSE,      //... Not building res/exe file
                    TRUE,       //... Building token file
                    wFilter);
        
        FCLOSE( fResFile);
        FCLOSE( fTmpTokFile);
        
                                //... now merge temporary file with existing
                                //... file open temporary token file

        if ( (fTmpTokFile = FOPEN( pchTTok, "rt")) == NULL )
        {
            QuitA( IDS_ENGERR_01, "temporary token", pchTTok);
        }
        
                                //... open current token file

        if ( (fCurTokFile = FOPEN( szTargetTokFile, "rt")) == NULL )
        {
            FCLOSE( fTmpTokFile);
            QuitA( IDS_ENGERR_01, "current token", szTargetTokFile);
        }
        
                                //... open new tok file name

        if ( (fNewTokFile = FOPEN( pchTMerge, "wt")) == NULL )
        {
            FCLOSE( fTmpTokFile);
            FCLOSE( fCurTokFile);
            QuitA( IDS_ENGERR_02, pchTMerge, NULL);
        }                     
        
                                //... Merge current tokens with temporary tokens

        *pbTokensChanged = MergeTokFiles( fNewTokFile,
                                          fCurTokFile,
                                          fTmpTokFile);
        
        FCLOSE( fNewTokFile);
        FCLOSE( fTmpTokFile);
        FCLOSE( fCurTokFile);

                                //... bpTokensChanged, only valid if creating
                                //... master token files so force it to be
                                //... always true if building proj token files.
        
        if ( gbMaster == FALSE )
        {
            *pbTokensChanged = TRUE;
        }
        
        if ( *pbTokensChanged )
        {
            if ( ! CopyFileA( pchTMerge, szTargetTokFile, FALSE) )
            {
                remove( pchTTok);
                remove( pchTMerge);
                RLFREE( pchTMerge);

                QuitA( IDS_COPYFILE_FAILED, pchTMerge, szTargetTokFile);
            }
        }        
        remove( pchTTok);
        remove( pchTMerge);

        RLFREE( pchTTok);
        RLFREE( pchTMerge);
    }
                                //... now szTargetTokFile contains latest
                                //... tokens form szImageFile
                                //... Clean up if we made a temp .RES file
    if ( bExeFile )
    {
        rc = remove( pchTRes);
        RLFREE( pchTRes);
    }
    return( 0);
}



BOOL ResReadBytes(

FILE   *InFile,     //... File to read from
CHAR   *pBuf,       //... Buffer to write to
size_t  dwSize,     //... # bytes to read
DWORD  *plSize)     //... bytes-read counter (or NULL)
{
    size_t dwcRead = 0;


    dwcRead = fread( pBuf, 1, dwSize, InFile);

    if ( dwcRead == dwSize )
    {
        if ( plSize )
        {
            *plSize -= dwcRead;
        }
        return( TRUE);
    }
    return( FALSE);
}


int InsDlgToks( PCHAR szCurToks, PCHAR szDlgToks, WORD wFilter)
{
    CHAR szMrgToks[MAXFILENAME];
    
    FILE * fCurToks = NULL;
    FILE * fDlgToks = NULL;
    FILE * fMrgToks = NULL;
    TOKEN Tok1, Tok2;
    
    MyGetTempFileName(0,"TOK",0,szMrgToks);
    
    fMrgToks = FOPEN(szMrgToks, "w");
    fCurToks = FOPEN(szCurToks, "r");
    fDlgToks = FOPEN(szDlgToks, "r");
    
    if (! (fMrgToks && fCurToks && fDlgToks))
    {
        return -1;
    }
    
    while (!GetToken(fCurToks, &Tok1))                                          
    {
        if (Tok1.wType != wFilter)
        {
            PutToken(fMrgToks, &Tok1);          
            RLFREE(Tok1.szText);                                                  
            continue;
        }
        
        Tok2.wType  = Tok1.wType;
        Tok2.wName  = Tok1.wName;
        Tok2.wID    = Tok1.wID;
        Tok2.wFlag  = Tok1.wFlag;
        Tok2.wLangID    = Tok1.wLangID;
        Tok2.wReserved  =  0 ;
        lstrcpy( Tok2.szType, Tok1.szType);
        lstrcpy( Tok2.szName, Tok1.szName);
        Tok2.szText = NULL;                                                     
        
        if (FindToken(fDlgToks, &Tok2, 0))                                      
        {
            Tok2.wReserved  =  Tok1.wReserved ;
            PutToken(fMrgToks, &Tok2);          
            RLFREE(Tok2.szText);                                                  
        }
        else
        {
            PutToken(fMrgToks, &Tok1);
        }
        RLFREE(Tok1.szText);                                                      
    }
    FCLOSE (fMrgToks);
    FCLOSE (fCurToks);
    
    if ( ! CopyFileA( szMrgToks, szCurToks, FALSE) )
    {
        remove( szDlgToks);
        remove( szMrgToks);
        QuitA( IDS_COPYFILE_FAILED, szMrgToks, szCurToks);
    }
    remove(szMrgToks);
    
    return 1;
}


//+-----------------------------------------------------------------------
//
// MergeTokFiles
//
// Returns: TRUE if a token changed, was added, or was deleted else FALSE
//
// History:
//      7-22-92     stevebl     added return value
//      9-8-92      terryru     changed order of translation/delta tokens
//      01-25-93    MHotchin    Added changes to handle var length token
//                              text.
//------------------------------------------------------------------------

BOOL MergeTokFiles(

FILE *fNewTokFile,      //... Final product of the merge process
FILE *fCurTokFile,      //... The soon-to-be-old current token file
FILE *fTmpTokFile)      //... The token file generated from the updated .EXE
{
    TOKEN Tok1, Tok2;
    BOOL bChangesDetected = FALSE;  //... Set TRUE if any token changes found
    BOOL bChangedText     = FALSE;  //... TRUE if a token's text has changed
    WORD cTokenCount = 0;       //... Count of tokens in the new token file

                                //... Scan through the new token file.  For
                                //... every token in the new token file, find
                                //... the corresponding token in the current
                                //... token file. This process will make sure
                                //... tokens that are no longer in the .EXE
                                //... will not be in the final token file.


    while ( GetToken( fTmpTokFile, &Tok1) == 0 )                                       
    {
        ++cTokenCount;          //... Used in checking for deleted tokens
        bChangedText = FALSE;   //... assume the token did not change

                                //... Copy pertanent data to use in search
        Tok2.wType  = Tok1.wType;
        Tok2.wName  = Tok1.wName;
        Tok2.wID    = Tok1.wID;
        Tok2.wFlag  = Tok1.wFlag;
        Tok2.wLangID    = Tok1.wLangID;
        Tok2.wReserved  = 0;
        Tok2.szText = NULL;
        
        lstrcpy( Tok2.szType, Tok1.szType);
        lstrcpy( Tok2.szName, Tok1.szName);
        
                                //... Now look for the corresponding token

								//If token is Version stamp and szTexts is "Translation",
								//it is 1.0 version format. So ignore it.
		IGNORETRANSLATION:

        if ( FindToken( fCurTokFile, &Tok2, 0) )                                   
        {
            if ( gbMaster && !(Tok2.wReserved & ST_READONLY) )
            {
                if ( _tcscmp( (TCHAR *)Tok2.szText, (TCHAR *)Tok1.szText) )
                {
                                //... Token text changed

								//If the changes are only align info, translate it to the "unchanged" status.
                    int l1, r1, t1, b1, l2, r2, t2, b2;
                    TCHAR   a1[20], a2[20];

                                                   //Cordinates token?
                    if( (Tok1.wType==ID_RT_DIALOG) && (Tok1.wFlag&ISCOR)
                                                   //Including align info?
                        && _stscanf(Tok1.szText,TEXT("%d %d %d %d %s"),
						    &l1,&r1,&t1,&b1,a1) == 5
                                                   //Not including align info?
                        && _stscanf(Tok2.szText,TEXT("%d %d %d %d %s"),
                            &l2,&r2,&t2,&b2,a2) == 4 
                                                   //Cordinates are same?
                        && l1==l2 && r1==r2 && t1==t2 && b1==b2 )
                    {
                        Tok1.wReserved = 0;
                    }
                    else
                    {
								//If token is Version stamp and szTexts is "Translation",
								//it is 1.0 version format. So ignore it.
                    	if ( Tok1.wType == ID_RT_VERSION
                          && !_tcscmp( Tok2.szText, TEXT("Translation")) )
                    	{
                        	if ( Tok2.szText != NULL )
							{
                        		RLFREE( Tok2.szText);
							}
                        	Tok2.szText = NULL;
							Tok2.wFlag = 1;
                        	goto IGNORETRANSLATION;
	                    }
    	                bChangedText = bChangesDetected = TRUE;

        	            Tok1.wReserved = ST_CHANGED|ST_NEW;
            	        Tok2.wReserved = ST_CHANGED;
                    }
                }
                else
                {
                    Tok1.wReserved = 0;
                }
            }    
            else
            {
                Tok1.wReserved = Tok2.wReserved;
            }
        }
        else
        {
                        		//... Must be a new token (not in current token file)

								//If token is Version stump, and old mtk is 1.0 data file, convert it.
            if ( Tok1.wType==ID_RT_VERSION )
            {
                Tok2.szText = NULL;
                Tok2.wFlag = 1; 				   
                _tcscpy( Tok2.szName, TEXT("VALUE") );

                if ( FindToken( fCurTokFile, &Tok2, 0)
                  && ! lstrcmp( Tok1.szText, Tok2.szText) )
                {
                    Tok1.wReserved = Tok2.wReserved;
                }
				else 
					Tok1.wReserved = ST_TRANSLATED | ST_DIRTY;
            }
            else
            {
                Tok1.wReserved = ST_TRANSLATED | ST_DIRTY;
            }										
            bChangesDetected = TRUE;
        }

                        //... Copy token from new token file to final token
                        //... file.  If a change was detected, then copy the
                        //... original token (from the "current" token file
                        //... into the final token file.

        PutToken( fNewTokFile, &Tok1);
        RLFREE( Tok1.szText);                                                      

        if ( bChangedText )
        {
            PutToken( fNewTokFile, &Tok2);
                               // now delta tokens follow translation tokens
        }

        if ( Tok2.szText != NULL )
        {
            RLFREE( Tok2.szText);                                                  
        }
    }
    
    if ( ! bChangesDetected )
    {
        // We have to test to be sure that no tokens were deleted
        // since we know that none changed.

        rewind( fCurTokFile);

                                //... Look for tokens that exist in the current
                                //... token file that do not exist in the token
                                //... file created from the updated .EXE.

        while ( GetToken( fCurTokFile, &Tok1) == 0 )                                   
        {
            --cTokenCount;
            RLFREE( Tok1.szText);
        }

        if ( cTokenCount != 0 )
        {
            bChangesDetected = TRUE;
        }
    }
    return( bChangesDetected);
}


void MakeNewExt(char *NewName, char *OldName, char *ext)
{
    
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];  // dummy vars to hold file name info
    char dext[_MAX_EXT];
    
    
    // Split obj file name into filename and extention
    _splitpath(OldName, drive, dir, fname, dext);
    
    // Make new file name with new ext extention
    _makepath(NewName, drive, dir, fname, ext);
}


//......................................................................
//...
//... Check to see if the given file name *should* be an EXE
//...
//... Return: TRUE if it should, else FALSE.


static BOOL ShouldBeAnExe( PCHAR szFileName)
{
    PCHAR psz;


    if ( (psz = strrchr( szFileName, '.')) != NULL )
    {
        if ( IsRes( szFileName) )
        {
            return( FALSE);
        }
        else if ( lstrcmpiA( psz, ".exe") == 0
               || lstrcmpiA( psz, ".dll") == 0
               || lstrcmpiA( psz, ".com") == 0
               || lstrcmpiA( psz, ".scr") == 0
               || lstrcmpiA( psz, ".cpl") == 0 )
        {
            return( TRUE);
		}
								//... Because we think this case of filename
								//... would be not executable file rather than res file.
        else if ( lstrcmpiA( psz, ".tmp") == 0 ) //for tmp file created by Dlgedit
        {
            return( FALSE );
        }
        else
        {
            return( TRUE );
        }
    }
    return( FALSE);
}

//.........................................................
//...
//... If the named file exists and is not empty, return FALSE, else TRUE.

static BOOL NotExistsOrIsEmpty( PCHAR pszFileName)
{
    BOOL fRC = TRUE;
    int  hFile = -1;

                                //... Does file not exist?

    if ( _access( pszFileName, 0) == 0 )
    {
                                //... No, file exists.  Open it.

        if ( (hFile = _open( pszFileName, _O_RDONLY)) != -1 )
        {
                                //... Is it Empty?

            if ( _filelength( hFile) == 0L )
            {
                fRC = TRUE;     //... Yes, file is empty.
            }
            else
            {
                fRC = FALSE;    //... No, file is not empty.
            }
            _close( hFile);
        }
        else
        {
            QuitA( IDS_ENGERR_01, "non-empty", pszFileName);
        }
    }
    else
    {                                
        fRC = TRUE;             //... Yes, file does not exist.
    }
    return( fRC);
}