//+---------------------------------------------------------------------------
//
//  File:   win16.cpp
//
//  Contents:   Implementation for the Windows 16 Read/Write module
//
//  Classes:    one
//
//  History:    26-July-93   alessanm    created
//
//----------------------------------------------------------------------------

#include <afxwin.h>
#include "..\common\rwdll.h"
#include "newexe.h"
#include <stdio.h>

#include <limits.h>

/////////////////////////////////////////////////////////////////////////////
// Initialization of MFC Extension DLL

#include "afxdllx.h"    // standard MFC Extension DLL routines

static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };

/////////////////////////////////////////////////////////////////////////////
// General Declarations
#define MODULENAME "RWWin16.dll"
#define RWTAG "WIN16"

#define LPNULL 0L
#define Pad16(x) ((((x+15)>>4)<<4)-x)
#define Pad4(x) ((((x+3)>>2)<<2)-x)

#define MAXSTR 300 
#define MAXID 128
#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_WIN_SIGNATURE                 0x454E      // NE

#define VB					// RCDATA process for VB only - WB
#ifdef VB
static const RES_SIGNATURE = 0xA5;	// identifier for VB entry
#endif


// Code pages
#define CP_ASCII7   0       // 7-bit ASCII
#define CP_JIS      932     // Japan (Shift - JIS X-0208)
#define CP_KSC      949     // Korea (Shift - KSC 5601)
#define CP_GB5      950     // Taiwan (GB5)
#define CP_UNI      1200    // Unicode
#define CP_EE       1250    // Latin-2 (Eastern Europe)
#define CP_CYR      1251    // Cyrillic
#define CP_MULTI    1252    // Multilingual
#define CP_GREEK    1253    // Greek
#define CP_TURK     1254    // Turkish
#define CP_HEBR     1255    // Hebrew
#define CP_ARAB     1256    // Arabic

/////////////////////////////////////////////////////////////////////////////
// General type Declarations
typedef unsigned char UCHAR;

typedef UCHAR * PUCHAR;

typedef struct ver_block {
    WORD wBlockLen;
    WORD wValueLen;
    WORD wType;         
    WORD wHead;
    BYTE far * pValue;
    char szKey[100];
    char szValue[300];
} VER_BLOCK;

/////////////////////////////////////////////////////////////////////////////
// Function Declarations

static UINT GetResInfo( 
                 CFile*,
                 WORD* wTypeId, LPSTR lplpszTypeId, BYTE bMaxTypeLen,
                 WORD* wNameId, LPSTR lplpszNameId, BYTE bMaxNameLen,
                 WORD* pwFlags,
                 DWORD* dwSize, DWORD* dwFileOffset );
             
static UINT WriteHeader( 
                 CFile*,
                 WORD wTypeId, LPSTR lpszTypeId,
                 WORD wNameId, LPSTR lpszNameId,
                 WORD wFlags );
             
static UINT WriteImage( 
                 CFile*,
                 LPVOID lpImage, DWORD dwSize );
             
static UINT GetUpdatedRes( 
                 LPVOID far * lplpBuffer,
                 UINT* uiSize,
                 WORD* wTypeId, LPSTR lplpszTypeId,
                 WORD* wNameId, LPSTR lplpszNameId,
                 DWORD* dwlang, DWORD* dwSize );
            
static UINT GetUpdatedItem( 
                 LPVOID far * lplpBuffer,
                 LONG* dwSize,
                 WORD* wX, WORD* wY,
                 WORD* wcX, WORD* wcY,
                 DWORD* dwPosId, 
                 DWORD* dwStyle, DWORD* dwExtStyle, 
                 LPSTR lpszText);

static int GetVSBlock( BYTE far * far * lplpImage, LONG* pdwSize, VER_BLOCK* pverBlock);
static int PutVSBlock( BYTE far * far * lplpImage, LONG* pdwSize, VER_BLOCK verBlock, 
                       LPSTR lpStr, BYTE far * far * lplpBlockSize, WORD* pwPad);

/////////////////////////////////////////////////////////////////////////////
// Helper Function Declarations
static UINT CopyFile( CFile* filein, CFile* fileout );
static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen );
static UINT ParseMenu( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseString( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseDialog( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseCursor( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseIcon( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseBitmap( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
static UINT ParseAccel( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
#ifdef VB
static UINT ParseVBData(  LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );
#endif
static UINT ParseVerst( LPVOID lpImageBuf, DWORD dwImageSize,  LPVOID lpBuffer, DWORD dwSize );

static UINT GenerateFile( LPCSTR        lpszTgtFilename,
                          HANDLE        hResFileModule,
                          LPVOID        lpBuffer,
                          UINT      uiSize,
                          HINSTANCE   hDllInst
                        );


static UINT UpdateMenu( LPVOID lpNewBuf, LONG dwNewSize,  
                        LPVOID lpOldImage, LONG dwOldImageSize,
                        LPVOID lpNewImage, DWORD* pdwNewImageSize );
static UINT GenerateMenu( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpNewImage, DWORD* pdwNewImageSize );
static UINT UpdateString( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpOldI, LONG dwOldImageSize,
                          LPVOID lpNewI, DWORD* pdwNewImageSize );
static UINT GenerateString( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpNewImage, DWORD* pdwNewImageSize );

static UINT UpdateDialog( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpOldI, LONG dwOldImageSize,
                          LPVOID lpNewI, DWORD* pdwNewImageSize );
static UINT GenerateDialog( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpNewImage, DWORD* pdwNewImageSize );
                      
static UINT UpdateAccel(LPVOID lpNewBuf, LONG dwNewSize,  
                        LPVOID lpOldImage, LONG dwOldImageSize,
                        LPVOID lpNewImage, DWORD* pdwNewImageSize );
#ifdef VB
static UINT UpdateVBData( LPVOID lpNewBuf, LONG dwNewSize,
                          LPVOID lpOldI, LONG dwOldImageSize,
                          LPVOID lpNewI, DWORD* pdwNewImageSize );
#endif

static UINT UpdateVerst( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpOldI, LONG dwOldImageSize,
                          LPVOID lpNewI, DWORD* pdwNewImageSize );


static BYTE SkipByte( BYTE far * far * lplpBuf, UINT uiSkip, LONG* pdwRead );

static BYTE PutDWord( BYTE far * far* lplpBuf, DWORD dwValue, LONG* pdwSize );
static BYTE PutWord( BYTE far * far* lplpBuf, WORD wValue, LONG* pdwSize );
static BYTE PutByte( BYTE far * far* lplpBuf, BYTE bValue, LONG* pdwSize ); 
static UINT PutString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize );
static UINT PutPascalString( BYTE far * far* lplpBuf, LPSTR lpszText, BYTE bLen, LONG* pdwSize );
static UINT PutNameOrOrd( BYTE far * far* lplpBuf, WORD wOrd, LPSTR lpszText, LONG* pdwSize );
static UINT PutCaptionOrOrd( BYTE far * far* lplpBuf, WORD wOrd, LPSTR lpszText, LONG* pdwSize,
							 BYTE bClass, DWORD dwStyle );
static UINT PutClassName( BYTE far * far* lplpBuf, BYTE bClass, LPSTR lpszText, LONG* pdwSize );
static UINT PutControlClassName( BYTE far * far* lplpBuf, BYTE bClass, LPSTR lpszText, LONG* pdwSize );

static BYTE GetDWord( BYTE far * far* lplpBuf, DWORD* dwValue, LONG* pdwSize );
static BYTE GetWord( BYTE far * far* lplpBuf, WORD* wValue, LONG* pdwSize );
static BYTE GetByte( BYTE far * far* lplpBuf, BYTE* bValue, LONG* pdwSize );
static UINT GetNameOrOrd( BYTE far * far* lplpBuf, WORD* wOrd, LPSTR lpszText, LONG* pdwSize );
static UINT GetCaptionOrOrd( BYTE far * far* lplpBuf, WORD* wOrd, LPSTR lpszText, LONG* pdwSize,
							 BYTE wClass, DWORD dwStyle );
static UINT GetString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize );               
static UINT GetClassName( BYTE far * far* lplpBuf, BYTE* bClass, LPSTR lpszText, LONG* pdwSize );
static UINT GetControlClassName( BYTE far * far* lplpBuf, BYTE* bClass, LPSTR lpszText, LONG* pdwSize );
static UINT CopyText( BYTE far * far * lplpTgt, BYTE far * far * lplpSrc, LONG* pdwTgtSize, LONG* pdwSrcSize);
static int  GetVSString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize, int cMaxLen );
static LPRESITEM GetItem( BYTE far * lpBuf, LONG dwNewSize, LPSTR lpStr );
static DWORD CalcID( WORD wId, BOOL bFlag );
static DWORD GenerateTransField( WORD wLang, BOOL bReverse );
static void GenerateTransField( WORD wLang, VER_BLOCK * pVer );
static void ChangeLanguage( LPVOID, UINT );
// Allignment helpers
static LONG Allign( BYTE * * lplpBuf, LONG* plBufSize, LONG lSize );

/////////////////////////////////////////////////////////////////////////////
// Global variables
static BYTE sizeofByte = sizeof(BYTE);
static BYTE sizeofWord = sizeof(WORD);
static BYTE sizeofDWord = sizeof(DWORD);
static CWordArray wIDArray;
static DWORD    gLang = 0;
/////////////////////////////////////////////////////////////////////////////
// Public C interface implementation

//[registration]                                    
extern "C"
BOOL    FAR PASCAL RWGetTypeString(LPSTR lpszTypeName)
{   
    strcpy( lpszTypeName, RWTAG ); 
    return FALSE;
}

extern "C"
BOOL    FAR PASCAL RWValidateFileType   (LPCSTR lpszFilename)
{
    UINT uiError = ERROR_NO_ERROR;
    CFile file;
    WORD w;
    
    // we Open the file to see if it is a file we can handle
    if (!file.Open( lpszFilename, CFile::shareDenyNone | CFile::typeBinary | CFile::modeRead )) 
        return FALSE;

    // Read the file signature
    file.Read((WORD*)&w, sizeof(WORD));
    if (w==IMAGE_DOS_SIGNATURE) {
        file.Seek( 0x18, CFile::begin );
        file.Read((WORD*)&w, sizeof(WORD));
        if (w<0x0040) {
            // this is not a Windows Executable
            file.Close();
            return FALSE;   
        }                                     
        // get offset to header
        file.Seek( 0x3c, CFile::begin );
        file.Read((WORD*)&w, sizeof(WORD));

        // Read header
        new_exe ne;
        file.Seek( w, CFile::begin );
        file.Read(&ne, sizeof(new_exe));     
        if (NE_MAGIC(ne)==LOWORD(IMAGE_WIN_SIGNATURE)) {
            // this is a Windows Executable
            // we can handle the situation
            file.Close();
            return TRUE;     
        }
    }
    file.Close();       
    return FALSE;
}


extern "C"
UINT
APIENTRY 
RWReadTypeInfo(
    LPCSTR lpszFilename,
    LPVOID lpBuffer,
    UINT* puiSize

    )   
{                                   
    UINT  uiError = ERROR_NO_ERROR;
    BYTE  far * lpBuf = (BYTE far *)lpBuffer;
    DWORD uiBufSize = *puiSize;

    // we can consider the use of a CMemFile so we get the same speed as memory access.
    CFile file;
    WORD i;
    WORD wAlignShift;
    WORD w, wResCount;
    WORD wWinHeaderOffset, wResTableOffset;
    WORD wCurTypeOffset, wCurNameOffset;
    BYTE nCount; 

    WORD wTypeId; DWORD dwTypeId;
    static char szTypeId[128];

    WORD wNameId;
    static char szNameId[128];
                 
    WORD  wSize, wFileOffset;         
    DWORD dwSize,dwFileOffset;
    WORD  wResidentOffset;
    DWORD dwVerStampOffset = 0xffffffff; 
    DWORD dwVerStampSize = 0; 
                     
    UINT uiOverAllSize = 0;
    

    if (!RWValidateFileType(lpszFilename))
        return ERROR_RW_INVALID_FILE;

    // Open the file and try to read the information on the resource in it.
    if (!file.Open(lpszFilename, CFile::shareDenyNone | CFile::modeRead | CFile::typeBinary))
        return ERROR_FILE_OPEN;

    // we try to read as much information as we can
    // Because this is a exe file we can read all the information we need.

    file.Read((WORD*)&w, sizeof(WORD)); 
    if (w!=IMAGE_DOS_SIGNATURE) return ERROR_RW_INVALID_FILE;

    file.Seek( 0x18, CFile::begin );
    file.Read((WORD*)&w, sizeof(WORD));
    if (w<0x0040) {
        // this is not a Windows Executable
        file.Close();
        return ERROR_RW_INVALID_FILE;   
    }                                     

    // Get offset to Windows new header
    file.Seek( 0x3c, CFile::begin );
    file.Read((WORD*)&wWinHeaderOffset, sizeof(WORD));

    // Read and save Windows header Offset
    file.Seek( wWinHeaderOffset, CFile::begin );

    // Read header
    new_exe ne;
    file.Read(&ne, sizeof(new_exe));     
    if (NE_MAGIC(ne)!=LOWORD(IMAGE_WIN_SIGNATURE)) {
        // this is not a Windows Executable
        file.Close();
        return ERROR_RW_INVALID_FILE;     
    }

    // this is a Windows 16 Executable
    // we can handle the situation
    // Later we want to check for the file type 

    // Location 24H inside of the Windows header has the relative offset from 
    // the beginning of the Windows header to the beginning of the resource table
    file.Seek (wWinHeaderOffset+0x24, CFile::begin);
    file.Read ((WORD*)&wResTableOffset, sizeof(WORD));
    file.Read ((WORD*)&wResidentOffset, sizeof(WORD));

    // Check if there are resources
    if (wResTableOffset == wResidentOffset) {
        file.Close ();
        return ERROR_RW_NO_RESOURCES;        
    }

    // Read the resurce table
    new_rsrc rsrc;
    file.Seek (wWinHeaderOffset+NE_RSRCTAB(ne), CFile::begin);
    file.Read (&rsrc, sizeof(new_rsrc));
    
    WORD rsrc_size = NE_RESTAB(ne)-NE_RSRCTAB(ne);

    // Read and save alignment shift count    
    file.Seek (wWinHeaderOffset+wResTableOffset, CFile::begin);
    file.Read ((WORD*)&wAlignShift, sizeof(WORD));

    // Read the first type ID
    file.Read ((WORD*)&wTypeId, sizeof(WORD));

    // Save the Offset of the current TypeInfo record
    wCurTypeOffset = wWinHeaderOffset + wResTableOffset + 2;

    // reset the global language 
    gLang = 0;

    // Process TypeInfo records while there are TypeInfo record left
    while (wTypeId) {
        // Get Name of ord 
        if (!(wTypeId & 0x8000)) {
            // It is a Offset to a string
            dwTypeId = (MAKELONG(wTypeId, 0)); //<<wAlignShift;     
            file.Seek (wWinHeaderOffset+wResTableOffset+dwTypeId, CFile::begin);
            // Get the character count for the ID string
            file.Read ((BYTE*)&nCount, sizeof(BYTE));
            // Read the ID string
            file.Read (szTypeId, nCount);
            // Put null at the end of the string
            szTypeId[nCount] = 0;

            if (0 == strlen(szTypeId))
        		return ERROR_RW_INVALID_FILE;

            // Set wTypeId to zero
            wTypeId = 0;                
        }
        else { 
            // It is an ID 
            // Turn off the high bit
            wTypeId = wTypeId & 0x7FFF; 
            if (0 == wTypeId)
        		return ERROR_RW_INVALID_FILE;
        
            // Set the ID string to null 
            szTypeId[0] = 0;
        }

        // Restore the file read point
        file.Seek (wCurTypeOffset+2, CFile::begin);
            
        // Get the count for this type of resource
        file.Read ((WORD*)&wResCount, sizeof(WORD));
    
        // Pass the reserved DWORD
        file.Seek (4, CFile::current);
    
        // Save the Offset of the current NameInfo record       
        wCurNameOffset = wCurTypeOffset + 8;
    
        // Process NameInfo records
        for (i = 0; i < wResCount; i++) {
            file.Read ((WORD*)&wFileOffset, sizeof(WORD));
            file.Read ((WORD*)&wSize, sizeof(WORD)); 
            // Pass the flags
            file.Seek (2, CFile::current);
            file.Read ((WORD*)&wNameId, sizeof(WORD));
        
            // Get name of ord
            if (!(wNameId & 0x8000)) {
                // It is a Offset to a string            
                file.Seek (wWinHeaderOffset+wResTableOffset+wNameId, CFile::begin);
                // Get the character count for the string
                file.Read ((BYTE*)&nCount, sizeof(BYTE));
                // Read the string
                file.Read (szNameId, nCount);
                // Put null at the end of the string
                szNameId[nCount] = 0;
                // Set wNameId to zero
                wNameId = 0;                
            }
            else { 
                // It is an ID 
                // Turn off the high bit
                wNameId = wNameId & 0x7FFF; 
          		if (0 == wNameId)
               		return ERROR_RW_INVALID_FILE;
            
                // Set the string to null 
                szNameId[0] = 0;
            }
                        
            dwSize = (MAKELONG (wSize, 0))<<wAlignShift;
//          dwSize = MAKELONG (wSize, 0);
            dwFileOffset = (MAKELONG (wFileOffset, 0))<<wAlignShift;
        
            // Put the data into the buffer
        
            uiOverAllSize += PutWord( &lpBuf, wTypeId, (LONG*)&uiBufSize );
            uiOverAllSize += PutString( &lpBuf, szTypeId, (LONG*)&uiBufSize );
	     	// Check if it is alligned
	     	uiOverAllSize += Allign( &lpBuf, (LONG*)&uiBufSize, (LONG)uiOverAllSize);
    
            uiOverAllSize += PutWord( &lpBuf, wNameId, (LONG*)&uiBufSize );
            uiOverAllSize += PutString( &lpBuf, szNameId, (LONG*)&uiBufSize );
	     	// Check if it is alligned
	     	uiOverAllSize += Allign( &lpBuf, (LONG*)&uiBufSize, (LONG)uiOverAllSize);
    
            uiOverAllSize += PutDWord( &lpBuf, gLang, (LONG*)&uiBufSize );
    
            uiOverAllSize += PutDWord( &lpBuf, dwSize, (LONG*)&uiBufSize );
    
            uiOverAllSize += PutDWord( &lpBuf, dwFileOffset, (LONG*)&uiBufSize );                                              
        
            TRACE("WIN16: Type: %hd\tName: %hd\tOffset: %lX\n", wTypeId, wNameId, dwFileOffset);
            
            // Check if this is the Version stamp block and save the offset to it
            if(wTypeId==16)
            {
                dwVerStampOffset = dwFileOffset;
                dwVerStampSize = dwSize;
            }

            // Update the current NameInfo record offset
            wCurNameOffset = wCurNameOffset + 12;
            // Move file pointer to the next NameInfo record
            file.Seek (wCurNameOffset, CFile::begin);               
        } 
    
        // Update the current TypeInfo record offset
        wCurTypeOffset = wCurTypeOffset + 8 + wResCount * 12;  
        // Move file pointer to the next TypeInfo record
        file.Seek (wCurTypeOffset, CFile::begin);
        // Read the next TypeId
        file.Read ((WORD*)&wTypeId, sizeof(WORD));
    }

    // Now do we have a VerStamp Offset
    if(dwVerStampOffset!=0xffffffff)
    {
        // Let's get the language ID and touch the buffer with the new information
        file.Seek (dwVerStampOffset, CFile::begin);               

        
        DWORD  dwBuffSize = dwVerStampSize;
        char * pBuff = new char[dwVerStampSize+1];
        char * pTrans = pBuff;
        file.Read(pBuff, dwVerStampSize);
        
        while( pTrans = (LPSTR)memchr(pTrans, 'T', dwBuffSize) )
        {               
            if(!memcmp( pTrans, "Translation", 11))
            {
                pTrans = pTrans + 12;
                gLang = (WORD)*((WORD*)pTrans);
                break;    
            }

            dwBuffSize = ++pTrans - pBuff;
        }
        
        delete pBuff;

        if(gLang!=0)
        {
            // walk the buffer and change the language id
            ChangeLanguage(lpBuffer, uiOverAllSize);
        }
    }

    file.Close();
    *puiSize = uiOverAllSize;
    return uiError;
}

extern "C"
DWORD
APIENTRY   
RWGetImage(
    LPCSTR  lpszFilename,
    DWORD   dwImageOffset,
    LPVOID  lpBuffer,
    DWORD   dwSize
    )
{   
    UINT uiError = ERROR_NO_ERROR;
    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    DWORD dwBufSize = dwSize;
    // we can consider the use of a CMemFile so we get the same speed as memory access.
    CFile file;
        
    // Open the file and try to read the information on the resource in it.
    if (!file.Open(lpszFilename, CFile::shareDenyNone | CFile::modeRead | CFile::typeBinary)) {
        return (DWORD)ERROR_FILE_OPEN;
     }

    if ( dwImageOffset!=(DWORD)file.Seek( dwImageOffset, CFile::begin) )
        return (DWORD)ERROR_FILE_INVALID_OFFSET;
    if (dwSize>UINT_MAX) {
        // we have to read the image in different steps
        return (DWORD)0L;
    } else uiError = file.Read( lpBuf, (UINT)dwSize);
    file.Close();    

    return (DWORD)uiError;
}

extern "C"
UINT
APIENTRY   
RWParseImage(
    LPCSTR  lpszType,
    LPVOID  lpImageBuf,
    DWORD   dwImageSize,
    LPVOID  lpBuffer,
    DWORD   dwSize
    )
{
    UINT uiError = ERROR_NO_ERROR;
    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    DWORD dwBufSize = dwSize;
    
    // The Type we can parse are only the standard ones
    // This function should fill the lpBuffer with an array of ResItem structure
    switch ((UINT)LOWORD(lpszType)) {
        case 1: 
            uiError = ParseCursor( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;

        case 2: 
            uiError = ParseBitmap( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;

        case 3: 
            uiError = ParseIcon( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;
    
        case 4: 
            uiError = ParseMenu( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;

        case 5: 
            uiError = ParseDialog( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;

        case 6: 
            uiError = ParseString( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;
    
        case 9: 
            uiError = ParseAccel( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;                                                                 
#ifdef VB
		case 10:
			uiError = ParseVBData(  lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;
#endif


        case 16: 
            uiError = ParseVerst( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
        break;
    
        default:
        break;
    }

    return uiError;
}                      

extern"C"
UINT    
APIENTRY   
RWWriteFile(
    LPCSTR      lpszSrcFilename,
    LPCSTR      lpszTgtFilename,
    HANDLE      hResFileModule,
    LPVOID      lpBuffer,
    UINT        uiSize,
    HINSTANCE   hDllInst
    )
{   
    UINT uiError = ERROR_NO_ERROR;
    BYTE far * lpBuf = LPNULL;
    UINT uiBufSize = uiSize;
    // we can consider the use of a CMemFile so we get the same speed as memory access.
    CFile fileIn;
    CFile fileOut;
    BOOL  bfileIn = TRUE;

    WORD wTypeId;  DWORD dwTypeId;
    char szTypeId[128];

    WORD wNameId;  
    char szNameId[128];

    DWORD dwSize;
    DWORD dwFileOffset;

    WORD wUpdTypeId = 0;
    static char szUpdTypeId[128];

    static char szUpdNameId[128];     

    UINT uiBufStartSize = uiBufSize;
    DWORD dwImageBufSize = 0L;
    BYTE far * lpImageBuf = 0L; 

    WORD wWinHeaderOffset = 0;
    WORD wResTableOffset = 0;
    WORD wCurTypeOffset = 0;
    WORD wFileOffset  = 0;
    WORD wSize = 0;
    WORD wCurNameOffset = 0;  
    WORD wAlignShift = 0;
    WORD wResDataOffset = 0;
    WORD wResDataBegin = 0;
    WORD wCurResDataBegin = 0;
    DWORD dwResDataBegin = 0L;
    DWORD dwCurResDataBegin = 0L;
    WORD i = 0; short j = 0L; WORD wResCount = 0L;  
    BYTE nCharCount = 0;    
    short delta = 0;
    WORD wFlags = 0; WORD wLoadOnCallResDataBegin = 0;
    WORD wNumOfSegments  = 0;
    WORD wSegmentTableOffset = 0;
    WORD wOffset = 0;
    WORD wLoadOnCallCodeBegin = 0;
    DWORD dwLoadOnCallCodeBegin = 0L;    
    DWORD (FAR PASCAL    * lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD);
                       
    // Open the file and try to read the information on the resource in it.
    CFileStatus status;
    if (CFile::GetStatus( lpszSrcFilename, status )) {
        // check if the size of the file is not null
        if (!status.m_size)
            CFile::Remove(lpszSrcFilename);
    }

    if (!fileIn.Open(lpszSrcFilename, CFile::shareDenyNone | CFile::modeRead | CFile::typeBinary))
        return GenerateFile(lpszTgtFilename,
                            hResFileModule,
                            lpBuffer,
                            uiSize,
                            hDllInst
                            );

    if (!fileOut.Open(lpszTgtFilename, CFile::shareDenyNone | CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
        return ERROR_FILE_CREATE;

    // Get the handle to the IODLL 
  	hDllInst = LoadLibrary("iodll.dll");

    if (!hDllInst) 
        return ERROR_DLL_LOAD;

    // Get the pointer to the function to extract the resources image
    lpfnGetImage = (DWORD (FAR PASCAL   *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD))
                        GetProcAddress( hDllInst, "RSGetResImage" );
    if (lpfnGetImage==NULL) {
        FreeLibrary(hDllInst);
        return ERROR_DLL_PROC_ADDRESS;
    }

    // We read the resources from the file and then we check if the resource has been updated
    // or if we can just copy it

    // Get offset to Windows new header
    fileIn.Seek( 0x3c, CFile::begin );
    fileIn.Read((WORD*)&wWinHeaderOffset, sizeof(WORD));

    // Read and save resource table Offset
    fileIn.Seek( wWinHeaderOffset+0x24, CFile::begin );
    fileIn.Read ((WORD*)&wResTableOffset, sizeof(WORD));
             
    // Read AlignShift  
    fileIn.Seek (wWinHeaderOffset+wResTableOffset, CFile::begin);
    fileIn.Read ((WORD*)&wAlignShift, sizeof(WORD));

    // Get the beginning of the resource data                             
    wResDataBegin = 0xffff;                             
    wLoadOnCallResDataBegin = 0xffff;
    fileIn.Read((WORD*)&wTypeId, sizeof(WORD));
    while (wTypeId) {
        fileIn.Read ((WORD*)&wResCount, sizeof(WORD)); 
        // Pass the reserved DWORD
        fileIn.Seek (4, CFile::current);

        for (i=0; i<wResCount; i++) {
            fileIn.Read ((WORD*)&wResDataOffset, sizeof(WORD));
            fileIn.Seek (2, CFile::current);
            fileIn.Read ((WORD*)&wFlags, sizeof(WORD));
            if (wResDataOffset>0) {
                if (wFlags & 0x0040)
                    wResDataBegin = (wResDataOffset < wResDataBegin) ? wResDataOffset:wResDataBegin;
                else
                    wLoadOnCallResDataBegin = (wResDataOffset < wLoadOnCallResDataBegin) ? wResDataOffset:wLoadOnCallResDataBegin;
            }
            // Get to next NameInfo record
            fileIn.Seek (6, CFile::current);
        }
        fileIn.Read ((WORD*)&wTypeId, sizeof(WORD));
    }

    // Copy data before resource data
    fileIn.SeekToBegin ();
    fileOut.SeekToBegin ();
    CopyFile (&fileIn, &fileOut);

    if (wResDataBegin != 0xffff) { // If there are PreLoad resources
        dwResDataBegin = (MAKELONG (wResDataBegin, 0))<<wAlignShift;
    
        // Read the first type ID
        fileIn.Seek (wWinHeaderOffset+wResTableOffset+2, CFile::begin);
        fileIn.Read ((WORD*)&wTypeId, sizeof(WORD));
    
        // Save the Offset of the current TypeInfo record
        wCurTypeOffset = wWinHeaderOffset + wResTableOffset + 2;
    
        // Save the beginning of current resource data
        dwCurResDataBegin = dwResDataBegin; 
    
        // Loop through the TypeInfo table to write PreLoad resources
        while(wTypeId) {
            // Get Name of ord 
            if (!(wTypeId & 0x8000)) {
                // It is a Offset to a string                             
                dwTypeId = (MAKELONG(wTypeId, 0)); //<<wAlignShift;   
                fileIn.Seek (wWinHeaderOffset+wResTableOffset+dwTypeId, CFile::begin);
                // Get the character count for the ID string
                fileIn.Read ((BYTE*)&nCharCount, sizeof(BYTE));
                // Read the ID string
                fileIn.Read (szTypeId, nCharCount);
                // Put null at the end of the string
                szTypeId[nCharCount] = 0;
                // Set wTypeId to zero
                wTypeId = 0;                
            }
            else { 
                // It is an ID 
                // Turn off the high bit
                wTypeId = wTypeId & 0x7FFF; 
                if (0 == wTypeId)
                    return ERROR_RW_INVALID_FILE;
            
                // Set the ID string to null 
                szTypeId[0] = 0;
            }

            // Restore the file read point
            fileIn.Seek (wCurTypeOffset+2, CFile::begin);
                
            // Get the count for this type of resource
            fileIn.Read ((WORD*)&wResCount, sizeof(WORD));
        
            // Pass the reserved DWORD
            fileIn.Seek (4, CFile::current);
        
            // Save the Offset of the current NameInfo record       
            wCurNameOffset = wCurTypeOffset + 8;
        
            // Loop through NameInfo records
            for (i = 0; i < wResCount; i++) {
                // Read resource offset
                fileIn.Read ((WORD*)&wFileOffset, sizeof(WORD));
                // Read resource length
                fileIn.Read ((WORD*)&wSize, sizeof(WORD));
                // Read the flags
                fileIn.Read ((WORD*)&wFlags, sizeof(WORD));
                // Read resource ID
                fileIn.Read ((WORD*)&wNameId, sizeof(WORD));
            
                if (wFlags & 0x0040)
                {
                    // Get name of ord
                    if (!(wNameId & 0x8000)) {
                        // It is a Offset to a string
                        fileIn.Seek (wWinHeaderOffset+wResTableOffset+wNameId, CFile::begin);
                        // Get the character count for the string
                        fileIn.Read ((BYTE*)&nCharCount, sizeof(BYTE));
                        // Read the string
                        fileIn.Read (szNameId, nCharCount);
                        // Put null at the end of the string
                        szNameId[nCharCount] = 0;
                        // Set wNameId to zero
                        wNameId = 0;                
                    }
                    else { 
                        // It is an ID 
                        // Turn off the high bit
                        wNameId = wNameId & 0x7FFF; 
                        if( 0 == wNameId)
                            return ERROR_RW_INVALID_FILE;
                         
                        // Set the string to null 
                        szNameId[0] = 0;
                    }
                                
                    dwSize = (MAKELONG (wSize, 0))<<wAlignShift;   
                    dwFileOffset = (MAKELONG (wFileOffset, 0))<<wAlignShift;
                
                    // Now we got the Type and Name here and size
                
                    // Get the image from the IODLL
                    if(dwSize)
                    	lpImageBuf = new BYTE[dwSize]; 
					else lpImageBuf = LPNULL;
                    LPSTR   lpType = LPNULL;
                    LPSTR   lpRes = LPNULL;
                
                    if (wTypeId)            
                        lpType = (LPSTR)((WORD)wTypeId);
                    else
                        lpType = &szTypeId[0];
                
                    if (wNameId)
                        lpRes = (LPSTR)((WORD)wNameId);
                    else
                        lpRes = &szNameId[0];
                    
                    dwImageBufSize = (*lpfnGetImage)(  hResFileModule,
                                                    lpType,
                                                    lpRes,
                                                    (DWORD)-1,
                                                    lpImageBuf,
                                                    dwSize
                                                    );
    
                    if (dwImageBufSize>dwSize ) {
                        // The buffer is too small             
                        delete []lpImageBuf;
                        lpImageBuf = new BYTE[dwImageBufSize];
                        dwSize = (*lpfnGetImage)(  hResFileModule,
                                                        lpType,
                                                        lpRes,
                                                        (DWORD)-1,
                                                        lpImageBuf,
                                                        dwImageBufSize
                                                       );
                        if ((dwSize-dwImageBufSize)!=0 ) {  
                            delete []lpImageBuf;
                            lpImageBuf = LPNULL;
                        }
                    }
                
                    // Try to see if we have to set the memory to 0
                    if ((int)(dwSize-dwImageBufSize)>0)
                        memset(lpImageBuf+dwImageBufSize, 0, (size_t)(dwSize-dwImageBufSize));
                
                    // Write the image
                    fileOut.Seek (dwCurResDataBegin, CFile::begin); 
                    WriteImage( &fileOut, lpImageBuf, dwSize);      
                                     

                    // Fix the alignment for resource data   
                    delta = (short)((((dwSize+(1<<wAlignShift)-1)>>wAlignShift)<<wAlignShift)-dwSize);
                    BYTE nByte = 0;                                     
                
                    fileOut.Seek (dwCurResDataBegin+dwSize, CFile::begin);          
                    for (j=0; j<delta; j++)
                        fileOut.Write ((BYTE*)&nByte, sizeof(BYTE));
                                                                           
                    dwSize = dwSize + MAKELONG(delta, 0);
    
                    // Fixup the resource table
                    fileOut.Seek (wCurNameOffset, CFile::begin);
                    wCurResDataBegin = LOWORD(dwCurResDataBegin>>wAlignShift);
                    fileOut.Write ((WORD*)&wCurResDataBegin, sizeof(WORD));
                    wSize = LOWORD (dwSize>>wAlignShift);
                    fileOut.Write ((WORD*)&wSize, sizeof(WORD));
    
                    if (lpImageBuf) delete []lpImageBuf;                                           
                                               
                    // Update the current resource data beginning
                    dwCurResDataBegin = dwCurResDataBegin + dwSize;
                }
            
                // Update the current NameInfo record offset
                wCurNameOffset = wCurNameOffset + 12;
                // Move file pointer to the next NameInfo record
                fileIn.Seek (wCurNameOffset, CFile::begin);             
            } 
        
            // Update the current TypeInfo record offset
            wCurTypeOffset = wCurTypeOffset + 8 + wResCount * 12;  
            // Move file pointer to the next TypeInfo record
            fileIn.Seek (wCurTypeOffset, CFile::begin);
            // Read the next TypeId
            fileIn.Read ((WORD*)&wTypeId, sizeof(WORD));
        }
    }                      
                   
    // Get segment table offset
    fileIn.Seek (wWinHeaderOffset+0x001c, CFile::begin);
    fileIn.Read ((WORD*)&wNumOfSegments, sizeof(WORD));
    fileIn.Seek (wWinHeaderOffset+0x0022, CFile::begin);
    fileIn.Read ((WORD*)&wSegmentTableOffset, sizeof(WORD));

    // Find the beginning of the LoadOnCall code segments in the src exe file
    wLoadOnCallCodeBegin = 0xffff;
    for (i=0; i<wNumOfSegments; i++) {
        fileIn.Seek (wWinHeaderOffset+wSegmentTableOffset+8*i+4, CFile::begin);
        fileIn.Read ((WORD*)&wFlags, sizeof(WORD));
        if (!(wFlags & 0x0040)) {
            fileIn.Seek (wWinHeaderOffset+wSegmentTableOffset+8*i, CFile::begin);
            fileIn.Read ((WORD*)&wOffset, sizeof(WORD));
        
            // BUGBUG #294
            // In the file winoa386.mod we have a LoadOnCall segment that doesn't exist.
            // We have to check for this before go on
            if(wOffset)
                wLoadOnCallCodeBegin = (wOffset < wLoadOnCallCodeBegin) ? wOffset:wLoadOnCallCodeBegin;
        }
    }
                                                                     
    // Calculate the delta between the new beginning and the old beginnning
    // of the LoadOnCall code segments
    if (wResDataBegin != 0xffff && wLoadOnCallCodeBegin != 0xffff) { // Both LoadOnCall code and FastLoad
        wCurResDataBegin = LOWORD(dwCurResDataBegin>>wAlignShift);
        delta =  wCurResDataBegin - wLoadOnCallCodeBegin;
    }
    else if (wResDataBegin != 0xffff && wLoadOnCallResDataBegin != 0xffff){ // Both LoadOnCall and FastLoad Resources
	    wCurResDataBegin = LOWORD(dwCurResDataBegin>>wAlignShift);
	    delta =  wCurResDataBegin - wLoadOnCallResDataBegin;
    }
    else if (wResDataBegin != 0xffff) { // Only FastLoad Resources
        wCurResDataBegin = LOWORD(dwCurResDataBegin-dwSize>>wAlignShift);
	    delta =  wCurResDataBegin - wResDataBegin;
    }
    else delta = 0;

    dwLoadOnCallCodeBegin = MAKELONG (wLoadOnCallCodeBegin, 0) << wAlignShift;
    
    // Change the length for preload area
    if (wResDataBegin != 0xffff) {
        fileIn.Seek (wWinHeaderOffset+0x003a, CFile::begin);
        fileIn.Read ((WORD*)&wOffset, sizeof(WORD));  
        wOffset += delta;
    
        fileOut.Seek (wWinHeaderOffset+0x003a, CFile::begin);
        fileOut.Write ((WORD*)&wOffset, sizeof(WORD));  
    }
                                                                             
    if (wLoadOnCallCodeBegin != 0xffff && delta) {
        // Write LoadOnCall segments
        fileIn.Seek (dwLoadOnCallCodeBegin, CFile::begin);
        fileOut.Seek (dwCurResDataBegin, CFile::begin);
        LONG lLeft;
        if (wLoadOnCallResDataBegin != 0xffff)
            lLeft = MAKELONG (wLoadOnCallResDataBegin - wLoadOnCallCodeBegin, 0) << wAlignShift;
        else
            lLeft = fileIn.GetLength () - (MAKELONG (wLoadOnCallCodeBegin, 0)) << wAlignShift;
        
        WORD wRead = 0;
        BYTE far * pBuf = (BYTE far *) new BYTE[32739];
    
        if(!pBuf) {
            FreeLibrary(hDllInst);
            return ERROR_NEW_FAILED;
        }
    
        while(lLeft>0){
            wRead =(WORD) (32738ul < lLeft ? 32738: lLeft);
            if (wRead!= fileIn.Read( pBuf, wRead)) {
                delete []pBuf;
                FreeLibrary(hDllInst);
                return ERROR_FILE_READ;   
            }
            fileOut.Write( pBuf, wRead );
            lLeft -= wRead;
        }       
        delete []pBuf;  
    
        // Fixup the segment table  
        for (i=0; i<wNumOfSegments; i++) {
            fileIn.Seek (wWinHeaderOffset+wSegmentTableOffset+8*i+4, CFile::begin);
            fileIn.Read ((WORD*)&wFlags, sizeof(WORD));
            if (!(wFlags & 0x0040)) {
                fileIn.Seek (wWinHeaderOffset+wSegmentTableOffset+8*i, CFile::begin);
                fileIn.Read ((WORD*)&wOffset, sizeof(WORD));
                wOffset = wOffset + delta;
                fileOut.Seek (wWinHeaderOffset+wSegmentTableOffset+8*i, CFile::begin);
                fileOut.Write ((WORD*)&wOffset, sizeof(WORD));
            }
        }
    }

    if (wLoadOnCallResDataBegin != 0xffff)  {
        // Read the first type ID again
        fileIn.Seek (wWinHeaderOffset+wResTableOffset+2, CFile::begin);
        fileIn.Read ((WORD*)&wTypeId, sizeof(WORD));
    
        // Save the Offset of the current TypeInfo record
        wCurTypeOffset = wWinHeaderOffset + wResTableOffset + 2;
    
        // Calc the beginning of the LoadOnCall resources
        dwCurResDataBegin = (MAKELONG (wLoadOnCallResDataBegin + delta, 0))<<wAlignShift; 
    
        // Loop through the TypeInfo table again to write LoadOnCall resources
        while(wTypeId) {
            // Get Name of ord 
            if (!(wTypeId & 0x8000)) {
                // It is a Offset to a string                             
                dwTypeId = (MAKELONG(wTypeId, 0)); //<<wAlignShift;   
                fileIn.Seek (wWinHeaderOffset+wResTableOffset+dwTypeId, CFile::begin);
                // Get the character count for the ID string
                fileIn.Read ((BYTE*)&nCharCount, sizeof(BYTE));
                // Read the ID string
                fileIn.Read (szTypeId, nCharCount);
                // Put null at the end of the string
                szTypeId[nCharCount] = 0;
                // Set wTypeId to zero
                wTypeId = 0;                
            }
            else { 
                // It is an ID 
                // Turn off the high bit
                wTypeId = wTypeId & 0x7FFF; 
                if ( 0 == wTypeId)
                    return ERROR_RW_INVALID_FILE; 
            
                // Set the ID string to null 
                szTypeId[0] = 0;
            }

            // Restore the file read point
            fileIn.Seek (wCurTypeOffset+2, CFile::begin);
                
            // Get the count for this type of resource
            fileIn.Read ((WORD*)&wResCount, sizeof(WORD));
        
            // Pass the reserved DWORD
            fileIn.Seek (4, CFile::current);
        
            // Save the Offset of the current NameInfo record       
            wCurNameOffset = wCurTypeOffset + 8;
        
            // Loop through NameInfo records
            for (i = 0; i < wResCount; i++) {
                // Read resource offset
                fileIn.Read ((WORD*)&wFileOffset, sizeof(WORD));
                // Read resource length
                fileIn.Read ((WORD*)&wSize, sizeof(WORD));
                // Read the flags
                fileIn.Read ((WORD*)&wFlags, sizeof(WORD));
                // Read resource ID
                fileIn.Read ((WORD*)&wNameId, sizeof(WORD));
            
                if (!(wFlags & 0x0040))
                {
                    // Get name of ord
                    if (!(wNameId & 0x8000)) {
                        // It is a Offset to a string
                        fileIn.Seek (wWinHeaderOffset+wResTableOffset+wNameId, CFile::begin);
                        // Get the character count for the string
                        fileIn.Read ((BYTE*)&nCharCount, sizeof(BYTE));
                        // Read the string
                        fileIn.Read (szNameId, nCharCount);
                        // Put null at the end of the string
                        szNameId[nCharCount] = 0;
                        // Set wNameId to zero
                        wNameId = 0;                
                    }
                    else { 
                        // It is an ID 
                        // Turn off the high bit
                        wNameId = wNameId & 0x7FFF; 
                        if (0 == wNameId)
                            return ERROR_RW_INVALID_FILE;
                    
                        // Set the string to null 
                        szNameId[0] = 0;
                    }
                                
                    dwSize = (MAKELONG (wSize, 0))<<wAlignShift;   
                    dwFileOffset = (MAKELONG (wFileOffset, 0))<<wAlignShift;
                
                    // Now we got the Type and Name here and size
                
                    // Get the image from the IODLL
					if(dwSize)
                    	lpImageBuf = new BYTE[dwSize]; 
					else lpImageBuf = LPNULL;
                    LPSTR   lpType = LPNULL;
                    LPSTR   lpRes = LPNULL;
                
                    if (wTypeId)            
                        lpType = (LPSTR)((WORD)wTypeId);
                    else
                        lpType = &szTypeId[0];
                
                    if (wNameId)
                        lpRes = (LPSTR)((WORD)wNameId);
                    else
                        lpRes = &szNameId[0];
                    
                    dwImageBufSize = (*lpfnGetImage)(  hResFileModule,
                                                    lpType,
                                                    lpRes,
                                                    (DWORD)-1,
                                                    lpImageBuf,
                                                    dwSize
                                                    );
    
                    if (dwImageBufSize>dwSize ) {
                        // The buffer is too small             
                        delete []lpImageBuf;
                        lpImageBuf = new BYTE[dwImageBufSize];
                        dwSize = (*lpfnGetImage)(  hResFileModule,
                                                        lpType,
                                                        lpRes,
                                                        (DWORD)-1,
                                                        lpImageBuf,
                                                        dwImageBufSize
                                                       );
                        if ((dwSize-dwImageBufSize)!=0 ) {  
                            delete []lpImageBuf;
                            lpImageBuf = LPNULL;
                        }
                    }
                
                    // Try to see if we have to set the memory to 0
                    if ((int)(dwSize-dwImageBufSize)>0)
                        memset(lpImageBuf+dwImageBufSize, 0, (size_t)(dwSize-dwImageBufSize));
                    
                    // Write the image
                    fileOut.Seek (dwCurResDataBegin, CFile::begin); 
                    WriteImage( &fileOut, lpImageBuf, dwSize);      
    
                    // Fix the alignment for resource data   
                    DWORD dwTmp = 1;
                    delta = (short)((((dwSize+(dwTmp<<wAlignShift)-1)>>wAlignShift)<<wAlignShift)-dwSize);
                    BYTE nByte = 0;                                     
                
                    fileOut.Seek (dwCurResDataBegin+dwSize, CFile::begin);          
                    for (j=0; j<delta; j++)
                        fileOut.Write ((BYTE*)&nByte, sizeof(BYTE));
                                                                           
                    dwSize = dwSize + MAKELONG(delta, 0);
    
                    // Fixup the resource table
                    fileOut.Seek (wCurNameOffset, CFile::begin);
                    wCurResDataBegin = LOWORD(dwCurResDataBegin>>wAlignShift);
                    fileOut.Write ((WORD*)&wCurResDataBegin, sizeof(WORD));
                    wSize = LOWORD (dwSize>>wAlignShift);
                    fileOut.Write ((WORD*)&wSize, sizeof(WORD));
    
                    if (lpImageBuf) delete []lpImageBuf;                                           
                                               
                    // Update the current resource data beginning
                    dwCurResDataBegin = dwCurResDataBegin + dwSize;
                }
            
                // Update the current NameInfo record offset
                wCurNameOffset = wCurNameOffset + 12;
                // Move file pointer to the next NameInfo record
                fileIn.Seek (wCurNameOffset, CFile::begin);             
            } 
        
            // Update the current TypeInfo record offset
            wCurTypeOffset = wCurTypeOffset + 8 + wResCount * 12;  
            // Move file pointer to the next TypeInfo record
            fileIn.Seek (wCurTypeOffset, CFile::begin);
            // Read the next TypeId
            fileIn.Read ((WORD*)&wTypeId, sizeof(WORD));
        }
    }    

    fileIn.Close();
    fileOut.Close();
    FreeLibrary(hDllInst);

    return uiError;
}

extern "C"
UINT
APIENTRY   
RWUpdateImage(
    LPCSTR  lpszType,
    LPVOID  lpNewBuf,
    DWORD   dwNewSize,
    LPVOID  lpOldImage,
    DWORD   dwOldImageSize,
    LPVOID  lpNewImage,
    DWORD*  pdwNewImageSize
    )
{                          
    UINT uiError = ERROR_NO_ERROR;
    
    // The Type we can parse are only the standard ones
    switch ((UINT)LOWORD(lpszType)) {
        case 4: 
            if (lpOldImage)
                uiError = UpdateMenu( lpNewBuf, dwNewSize,  
                                      lpOldImage, dwOldImageSize,
                                      lpNewImage, pdwNewImageSize );
            else uiError = GenerateMenu( lpNewBuf, dwNewSize,  
                                      lpNewImage, pdwNewImageSize );
        break;                                                  
        case 5:         
            if (lpOldImage)
                uiError = UpdateDialog( lpNewBuf, dwNewSize,  
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
            else uiError = GenerateDialog( lpNewBuf, dwNewSize,  
                                      lpNewImage, pdwNewImageSize );
        break;                                                  
        case 6: 
            if (lpOldImage)
                uiError = UpdateString( lpNewBuf, dwNewSize,  
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
            else uiError = GenerateString( lpNewBuf, dwNewSize,  
                                      lpNewImage, pdwNewImageSize );
        break; 
        case 9:
            if (lpOldImage)
                uiError = UpdateAccel( lpNewBuf, dwNewSize,  
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
            else {
                *pdwNewImageSize = 0L;
                uiError = ERROR_RW_NOTREADY;
            }
        break;
#ifdef VB
        case 10:
            if (lpOldImage)
                uiError = UpdateVBData( lpNewBuf, dwNewSize,
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
            else {
                *pdwNewImageSize = 0L;
                uiError = ERROR_RW_NOTREADY;
            }
        break;
#endif

        case 16:
            if (lpOldImage)
                uiError = UpdateVerst( lpNewBuf, dwNewSize,  
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
            else {
                *pdwNewImageSize = 0L;
                uiError = ERROR_RW_NOTREADY;
            }
        break; 
        default:
            *pdwNewImageSize = 0L;
            uiError = ERROR_RW_NOTREADY;
        break;
    }

    return uiError;
}   

///////////////////////////////////////////////////////////////////////////
// Functions implementation

static UINT GenerateFile( LPCSTR        lpszTgtFilename,
                          HANDLE        hResFileModule,
                          LPVOID        lpBuffer,
                          UINT      uiSize,
                          HINSTANCE   hDllInst
                        )
{
    UINT uiError = ERROR_NO_ERROR;
    BYTE far * lpBuf = LPNULL;
    UINT uiBufSize = uiSize;
    // we can consider the use of a CMemFile so we get the same speed as memory access.
    CFile fileOut;

    if (!fileOut.Open(lpszTgtFilename, CFile::shareDenyNone | CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
        return ERROR_FILE_CREATE;

    // Get the pointer to the function
    if (!hDllInst) 
        return ERROR_DLL_LOAD;

    DWORD (FAR PASCAL    * lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD);
    // Get the pointer to the function to extract the resources image
    lpfnGetImage = (DWORD (FAR PASCAL   *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD))
                        GetProcAddress( hDllInst, "RSGetResImage" );
    if (lpfnGetImage==NULL) {
        return ERROR_DLL_PROC_ADDRESS;
    }


    WORD wUpdTypeId = 0;
    static char szUpdTypeId[128];

    WORD wUpdNameId;
    static char szUpdNameId[128];     

    DWORD dwUpdLang;
    DWORD dwUpdSize;
                     
    UINT uiBufStartSize = uiBufSize;
    DWORD dwImageBufSize;
    BYTE far * lpImageBuf;
    while(uiBufSize>0) {
        if ((!wUpdTypeId) && (uiBufSize))
            GetUpdatedRes( &lpBuffer, 
                    &uiBufSize,
                    &wUpdTypeId, &szUpdTypeId[0], 
                    &wUpdNameId, &szUpdNameId[0],
                    &dwUpdLang,
                    &dwUpdSize
                    );
                
        // The resource has been updated get the image from the IODLL
        if (dwUpdSize){
			lpImageBuf = new BYTE[dwUpdSize]; 
            LPSTR   lpType = LPNULL;
            LPSTR   lpRes = LPNULL;
            if (wUpdTypeId) {
                lpType = (LPSTR)((WORD)wUpdTypeId);
            } else {                 
                lpType = &szUpdTypeId[0];
            }                              
            if (wUpdNameId) {
                lpRes = (LPSTR)((WORD)wUpdNameId);
            } else {                    
                lpRes = &szUpdNameId[0];
            }

            dwImageBufSize = (*lpfnGetImage)(  hResFileModule,
                                            lpType,
                                            lpRes,
                                            dwUpdLang,
                                            lpImageBuf,
                                            dwUpdSize
                                            );
            if (dwImageBufSize>dwUpdSize ) {
                // The buffer is too small             
                delete []lpImageBuf;
                lpImageBuf = new BYTE[dwImageBufSize];
                dwUpdSize = (*lpfnGetImage)(  hResFileModule,
                                                lpType,
                                                lpRes,
                                                dwUpdLang,
                                                lpImageBuf,
                                                dwImageBufSize
                                               );
                if ((dwUpdSize-dwImageBufSize)!=0 ) {  
                    delete []lpImageBuf;
                    lpImageBuf = LPNULL;
                }
            }
            
            
            WriteHeader(&fileOut,
                        wUpdTypeId, &szUpdTypeId[0], 
                        wUpdNameId, &szUpdNameId[0],
                        0l);
        
            WriteImage( &fileOut,
                        lpImageBuf, dwImageBufSize);    
                    
            if (lpImageBuf) delete []lpImageBuf;
            wUpdTypeId = 0;
        
        } else wUpdTypeId = 0;
    
    }

    fileOut.Close();

    return uiError;
}

static UINT CopyFile( CFile* pfilein, CFile* pfileout )
{
    LONG lLeft = pfilein->GetLength();
    WORD wRead = 0;
    DWORD dwOffset = 0;
    BYTE far * pBuf = (BYTE far *) new BYTE[32739];

    if(!pBuf)
        return ERROR_NEW_FAILED;

    while(lLeft>0){
        wRead =(WORD) (32738ul < lLeft ? 32738: lLeft);
        if (wRead!= pfilein->Read( pBuf, wRead)) {
            delete []pBuf;
            return ERROR_FILE_READ;   
        }
        pfileout->Write( pBuf, wRead );
        lLeft -= wRead;
        dwOffset += wRead;
    }       
    delete []pBuf;   
    return ERROR_NO_ERROR;
}
    
static UINT GetUpdatedRes( 
                 LPVOID far * lplpBuffer,
                 UINT* uiSize,
                 WORD* wTypeId, LPSTR lplpszTypeId,
                 WORD* wNameId, LPSTR lplpszNameId,
                 DWORD* dwLang, DWORD* dwSize )
{                            
    BYTE far * lpBuf = (BYTE far *)*lplpBuffer;

    *wTypeId = *((WORD*)lpBuf);
    lpBuf += sizeofWord;
      
    strcpy( lplpszTypeId, (char *)lpBuf);
    lpBuf += strlen(lplpszTypeId)+1;

    *wNameId = *((WORD*)lpBuf);
    lpBuf += sizeofWord;

    strcpy( lplpszNameId, (char *)lpBuf);
    lpBuf += strlen(lplpszNameId)+1;

    *dwLang = *((DWORD*)lpBuf);
    lpBuf += sizeofDWord;

    *dwSize = *((DWORD*)lpBuf);
    lpBuf += sizeofDWord;           
                            
    *uiSize -= (lpBuf-(BYTE far *)*lplpBuffer);
    *lplpBuffer = (LPVOID)lpBuf;
    return 0;
}   

static
UINT
GetUpdatedItem( 
                 LPVOID far * lplpBuffer,
                 LONG* dwSize,
                 WORD* wX, WORD* wY,
                 WORD* wcX, WORD* wcY,
                 DWORD* dwPosId, 
                 DWORD* dwStyle, DWORD* dwExtStyle, 
                 LPSTR lpszText)
{
    BYTE far * far * lplpBuf = (BYTE far * far *)lplpBuffer;
    UINT uiSize = GetWord( lplpBuf, wX, dwSize );

    uiSize += GetWord( lplpBuf, wY, dwSize );
    uiSize += GetWord( lplpBuf, wcX, dwSize );
    uiSize += GetWord( lplpBuf, wcY, dwSize );
    uiSize += GetDWord( lplpBuf, dwPosId, dwSize );
    uiSize += GetDWord( lplpBuf, dwStyle, dwSize );
    uiSize += GetDWord( lplpBuf, dwExtStyle, dwSize );
    uiSize += GetString( lplpBuf, lpszText, dwSize );

    return uiSize;

    /*
    *wX = *((WORD*)lpBuf);
    lpBuf += sizeofWord;

    *wY = *((WORD*)lpBuf);
    lpBuf += sizeofWord;

    *wcX = *((WORD*)lpBuf);
    lpBuf += sizeofWord;

    *wcY = *((WORD*)lpBuf);
    lpBuf += sizeofWord;

    *dwPosId = *((DWORD*)lpBuf);
    lpBuf += sizeofDWord;

    *dwStyle = *((DWORD*)lpBuf);
    lpBuf += sizeofDWord;

    *dwExtStyle = *((DWORD*)lpBuf);
    lpBuf += sizeofDWord;

    strcpy( lpszText, (char *)lpBuf);
    lpBuf += strlen(lpszText)+1;

    *dwSize -= (lpBuf-(BYTE far *)*lplpBuffer);
    *lplpBuffer = lpBuf;
    return 0;*/
}   


static UINT
GetResInfo( CFile* pfile,
            WORD* pwTypeId, LPSTR lpszTypeId, BYTE bMaxTypeLen,
            WORD* pwNameId, LPSTR lpszNameId, BYTE bMaxNameLen,
            WORD* pwFlags,
            DWORD* pdwSize, DWORD* pdwFileOffset )
{                       
    static UINT uiSize;
    static LONG lOfsCheck;
    // get the Type info
    uiSize = GetNameOrOrdFile( pfile, pwTypeId, lpszTypeId, bMaxTypeLen);
    if (!uiSize) 
        return 0;
    
    // get the Name info
    uiSize = GetNameOrOrdFile( pfile, pwNameId, lpszNameId, bMaxNameLen);
    if (!uiSize) 
        return 0;

    // Skip the Flag
    pfile->Read( pwFlags, 2 );

    // get the size
    pfile->Read( pdwSize, 4 );
    if (*pdwSize==0)
        // size id 0 the resource file is corrupted or is not a res file
        return 0;

    *pdwFileOffset = pfile->GetPosition();

    // check if the size is valid
    TRY {
        lOfsCheck = pfile->Seek(*pdwSize, CFile::current);
    } CATCH(CFileException, e) {
        // Check is the right exception
        return 0;
    } END_CATCH
    if (lOfsCheck!=(LONG)(*pdwFileOffset+*pdwSize)) 
            return 0;
    return 1;
}

static UINT WriteHeader( 
                 CFile* pFile,
                 WORD wTypeId, LPSTR lpszTypeId,
                 WORD wNameId, LPSTR lpszNameId,
                 WORD wFlags )
{
    UINT uiError = ERROR_NO_ERROR;
    BYTE bFF = 0xFF;
    if(wTypeId) {
        // It is an ordinal   
    
        pFile->Write( &bFF, 1 );
        pFile->Write( &wTypeId, 2 );
    } else {
        pFile->Write( lpszTypeId, strlen(lpszTypeId)+1 );
    }                                                 

    if(wNameId) {
        // It is an ordinal   
        pFile->Write( &bFF, 1 );
        pFile->Write( &wNameId, 2 );
    } else {
        pFile->Write( lpszNameId, strlen(lpszNameId)+1 );
    }                                            

    pFile->Write( &wFlags, 2 );

    return uiError;
}                
             
static UINT WriteImage( 
                 CFile* pFile,
                 LPVOID lpImage, DWORD dwSize )
{                  
    UINT uiError = ERROR_NO_ERROR;
    if(lpImage) {
//      pFile->Write( &dwSize, sizeofDWord );
        pFile->Write( lpImage, (UINT)dwSize );
    }
    return uiError;
}

////////////////////////////////////////////////////////////////////////////
// Helper Function Implementation
static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen )
{
    UINT uiSize = 0; 

    *pwId = 0;

    // read the first BYTE to see if it is a string or an ordinal
    pfile->Read( pwId, sizeof(BYTE) );  
    if(LOBYTE(*pwId)==0xFF) {
        // This is an Ordinal
        pfile->Read( pwId, sizeofWord );    
        *lpszId = '\0';          
        uiSize = 2;
    } else {
        uiSize++;
        *lpszId = LOBYTE(*pwId);
        while((*lpszId++) && (bMaxStrLen-2)) {
            pfile->Read( pwId, sizeof(BYTE) );  
            *lpszId = LOBYTE(*pwId);
            uiSize++;
            bMaxStrLen--;
        }
        if ( (!(bMaxStrLen-2)) && (*pwId) ) {
            // Failed
            return 0;
        }
    }
    return uiSize;
}       

static                                                  
UINT
ParseCursor( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{                                  

    // Should be almost impossible for a Cursor to be Huge
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;

    LONG dwOverAllSize = 0L;

    // Cursor Items
    WORD wWidth = 0;
    WORD wHeight = 0;
    WORD wPlanes = 0;
    WORD wBitCount = 0;
    DWORD dwBytesInRes = 0;
    WORD wImageIndex = 0;

    // Get the CURSOR DIR ENTRY
    GetWord( &lpImage, &wWidth, &dwImageSize );
    GetWord( &lpImage, &wHeight, &dwImageSize );
    GetWord( &lpImage, &wPlanes, &dwImageSize );
    GetWord( &lpImage, &wBitCount, &dwImageSize );
    GetDWord( &lpImage, &dwBytesInRes, &dwImageSize );
    GetWord( &lpImage, &wImageIndex, &dwImageSize );

    //SkipByte( &lpImage, 4, &dwImageSize );
    //BITMAPINFO
    BITMAPINFOHEADER* pBmpInfHead = (BITMAPINFOHEADER*) lpImage;
    UINT uiSize = sizeof(BITMAPINFOHEADER);
    SkipByte( &lpImage, uiSize, &dwImageSize );
    /*

    // Get the Width
    SkipByte( &lpImage, 4, &dwImageSize );


    // Menu Items
    WORD fItemFlags;
    WORD wMenuId;
    CString szCaption;

    while(dwImageSize>0) {
        // Fixed field                                    
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        // We don't have the size and pos in a menu
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
    
        // we don't have checksum and style                        
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
    
        // Let's get the Menu flags
        GetWord( &lpImage, &fItemFlags, &dwImageSize );
    
        if ( !(fItemFlags & MF_POPUP) )
            // Get the menu Id 
            GetWord( &lpImage, &wMenuId, &dwImageSize );
        else wMenuId = -1;
    
        //Put the Flag
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)fItemFlags, &dwBufSize);
        //Put the MenuId
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)wMenuId, &dwBufSize);
    
    
        // we don't have the resID, and the Type Id
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
    
        // we don't have the language                                    
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
    
        // we don't have the codepage or the font name
        dwOverAllSize += PutDWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, -1, &dwBufSize);
                                                       
        // Let's put null were we don;t have the strings     
        uiOffset = sizeof(RESITEM);           
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)(lpItem+uiOffset), &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    
        // Get the text
        // calculate were the string is going to be
        // Will be the fixed header+the pointer
        dwOverAllSize += CopyText( &lpBuf, &lpImage, &dwBufSize, &dwImageSize );
    
        // Put the size of the resource             
        if (dwBufSize>=0) {
            uiOffset += strlen((LPSTR)(lpItem+uiOffset))+1;
            lDummy = 8;
            PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
        }
    
        // Move to the next position
        lpItem = lpBuf;
        if (dwImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==(dwImageSize))
                dwImageSize = -1;
        }
    }      
    */

    return (UINT)(dwOverAllSize);
}   

static
UINT
ParseBitmap( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{
	// we will return just one item so the iodll will handle this resource as
	// something valid. We will not bother doing anything else. The only thing
	// we are interesed is the raw data in the immage, but if we don't return at
	// least one item IODLL will consider the resource empty.
	BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;
    LONG dwOverAllSize = 0;

	TRACE1("ParseBitmap: dwISize=%ld\n", dwISize);

	dwOverAllSize += PutDWord( &lpBuf, sizeof(RESITEM), &dwBufSize);

    // We have the size and pos in a cursor but we are not interested now
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);

    // we don't have checksum and style
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

    //Put the Flag
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

    // The ID will be just 1
    dwOverAllSize += PutDWord( &lpBuf, 1, &dwBufSize);

    // we don't have the resID, and the Type Id
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

    // we don't have the language
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

    // we don't have the codepage or the font name
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);

    // Let's put null were we don;t have the strings
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);

    // we just return. This is enough for IODLL
    return (UINT)(dwOverAllSize);
}

static                                                  
UINT
ParseIcon( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{                                  

    // Should be almost impossible for an Icon to be Huge
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;
    LONG lDummy;

    LONG dwOverAllSize = 0L;
                            
    BITMAPINFOHEADER* pBmpInfo = (BITMAPINFOHEADER*) lpImage;
    // difficult it will be bigger than UINT_MAX
    SkipByte( &lpImage, (UINT)pBmpInfo->biSize, &dwImageSize );

    RGBQUAD* pRgbQuad = (RGBQUAD*) lpImage;
    SkipByte( &lpImage, sizeof(RGBQUAD), &dwImageSize );    

    // Calculate CheckSum on the image
    DWORD dwCheckSum = 0l;
    BYTE * hp = (BYTE *) lpImage;

    for( DWORD dwLen = pBmpInfo->biSizeImage; dwLen; dwLen--)
        dwCheckSum = (dwCheckSum << 8) | *hp++; 


    // Fixed field                                    
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);

    // We don't have the size and pos in a menu
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)pBmpInfo->biWidth, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)pBmpInfo->biHeight, &dwBufSize);
    
    // we don't have checksum and style                        
    dwOverAllSize += PutDWord( &lpBuf, dwCheckSum, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    

    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    // we don't have the resID, and the Type Id
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
    // we don't have the language                                    
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
    // we don't have the codepage or the font name
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
                                                       
    // Let's put null were we don;t have the strings     
    uiOffset = sizeof(RESITEM);           
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    
    
    // Put the size of the resource             
    if (dwBufSize>=0) {
        lDummy = 8;
        PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
    }
    

    return (UINT)(dwOverAllSize);
}

static int
GetVSBlock( BYTE far * far * lplpImage, LONG* pdwSize, VER_BLOCK* pver)
{            
    // We have to hard code the language filed because otherwise, due to some
    // inconsistent RC compiler, the Image are not following any standard.
    // We assume that all the block but the one hard-coded here are binary and
    // we just skip them
    WORD wHead = 0;
    WORD wPad = 0;
    WORD wValue = 0;
    pver->pValue = *lplpImage;

    // Read the header of the block
    wHead = GetWord( lplpImage, &pver->wBlockLen, pdwSize );
    wHead += GetWord( lplpImage, &pver->wValueLen, pdwSize );
    // The Key name is all the time a NULL terminated string
    wHead += GetString( lplpImage, &pver->szKey[0], pdwSize );
    pver->wHead = wHead;

    // See if we have padding after the header. We can check on wHead because
    // we need an allignment on a DWORD boundary and we have 2 WORD+the string.
    wPad = SkipByte( lplpImage, Pad4(wHead), pdwSize );

    // Fix the pointer to the value
    pver->pValue = (pver->pValue+wHead+wPad);

    if ((int)pver->wValueLen>*pdwSize) {
        // There is an error
        wPad += SkipByte( lplpImage, (UINT)*pdwSize, pdwSize );
        return wHead+wPad;
    }

    // Now we check the key name and if is one of the one we accept as good
    // we read the string. Otherwise we just skip the value field
    if ( !strcmp(pver->szKey,"Comments") ||
         !strcmp(pver->szKey,"CompanyName") ||
         !strcmp(pver->szKey,"FileDescription") ||
         !strcmp(pver->szKey,"FileVersion") ||
         !strcmp(pver->szKey,"InternalName") ||
         !strcmp(pver->szKey,"LegalCopyright") ||
         !strcmp(pver->szKey,"LegalTrademarks") ||
         !strcmp(pver->szKey,"OriginalFilename") ||
         !strcmp(pver->szKey,"PrivateBuild") ||
         !strcmp(pver->szKey,"ProductName") ||
         !strcmp(pver->szKey,"ProductVersion") ||
	 	 !strcmp(pver->szKey,"SpecialBuild") ||
	 	 !strcmp(pver->szKey,"StringFileInfo")	// found in a Borland Version resource
       ) {
        // It is a standard key name read the string.                     
        // Set the flag to show it is a string
        pver->wType = 1;
        wValue = GetVSString( lplpImage, &pver->szValue[0], pdwSize, pver->wValueLen );
    
        // BUGBUG 
        // check if this is the LegalCopyright block.
        // If it is then there might be a null in the middle of the string
        if (!strcmp(pver->szKey,"LegalCopyright")) {
            // we just skip the rest. This need to be fixed in the RC, not here
            if ((int)(pver->wValueLen-wValue)>0)
                wValue += SkipByte( lplpImage, pver->wValueLen-wValue, pdwSize );
        }
    
    } else {
        // It isn't a string, or if is is not a standard key name, skip it
        pver->wType = 0;
        *pver->szValue = '\0';
        wValue = SkipByte( lplpImage, pver->wValueLen, pdwSize );
    }   

    // Check the padding
    wPad += SkipByte( lplpImage, Pad4(wValue), pdwSize );
      
    // BUGBUG 
    // Even if it look what we have done should be enough we have to walk the image
    // skiping the NULL char that sometimes the comipler place there.
    // Do this only if it is not the translation field.  
    // The translation field is the last so we might have some image padding
    if (strcmp(pver->szKey, "Translation")) {
		WORD wSkip = 0;
		BYTE far * lpTmp = *lplpImage;

		while(!**lplpImage && *pdwSize) {
			wSkip += SkipByte(lplpImage, 1, pdwSize);
		}
		if (Pad4(wSkip)) { 
			*lplpImage = lpTmp;
			*pdwSize += wSkip;
		}
		else wPad += wSkip;
	}

    return wHead+wValue+wPad;
}

static int
GetVSBlockOld( BYTE far * far * lplpImage, LONG* pdwSize, VER_BLOCK* pver)
{   
    WORD wHead = 0;
    WORD wPad = 0;
    WORD wValue = 0;
    LONG lValueLen = 0; 
    pver->pValue = *lplpImage;
    wHead = GetWord( lplpImage, &pver->wBlockLen, pdwSize );
    wHead += GetWord( lplpImage, &pver->wValueLen, pdwSize );
    wHead += GetString( lplpImage, &pver->szKey[0], pdwSize );

    pver->wHead = wHead;

    wPad = SkipByte( lplpImage, Pad4(wHead), pdwSize );

    lValueLen = pver->wValueLen;                                 
    if (lValueLen>*pdwSize) {
        // There is an error
        wPad += SkipByte( lplpImage, (UINT)*pdwSize, pdwSize );
        return wHead+wPad;
    }

    pver->wType = 0;
    pver->pValue = (pver->pValue+wHead+wPad);
    if(pver->wValueLen) {
        wValue = GetString( lplpImage, &pver->szValue[0], &lValueLen );
        *pdwSize -= wValue;
        pver->wType = 1;
    }
    if(wValue!=pver->wValueLen) {
        // Just skip the value. It isn't a string, is a value
        if(pver->wValueLen-wValue!=1) {
            *pver->szValue = '\0';
            pver->wType = 0;     
        }
        wPad += SkipByte( lplpImage, pver->wValueLen-wValue, pdwSize );
    }
    
    wPad += SkipByte( lplpImage, Pad4(pver->wValueLen), pdwSize );

    return wHead+wPad+wValue;
}

static int
PutVSBlock( BYTE far * far * lplpImage, LONG* pdwSize, VER_BLOCK ver, 
            LPSTR lpStr, BYTE far * far * lplpBlockSize, WORD* pwTrash)

{
    // We have to write the info in the VER_BLOCK in the new image
    // We want to remember were the block size field is so we can update it later

    WORD wHead = 0;
    WORD wValue = 0;
    WORD wPad = Pad4(ver.wHead);
    *pwTrash = 0;

    // Get the pointer to the header of the block
    BYTE far * pHead = ver.pValue-ver.wHead-wPad; 
    BYTE far * lpNewImage = *lplpImage;

    // Copy the header of the block to the new image   
    wHead = ver.wHead;
    if (*pdwSize>=(int)ver.wHead) {
        memcpy( *lplpImage, pHead, ver.wHead );
        *pdwSize -= ver.wHead;
        lpNewImage += ver.wHead;
    } else *pdwSize = -1;

    // Check if padding is needed
    if (*pdwSize>=(int)wPad) {
        memset( *lplpImage+ver.wHead, 0, wPad );
        *pdwSize -= wPad;
        lpNewImage += wPad;
    } else *pdwSize = -1;

    // Store the pointer to the block size WORD
    BYTE far * pBlockSize = *lplpImage;

    // Check if the value is a string or a BYTE array
    if(ver.wType) {
        // it is a string, copy the updated item
        wValue = strlen(lpStr)+1;
        if (*pdwSize>=(int)wValue) {
            memcpy(*lplpImage+wHead+wPad, lpStr, wValue);
            *pdwSize -= wValue;
            lpNewImage += wValue;
        } else *pdwSize = -1;
    
        // Check if padding is needed
        int wPad1 = Pad4(wValue);
        if (*pdwSize>=wPad1) {
            memset( *lplpImage+ver.wHead+wValue+wPad, 0, wPad1 );
            *pdwSize -= wPad1;
            lpNewImage += wPad1;
        } else *pdwSize = -1;
    
        *pwTrash = Pad4(ver.wValueLen);
        wValue += wPad1;
    
        // Fix to the strange behaviour of the ver.dll
        if((wPad1) && (wPad1>=(int)*pwTrash)) {
            wValue -= *pwTrash;
        } else *pwTrash = 0;
        // Fix up the Value len field. We will put the len of the value + padding
        if (*pdwSize>=0)
            memcpy( pBlockSize+2, &wValue, 2);
    
    } else {
        // it is an array, just copy it in the new image buffer
        wValue = ver.wValueLen;
        if (*pdwSize>=(int)ver.wValueLen) {
            memcpy(*lplpImage+wHead+wPad, ver.pValue, ver.wValueLen);
            *pdwSize -= ver.wValueLen;        
            lpNewImage += ver.wValueLen;
        } else *pdwSize = -1;
        
        // Check if padding is needed
        if (*pdwSize>=(int)Pad4(ver.wValueLen)) {
            memset( *lplpImage+ver.wHead+ver.wValueLen+wPad, 0, Pad4(ver.wValueLen) );
            *pdwSize -= Pad4(ver.wValueLen);
            lpNewImage += Pad4(ver.wValueLen);
        } else *pdwSize = -1;
        wPad += Pad4(ver.wValueLen);
    }

    *lplpBlockSize = pBlockSize;
    *lplpImage = lpNewImage;
    return wPad+wValue+wHead;
}

static
UINT ParseVerst( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{
    TRACE("ParseVersion Stamp: \n");
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;
    LPRESITEM lpResItem = (LPRESITEM)lpBuffer;
    char far * lpStrBuf = (char far *)(lpBuf+sizeof(RESITEM));  
    LONG dwOverAllSize = 0L;

    WORD wPos = 0;

    static VER_BLOCK verBlock;

    while(dwImageSize>0){                                
        wPos++;
        GetVSBlock( &lpImage, &dwImageSize, &verBlock);
    
        // check if this is the translation block
        if (!strcmp(verBlock.szKey, "Translation" )) {
            // This is the translation block let the localizer have it for now
            DWORD dwCodeLang = 0;
            LONG lDummy = 4;
            GetDWord( &verBlock.pValue, &dwCodeLang, &lDummy);
        
            // Put the value in the string value
            wsprintf( &verBlock.szValue[0], "%#08lX", dwCodeLang );
        }
    
        // Fixed field                                    
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        // We don't have the size and pos in an accelerator
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    
        // we don't have checksum and style                        
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        //Put the Flag
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        // we will need to calculate the correct ID for mike
        //Put the Id
        dwOverAllSize += PutDWord( &lpBuf, wPos, &dwBufSize);
    
    
        // we don't have the resID, and the Type Id
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the language                                    
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the codepage or the font name
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
                               
        // Let's put null were we don;t have the strings     
        uiOffset = sizeof(RESITEM);           
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    
        lpResItem->lpszClassName = strcpy( lpStrBuf, verBlock.szKey );
        lpStrBuf += strlen(lpResItem->lpszClassName)+1;
    
        lpResItem->lpszCaption = strcpy( lpStrBuf, verBlock.szValue );
        lpStrBuf += strlen(lpResItem->lpszCaption)+1;
    
    
        // Put the size of the resource             
        if (dwBufSize>0) {
            uiOffset += strlen((LPSTR)(lpResItem->lpszClassName))+1;
            uiOffset += strlen((LPSTR)(lpResItem->lpszCaption))+1;
        }
    
        // Check if we are alligned
        uiOffset += Allign( (BYTE**)&lpStrBuf, &dwBufSize, (LONG)uiOffset);
        dwOverAllSize += uiOffset-sizeof(RESITEM);
        lpResItem->dwSize = (DWORD)uiOffset;

    
        // Move to the next position
        lpResItem = (LPRESITEM) lpStrBuf;
        lpBuf = (BYTE far *)lpStrBuf;
        lpStrBuf = (char far *)(lpBuf+sizeof(RESITEM));
    
        if (dwImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==(dwImageSize))
                dwImageSize = -1;
        }
    }
    return (UINT)(dwOverAllSize);
}

static void GenerateTransField( WORD wLang, VER_BLOCK * pVer )
{
    // Get the DWORD value 
    DWORD dwValue = GenerateTransField( wLang, TRUE );
    char buf[9];

    // Put the value in the string value
    wsprintf( &buf[0], "%08lX", dwValue );

    // Just check if we are in the right place. Should never have problem
    if(strlen(pVer->szKey)==8) {
        //strcpy( pVer->szKey, buf );
        // We have to change the header in the image, not just the
        // szKey field
        // Get the pointer to he begin of the filed
        WORD wPad = Pad4(pVer->wHead);
        BYTE far * pHead = pVer->pValue-pVer->wHead-wPad; 
        pHead += 4; // Move at the begin of the string
        strcpy( (char*)pHead, buf );
   }
}

static DWORD GenerateTransField(WORD wLang, BOOL bReverse)
{
    // we have to generate a table to connect 
    // the language with the correct code page

    WORD wCP = 0;
    DWORD dwRet = 0;
    switch(wLang) {
        // Just be stupid and have a big switch to assign the codepage
        case 0x1401: wCP =  1256;   break;      //    Algeria
        case 0x1801: wCP =  1256;   break;      //    Morocco
        case 0x1C01: wCP =  1256;   break;      //    Tunisia
        case 0x2001: wCP =  1256;   break;      //    Oman
        case 0x2401: wCP =  1256;   break;      //    Yemen
        case 0x2801: wCP =  1256;   break;      //    Syria
        case 0x2C01: wCP =  1256;   break;      //    Jordan
        case 0x3001: wCP =  1256;   break;      //    Lebanon
        case 0x3401: wCP =  1256;   break;      //    Kuwait
        case 0x3801: wCP =  1256;   break;      //    U.A.E.
        case 0x3C01: wCP =  1256;   break;      //    Bahrain
        case 0x4001: wCP =  1256;   break;      //    Qatar
        case 0x0423: wCP =  1251;   break;      //    Byelorussia
        case 0x0402: wCP =  1251;   break;      //    Bulgaria
        case 0x0403: wCP =  1252;   break;      //    Catalan
        case 0x0404: wCP =  950;    break;      //    Taiwan
        case 0x0804: wCP =  936;    break;      //    PRC
        case 0x0C04: wCP =  950;    break;      //    Hong Kong
        case 0x1004: wCP =  936;    break;      //    Singapore
        case 0x0405: wCP =  1250;   break;      //    Czech
        case 0x0406: wCP =  1252;   break;      //    Danish
        case 0x0413: wCP =  1252;   break;      //    Dutch (Standard)
        case 0x0813: wCP =  1252;   break;      //    Dutch (Belgian)
        case 0x0409: wCP =  1252;   break;      //    English (American)
        case 0x0809: wCP =  1252;   break;      //    English (British)
        case 0x1009: wCP =  1252;   break;      //    English (Canadian)
        case 0x1409: wCP =  1252;   break;      //    English (New Zealand)
        case 0x0c09: wCP =  1252;   break;      //    English (Australian)
        case 0x1809: wCP =  1252;   break;      //    English (Ireland)
        case 0x0425: wCP =  1257;   break;      //    Estonia
        //case 0x0429: wCP =       Farsi
        case 0x040b: wCP =  1252;   break;      //    Finnish
        case 0x040c: wCP =  1252;   break;      //    French (Standard)
        case 0x080c: wCP =  1252;   break;      //    French (Belgian)
        case 0x100c: wCP =  1252;   break;      //    French (Swiss)
        case 0x0c0c: wCP =  1252;   break;      //    French (Canadian)
        case 0x0407: wCP =  1252;   break;      //    German (Standard)
        case 0x0807: wCP =  1252;   break;      //    German (Swiss)
        case 0x0c07: wCP =  1252;   break;      //    German (Austrian)
        case 0x0408: wCP =  1253;   break;      //    Greek
        case 0x040D: wCP =  1255;   break;      //    Israel
        case 0x040e: wCP =  1250;   break;      //    Hungarian
        case 0x040f: wCP =  1252;   break;      //    Icelandic
        case 0x0421: wCP =  1252;   break;      //    Indonesia
        case 0x0410: wCP =  1252;   break;      //    Italian (Standard)
        case 0x0810: wCP =  1252;   break;      //    Italian (Swiss)
        case 0x0411: wCP =  932;    break;      //    Japanese
        case 0x0412: wCP =  949;    break;      //    Korea
        case 0x0426: wCP =  1257;   break;      //    Latvia
        case 0x0427: wCP =  1257;   break;      //    Lithuania
        case 0x0414: wCP =  1252;   break;      //    Norwegian (Bokmal)
        case 0x0814: wCP =  1252;   break;      //    Norwegian (Nynorsk)
        case 0x0415: wCP =  1250;   break;      //    Polish
        case 0x0816: wCP =  1252;   break;      //    Portuguese (Standard)
        case 0x0416: wCP =  1252;   break;      //    Portuguese (Brazilian)
        case 0x0417: wCP =  1252;   break;      //    Rhaeto-Romanic
        case 0x0818: wCP =  1250;   break;      //    Moldavia
        case 0x0418: wCP =  1250;   break;      //    Romanian
        case 0x0419: wCP =  1251;   break;      //    Russian
        case 0x041b: wCP =  1250;   break;      //    Slovak
        case 0x0424: wCP =  1250;   break;      //    Slovenian
        case 0x042e: wCP =  1250;   break;      //    Germany
        case 0x080a: wCP =  1252;   break;      //    Spanish (Mexican)
        case 0x040a: wCP =  1252;   break;      //    Spanish (Castilian)
        case 0x0c0a: wCP =  1252;   break;      //    Spanish (Modern)
        case 0x041d: wCP =  1252;   break;      //    Swedish
        case 0x041E: wCP =  874;    break;      //    Thailand
        case 0x041f: wCP =  1254;   break;      //    Turkish
        case 0x0422: wCP =  1251;   break;      //    Ukraine
        default: wCP =  1252;       break;      //    Return standard US English CP.
    }                          
    if(bReverse)
    	dwRet = MAKELONG( wCP, wLang );
    else dwRet = MAKELONG( wLang, wCP );
    return dwRet;
}

#ifdef VB
static
UINT
UpdateVBData( LPVOID lpNewBuf, LONG dwNewSize,
            LPVOID lpOldI, LONG dwOldImageSize,
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{
// The following special format is used by VB for international messages
// The code here is mostly copied from the UpdateMenu routine
    UINT uiError = ERROR_NO_ERROR;

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;
    DWORD dwOriginalOldSize = dwOldImageSize;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;

    LPRESITEM lpResItem = LPNULL;

    // We have to read the information from the lpNewBuf
    // Data Items
    WORD wDataId;
    char szTxt[256];
    WORD wPos = 0;

    // Updated items
    WORD wUpdPos = 0;
    WORD wUpdDataId;
    char szUpdTxt[256];

    LONG  dwOverAllSize = 0l;


    // Copy the language specifier
    dwOldImageSize -= PutDWord( &lpNewImage, *((DWORD*)lpOldImage), &dwNewImageSize);
    lpOldImage += sizeofDWord;
    dwOverAllSize += sizeofDWord;
    GetString( &lpOldImage, &szTxt[0], &dwOldImageSize );
	dwOverAllSize += PutString( &lpNewImage, &szTxt[0], &dwNewImageSize);

	// Now copy the strings
    while(dwOldImageSize>0) {
        wPos++;
		// Check for only padding remaining and exit
		if ( *(WORD *)lpOldImage != RES_SIGNATURE )
			if ( dwOldImageSize < 16 && *(BYTE *)lpOldImage == 0 )
				break;
			else
    	    	return ERROR_RW_INVALID_FILE;
		// This copies signature and ID
		wDataId = *(WORD *)(lpOldImage + sizeof(WORD));
	    dwOldImageSize -= PutDWord( &lpNewImage, *((DWORD*)lpOldImage), &dwNewImageSize);
	    lpOldImage += sizeofDWord;
	    dwOverAllSize += sizeofDWord;

		// Get the untranslated string
	    GetString( &lpOldImage, &szTxt[0], &dwOldImageSize );

        if ((!wUpdPos) && dwNewSize ) {
            lpResItem = (LPRESITEM) lpBuf;

            wUpdPos = HIWORD(lpResItem->dwItemID);
            wUpdDataId = LOWORD(lpResItem->dwItemID);
            strcpy( szUpdTxt, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;
            dwNewSize -= lpResItem->dwSize;
        }

        if ((wPos==wUpdPos) && (wUpdDataId==wDataId)) {
            strcpy(szTxt, szUpdTxt);
            wUpdPos = 0;
        }
        // Write the text
        dwOverAllSize += PutString( &lpNewImage, &szTxt[0], &dwNewImageSize);

		  // Check for padding
        if (dwOldImageSize<=16) {
            // Check if we are at the end and this is just padding
	         BYTE bPad = (BYTE)Pad16((dwOriginalOldSize-dwOldImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwOldImageSize, bPad );
            if (bPad==dwOldImageSize) {
				BYTE far * lpBuf = lpOldImage;
				while (bPad){
					if(*lpBuf++!=0x00)
						break;
					bPad--;
				}
				if (bPad==0)
					dwOldImageSize = -1;
			}
        }

    }

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }

    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}
#endif


static
UINT
UpdateVerst( LPVOID lpNewBuf, LONG dwNewSize,  
             LPVOID lpOldI, LONG dwOldImageSize,
             LPVOID lpNewI, DWORD* pdwNewImageSize )
{   
    /*
     * This Function is a big mess. It is like this because the RC compiler generate 
     * some inconsistent code so we have to do a lot of hacking to get the VS working
     * In future, if ever ver.dll and the RC compiler will be fixed will be possible
     * fix some of the bad thing we have to do to get the updated VS as consistent as
     * possible with the old one
     */

    UINT uiError = ERROR_NO_ERROR;

    LONG dwNewImageSize = *pdwNewImageSize;
    BYTE far * lpNewImage = (BYTE far *) lpNewI;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                                   
    LPRESITEM lpResItem = LPNULL;

    WORD wPos = 0;

    // Updated info
    WORD wUpdPos = 0;
    static char szCaption[300];
    static char szUpdCaption[300];
    static char szUpdKey[100];

    DWORD dwOriginalOldSize = dwOldImageSize;
    LONG dwOverAllSize = 0l;

    WORD wPad = 0;

    // Pointer to the block size to fix up later
    BYTE far * lpVerBlockSize = LPNULL;
    BYTE far * lpSFIBlockSize = LPNULL;
    BYTE far * lpTrnBlockSize = LPNULL;
    BYTE far * lpStrBlockSize = LPNULL;
    BYTE far * lpDummy = LPNULL;

    WORD wVerBlockSize = 0;
    WORD wSFIBlockSize = 0;
    WORD wTrnBlockSize = 0;
    WORD wStrBlockSize = 0;
    WORD wTrash = 0;        // we need this to fix a bug in the RC compiler

    // StringFileInfo        
    static VER_BLOCK SFI;   // StringFileInfo
    LONG lSFILen = 0;

    // Translation blocks
    static VER_BLOCK Trn;   
    LONG lTrnLen = 0;

    static VER_BLOCK Str;   // Strings

    // we read first of all the information from the VS_VERSION_INFO block
    static VER_BLOCK VS_INFO; // VS_VERSION_INFO

    int iHeadLen = GetVSBlock( &lpOldImage, &dwOldImageSize, &VS_INFO );

    // Write the block in the new image
    wVerBlockSize = PutVSBlock( &lpNewImage, &dwNewImageSize, VS_INFO, 
                                &VS_INFO.szValue[0], &lpVerBlockSize, &wTrash );
                            
    dwOverAllSize = wVerBlockSize+wTrash;

    // [BUGBUG] - we have to check the len of the full block for padding.
    // For some wild reasons the RC compiler place a wrong value there
    LONG lVS_INFOLen = VS_INFO.wBlockLen - iHeadLen - Pad4(VS_INFO.wBlockLen);

    while(dwOldImageSize>0) {
        //Get the StringFileInfo
        iHeadLen = GetVSBlock( &lpOldImage, &dwOldImageSize, &SFI );
    
        // Check if this is the StringFileInfo field
        if (!strcmp(SFI.szKey, "StringFileInfo")) {
            // Read all the translation blocks
            lSFILen = SFI.wBlockLen-iHeadLen-Pad4(SFI.wBlockLen);
            // Write the block in the new image
            wSFIBlockSize = PutVSBlock( &lpNewImage, &dwNewImageSize, SFI, 
                                         &SFI.szValue[0], &lpSFIBlockSize, &wTrash );
            dwOverAllSize += wSFIBlockSize+wTrash;
    
            while(lSFILen>0) {
                // Read the Translation block
                iHeadLen = GetVSBlock( &lpOldImage, &dwOldImageSize, &Trn );
            
                // Calculate the right key name 
                if ((lpResItem = GetItem( lpBuf, dwNewSize, Trn.szKey)))  {
                	// Find the Translation ResItem
                	LPRESITEM lpTrans = GetItem( lpBuf, dwNewSize, "Translation");
                	WORD wLang = (lpTrans ? LOWORD(lpTrans->dwLanguage) : 0xFFFF);
                    GenerateTransField( wLang, &Trn );
                }   
            
                // Write the block in the new image
                wTrnBlockSize = PutVSBlock( &lpNewImage, &dwNewImageSize, Trn, 
                                             &Trn.szValue[0], &lpTrnBlockSize, &wTrash );
                dwOverAllSize += wTrnBlockSize+wTrash;
                lTrnLen = Trn.wBlockLen-iHeadLen-Pad4(Trn.wBlockLen);
                while(lTrnLen>0) {                  
                    // Read the Strings in the block
                    iHeadLen = GetVSBlock( &lpOldImage, &dwOldImageSize, &Str );        
                    lTrnLen -= iHeadLen;
                    TRACE2("Key: %s\tValue: %s\n", Str.szKey, Str.szValue );
                    TRACE3("Len: %hd\tValLen: %hd\tType: %hd\n", Str.wBlockLen, Str.wValueLen, Str.wType );
                
                    strcpy(szCaption, Str.szValue);
                    // Check if this Item has been updated
                    if ((lpResItem = GetItem( lpBuf, dwNewSize, Str.szKey)))  {
                        strcpy( szUpdCaption, lpResItem->lpszCaption );
                        strcpy( szUpdKey, lpResItem->lpszClassName );
                    }   
                    if (!strcmp( szUpdKey, Str.szKey)) {
                        strcpy( szCaption, szUpdCaption );
                        wUpdPos = 0;
                    }  
                
                    // Write the block in the new image
                    wStrBlockSize = PutVSBlock( &lpNewImage, &dwNewImageSize, Str, 
                                                 szCaption, &lpStrBlockSize, &wTrash );
                    dwOverAllSize += wStrBlockSize+wTrash;
                
                    // Fix up the size of the block
                    if (dwNewImageSize>=0) 
                        memcpy( lpStrBlockSize, &wStrBlockSize, 2);
                
                    wTrnBlockSize += wStrBlockSize + wTrash;
                }
                lSFILen -= Trn.wBlockLen;          
                // Fix up the size of the block
                if (dwNewImageSize>=0) 
                    memcpy( lpTrnBlockSize, &wTrnBlockSize, 2);
            
                wSFIBlockSize += wTrnBlockSize;
            }
            lVS_INFOLen -= SFI.wBlockLen;      
            // Fix up the size of the block
            if (dwNewImageSize>=0) 
                memcpy( lpSFIBlockSize, &wSFIBlockSize, 2);
            wVerBlockSize += wSFIBlockSize;
        
        } else {
            // this is another block skip it all
            lVS_INFOLen -= SFI.wValueLen+iHeadLen;
         
            // Check if this block is the translation field
            if (!strcmp(SFI.szKey, "Translation")) {
                // it is calculate the right value to place in the value field
                // We calculate automatically the value to have the correct
                // localized language in the translation field
                //wVerBlockSize += PutTranslation( &lpNewImage, &dwNewImageSize, SFI );
                // check if this is the translation block
                // This is the translation block let the localizer have it for now
                /*    
                if ((lpResItem = GetItem( lpBuf, dwNewSize, SFI.szKey)))  
                    strcpy( szUpdCaption, lpResItem->lpszCaption );
                // Convert the value back in numbers
                DWORD dwCodeLang = strtol( szUpdCaption, '\0', 16);
                */  
                              
                // 
                // We do generate the Tranlsation filed from the language
                // We will have to update the block name as well
                //
            
                DWORD dwCodeLang = 0;
                if ((lpResItem = GetItem( lpBuf, dwNewSize, SFI.szKey)))  
                    dwCodeLang = GenerateTransField((WORD)LOWORD(lpResItem->dwLanguage), FALSE);
                else {
                    // Place the original value here
                    dwCodeLang =(DWORD)*(SFI.pValue);
                }
                LONG lDummy = 4;
                SFI.pValue -= PutDWord( &SFI.pValue, dwCodeLang, &lDummy );  
            
            }   
        
            // Write the block in the new image
            wVerBlockSize += PutVSBlock( &lpNewImage, &dwNewImageSize, SFI, 
                                         &SFI.szValue[0], &lpDummy, &wTrash );
            if (dwNewImageSize>=0) 
                memcpy( lpVerBlockSize, &wVerBlockSize, 2);
    
            dwOverAllSize = wVerBlockSize+wTrash;
    
        }
    }

    // fix up the block size
    if (dwNewImageSize>=0) 
        memcpy( lpVerBlockSize, &wVerBlockSize, 2);

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}                                               


static
UINT ParseAccel( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{   
    TRACE("ParseAccelerator: \n");
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;
    LONG lDummy;    
    LONG dwOverAllSize = 0L;
    WORD wPos = 0;    
    BYTE fFlags = 0;
    WORD wEvent = 0;
    WORD wId = 0;

    // Reset the IDArray
    CalcID(0, FALSE);
    while(dwImageSize>0){                                
        wPos++;
        GetByte( &lpImage, &fFlags, &dwImageSize );
        GetWord( &lpImage, &wEvent, &dwImageSize );
        GetWord( &lpImage, &wId, &dwImageSize );
        if(fFlags & 0x80) 
            dwImageSize = 0;
        
        // Fixed field                                    
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        // We don't have the size and pos in an accelerator
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    
        // we don't have checksum and style                        
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)wEvent, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        //Put the Flag
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)fFlags, &dwBufSize);
        // we will need to calculate the correct ID for mike
        //Put the Id
        dwOverAllSize += PutDWord( &lpBuf, CalcID(wId, TRUE), &dwBufSize);
    
    
        // we don't have the resID, and the Type Id
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the language                                    
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the codepage or the font name
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
                               
        // Let's put null were we don;t have the strings     
        uiOffset = sizeof(RESITEM);           
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    
        // Put the size of the resource             
        if (dwBufSize>=0) {
            lDummy = 8;
            PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
        }
    
        // Move to the next position
        lpItem = lpBuf;
        /*
        if (dwImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==(dwImageSize))
                dwImageSize = -1;
        }
        */
    }
    return (UINT)(dwOverAllSize);
}

#ifdef VB
static
UINT ParseVBData( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{
// The following special format is used by VB for international messages
// The code here is mostly copied from the ParseMenu routine

	// UGLY!!  The following values are taken from GLOBALS.C in TMSB.
	// I have added a couple not in use by VB in hopes not to re-build
	// when they decide to add additionals
	enum LOCALE {
		FRENCH = 0x040C,
		GERMAN = 0x0407,
		SPANISH = 0X040A,
		DANISH = 0X0406,
		ITALIAN = 0X0410,
		RUSSIAN = 0X0419,
		JAPANESE = 0X0411,
		PORTUGUESE = 0X0816,
		DUTCH = 0X0413 };
//		       {3,0x041D,850,"Swedish",""},
//		       {4,0x0414,850,"Norwegian Bokm�l","NOB"},
//		       {5,0x0814,850,"Norwegian Nynorsk","NON"},
//		       {6,0x040B,850,"Finnish","FIN"},
//		       {7,0x0C0C,863,"French Canadian","FRC"},
//		       {9,0x0416,850,"Portuguese (Brazilian)","BPO"},
//		       {10,0x0816,850,"Portuguese (Portugal)","PPO"},
//		       {17,0x0415,850,"Polish","POL"},
//		       {18,0x040E,850,"Hungarian","HUN"},
//		       {19,0x0405,850,"Czech","CZE"},
//		       {20,0x0401,864,"Arabic","ARA"},
//		       {21,0x040D,862,"Hebrew","HBR"},
//		       {23,0x0412,934,"Korean","KOR"},
//		       {24,0x041E,938,"Thai","THA"},
//		       {25,0x0404,936,"Chinese (Traditional)","CHI (Tra)"},
//		       {26,0x0404,936,"Chinese (Simplified)","CHI (Sim)"},
	WORD wSig, wID;
	LONG dwImageSize = dwISize;
	LONG dwOverAllSize = 0L;
	LONG lDummy;
	BYTE far * lpImage = (BYTE far *)lpImageBuf;
	static char szWork[MAXSTR];
    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;

	GetWord( &lpImage, &wSig, &dwImageSize);
	if ( wSig != RES_SIGNATURE )	// Not a VB resource
		return 0;
	GetWord( &lpImage, &wSig, &dwImageSize);
	if ( wSig != 0 )				// Header should have zero ID
		return 0;
	GetString( &lpImage, &szWork[0], &dwImageSize );
	LOCALE locale = (LOCALE)GetPrivateProfileInt("AUTOTRANS","Locale", 0, "ESPRESSO.INI");
	if (( lstrcmp(szWork, "VBINTLSZ_FRENCH") == 0 && locale == FRENCH) ||
		( lstrcmp(szWork, "VBINTLSZ_GERMAN") == 0 && locale == GERMAN) ||
		( lstrcmp(szWork, "VBINTLSZ_ITALIAN") == 0 && locale == ITALIAN) ||
		( lstrcmp(szWork, "VBINTLSZ_JAPANESE") == 0 && locale == JAPANESE) ||
		( lstrcmp(szWork, "VBINTLSZ_SPANISH") == 0 && locale == SPANISH) ||
		( lstrcmp(szWork, "VBINTLSZ_DANISH") == 0 && locale == DANISH) ||
		( lstrcmp(szWork, "VBINTLSZ_DUTCH") == 0 && locale == DUTCH) ||
		( lstrcmp(szWork, "VBINTLSZ_PORTUGUESE") == 0 && locale == PORTUGUESE)
		)
	{
		while ( dwImageSize > 0 )
		{
			GetWord( &lpImage, &wSig, &dwImageSize);
			// Check for only padding remaining and exit
			if ( wSig != RES_SIGNATURE )
				if ( dwImageSize < 16 && *(BYTE *)lpImage == 0 )
					break;
				else
	    	    	return ERROR_RW_INVALID_FILE;
			GetWord( &lpImage, &wID, &dwImageSize);	// ID
	        // Fixed field
	        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	        // We don't have the size and pos in a string
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);

	        // we don't have checksum and style
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

	        // We'll save the string's "resource" ID as an Item ID
	        dwOverAllSize += PutDWord( &lpBuf, wID, &dwBufSize);

	        // Don't save a resource ID or  Type Id
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

	        // we don't display the language
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

	        // we don't have the codepage or the font name
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);

	        // Let's put null were we don;t have the strings
	        uiOffset = sizeof(RESITEM);
	        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ClassName
	        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // FaceName
	        dwOverAllSize += PutDWord( &lpBuf, (DWORD)(lpItem+uiOffset), &dwBufSize);   // Caption
	        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ResItem
	        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // TypeItem

	        // Get the text
			GetString( &lpImage, &szWork[0], &dwImageSize );	// Text string
			dwOverAllSize += PutString( & lpBuf, &szWork[0], &dwBufSize);
	        // Put the size of the resource
	        if (dwBufSize>=0) {
	            uiOffset += strlen((LPSTR)(lpItem+uiOffset))+1;
	            lDummy = 8;
	            PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
	        }

	        // Move to the next position
	        lpItem = lpBuf;
	        if (dwImageSize<=16) {
	            // Check if we are at the end and this is just padding
	            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
	            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
	            if (bPad==(dwImageSize))
	                dwImageSize = -1;
	        }
		}
	    return (UINT)(dwOverAllSize);
	}
	return 0;

}
#endif


static
UINT
UpdateAccel( LPVOID lpNewBuf, LONG dwNewSize,  
            LPVOID lpOldI, LONG dwOldImageSize,
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{   
    TRACE("UpdateAccel\n");

    UINT uiError = ERROR_NO_ERROR;              

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;
    DWORD dwOriginalOldSize = dwOldImageSize;
                        
    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                                   
                        
    LPRESITEM lpResItem = LPNULL;


    //Old Items 
    BYTE fFlags = 0;
    WORD wEvent = 0;
    WORD wId = 0;
    WORD wPos = 0;

    // Updated items
    BYTE fUpdFlags = 0;
    WORD wUpdEvent = 0;
    WORD wUpdId = 0;
    WORD wUpdPos = 0;

    LONG  dwOverAllSize = 0l;


    while(dwOldImageSize>0) {
        wPos++;
        // Get the information from the old image
        GetByte( &lpOldImage, &fFlags, &dwOldImageSize );
        GetWord( &lpOldImage, &wEvent, &dwOldImageSize );
        GetWord( &lpOldImage, &wId, &dwOldImageSize );
        if(fFlags & 0x80) 
            dwOldImageSize = 0;
    
    
        if ((!wUpdPos) && dwNewSize ) {
            lpResItem = (LPRESITEM) lpBuf;
        
            wUpdId = LOWORD(lpResItem->dwItemID);
            wUpdPos = HIWORD(lpResItem->dwItemID);
            fUpdFlags = (BYTE)lpResItem->dwFlags;
            wUpdEvent = (WORD)lpResItem->dwStyle;
            lpBuf += lpResItem->dwSize;    
            dwNewSize -= lpResItem->dwSize;
        }
    
        TRACE3("Old Accel: wID: %hd\t wEvent: %hd\t wFlag: %hd\n", wId, wEvent, fFlags);
        TRACE3("New Accel: wID: %hd\t wEvent: %hd\t wFlag: %hd\n", wUpdId, wUpdEvent, fUpdFlags);
    
    
        if ((wPos==wUpdPos) && (wUpdId==wId)) {
    
            if(fFlags & 0x80) 
                fFlags = fUpdFlags | 0x80;
            else fFlags = fUpdFlags;
            wEvent = wUpdEvent;
            wUpdPos = 0;
        }       
      
        dwOverAllSize += PutByte( &lpNewImage, fFlags, &dwNewImageSize); 
        dwOverAllSize += PutWord( &lpNewImage, wEvent, &dwNewImageSize);
        dwOverAllSize += PutWord( &lpNewImage, wId, &dwNewImageSize);
    
        /*
        if (dwOldImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwOriginalOldSize-dwOldImageSize));                        
            if (bPad==dwOldImageSize) 
                dwOldImageSize = 0;  
        
        }   
        */
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}                                               


static                                                  
UINT
ParseMenu( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{                                  

    // Should be almost impossible for a Menu to be Huge
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;
    LONG lDummy;

    LONG dwOverAllSize = 0L;

    // skip the menu header         
    SkipByte( &lpImage, 4, &dwImageSize );

    // Menu Items
    WORD fItemFlags;
    WORD wMenuId;
    static char    szCaption[MAXSTR];

    int iter = 1;
    while(dwImageSize>0) {

         // Let's get the Menu flags
        GetWord( &lpImage, &fItemFlags, &dwImageSize );
    
        if ( !(fItemFlags & MF_POPUP) )
            // Get the menu Id 
            GetWord( &lpImage, &wMenuId, &dwImageSize );
        else wMenuId = (WORD)-1;
    
        // Get the text
        GetString( &lpImage, &szCaption[0], &dwImageSize ); 
    
        // Check if is not a separator or padding
		  // Fixed field                                    
	     dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	     // We don't have the size and pos in a menu
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	     
	     // we don't have checksum and style                        
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     
	     //Put the Flag
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)fItemFlags, &dwBufSize);
	     //Put the MenuId
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)wMenuId, &dwBufSize);
	     
	     // we don't have the resID, and the Type Id
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     
	     // we don't have the language                                    
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     
	     // we don't have the codepage or the font name
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	     dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
	                                                        
	     // Let's put null were we don;t have the strings     
	     uiOffset = sizeof(RESITEM);           
	     dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, (DWORD)(lpItem+uiOffset), &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	     dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
	     
	     // Get the text
	     // calculate were the string is going to be
	     // Will be the fixed header+the pointer
 	     dwOverAllSize += PutString( &lpBuf, &szCaption[0], &dwBufSize);
	     
         TRACE("Menu: Iteration %d size %d\n", iter++, dwOverAllSize);
	     // Put the size of the resource             
         uiOffset += strlen(szCaption)+1;
         // Check if we are alligned
         lDummy = Allign( &lpBuf, &dwBufSize, (LONG)uiOffset);
         dwOverAllSize += lDummy;
         uiOffset += lDummy;
         lDummy = 4;
         if(dwBufSize>=0)
            PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
         
	     // Move to the next position
	     lpItem = lpBuf;
        
         if (dwImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==dwImageSize) {
				BYTE far * lpBuf = lpImage;
				while (bPad){
					if(*lpBuf++!=0x00) 
						break;
					bPad--;
				}
				if (bPad==0)
					dwImageSize = -1;
			}
        } 
    }      


    return (UINT)(dwOverAllSize);
}   

static
UINT
UpdateMenu( LPVOID lpNewBuf, LONG dwNewSize,  
            LPVOID lpOldI, LONG dwOldImageSize,
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{   
    UINT uiError = ERROR_NO_ERROR;              

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;
    DWORD dwOriginalOldSize = dwOldImageSize;
                                            
    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                               
                                            
    LPRESITEM lpResItem = LPNULL;

    // We have to read the information from the lpNewBuf
    // Menu Items
    WORD fItemFlags;
    WORD wMenuId;
    char szTxt[256];
    WORD wPos = 0;  

    // Updated items
    WORD wUpdPos = 0;       
    WORD fUpdItemFlags;
    WORD wUpdMenuId;
    char szUpdTxt[256];

    LONG  dwOverAllSize = 0l;


    // Copy the menu flags   
    dwOldImageSize -= PutDWord( &lpNewImage, *((DWORD*)lpOldImage), &dwNewImageSize);
    lpOldImage += sizeofDWord;
    dwOverAllSize += sizeofDWord;

    while(dwOldImageSize>0) {
        wPos++;
        // Get the information from the old image
        // Get the menu flag                     
        GetWord( &lpOldImage, &fItemFlags, &dwOldImageSize );
    
        if ( !(fItemFlags & MF_POPUP) ) 
            GetWord( &lpOldImage, &wMenuId, &dwOldImageSize );
        else wMenuId = (WORD)-1;
    
        // Get the text
        GetString( &lpOldImage, &szTxt[0], &dwOldImageSize );
    
        if ((!wUpdPos) && dwNewSize ) {
            lpResItem = (LPRESITEM) lpBuf;
                        
            wUpdPos = HIWORD(lpResItem->dwItemID);
            wUpdMenuId = LOWORD(lpResItem->dwItemID);
            fUpdItemFlags = (WORD)lpResItem->dwFlags;
            strcpy( szUpdTxt, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;    
            dwNewSize -= lpResItem->dwSize;
        }
    
        if ((wPos==wUpdPos) && (wUpdMenuId==wMenuId)) {
             // check if it is not the last item in the menu
	        if(fItemFlags & MF_END)
	                fItemFlags = fUpdItemFlags | (WORD)MF_END;  
	        else fItemFlags = fUpdItemFlags;
 
            wMenuId = wUpdMenuId;  
        
            // check it is not a separator
            if((fItemFlags==0) && (wMenuId==0))
                strcpy(szTxt, "");
            else strcpy(szTxt, szUpdTxt);
            wUpdPos = 0;
        }         
        dwOverAllSize += PutWord( &lpNewImage, fItemFlags, &dwNewImageSize);
    
        if ( !(fItemFlags & MF_POPUP) ) {
            dwOverAllSize += PutWord( &lpNewImage, wMenuId, &dwNewImageSize);
        }
    
        // Write the text
        dwOverAllSize += PutString( &lpNewImage, &szTxt[0], &dwNewImageSize);

		  // Check for padding
        if (dwOldImageSize<=16) {
            // Check if we are at the end and this is just padding
	         BYTE bPad = (BYTE)Pad16((dwOriginalOldSize-dwOldImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwOldImageSize, bPad );
            if (bPad==dwOldImageSize) {
				BYTE far * lpBuf = lpOldImage;
				while (bPad){
					if(*lpBuf++!=0x00) 
						break;
					bPad--;
				}
				if (bPad==0)
					dwOldImageSize = -1;
			}
        } 
    
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}                       

static UINT GenerateMenu( LPVOID lpNewBuf, LONG dwNewSize,  
                          LPVOID lpNewI, DWORD* pdwNewImageSize )
{
    UINT uiError = ERROR_NO_ERROR;              

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                               
                                            
    LPRESITEM lpResItem = LPNULL;

    // We have to read the information from the lpNewBuf
    // Updated items
    WORD wUpdPos = 0;       
    WORD fUpdItemFlags;
    WORD wUpdMenuId;
    char szUpdTxt[256];

    LONG  dwOverAllSize = 0l;

    // invent the menu flags   
    dwOverAllSize += PutDWord( &lpNewImage, 0L, &dwNewImageSize);

    while(dwNewSize>0) {
        if (dwNewSize ) {
            lpResItem = (LPRESITEM) lpBuf;
        
            wUpdMenuId = LOWORD(lpResItem->dwItemID);
            fUpdItemFlags = (WORD)lpResItem->dwFlags;
            strcpy( szUpdTxt, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;    
            dwNewSize -= lpResItem->dwSize;
        }
    
        dwOverAllSize += PutWord( &lpNewImage, fUpdItemFlags, &dwNewImageSize);
    
        if ( !(fUpdItemFlags & MF_POPUP) ) 
            dwOverAllSize += PutWord( &lpNewImage, wUpdMenuId, &dwNewImageSize);
    
        // Write the text
        // check if it is a separator
        if ( !(fUpdItemFlags) && !(wUpdMenuId) )                                           
            szUpdTxt[0] = 0x00; 
        dwOverAllSize += PutString( &lpNewImage, &szUpdTxt[0], &dwNewImageSize);
    
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}

static
UINT
ParseString( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{

    // Should be almost impossible for a String to be Huge
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize;

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;   

    BYTE far * lpItem = (BYTE far *)lpBuffer;
    UINT uiOffset = 0;
    LONG lDummy;

    LONG dwOverAllSize = 0L;

    LONG dwRead = 0L; 

    BYTE bIdCount = 0;

    while( (dwImageSize>0) && (bIdCount<16)  ) {
        // Fixed field                                    
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
        // We don't have the size and pos in a string
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
    
        // we don't have checksum and style                        
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        //Put the StringId
        dwOverAllSize += PutDWord( &lpBuf, bIdCount++, &dwBufSize);
            
        // we don't have the resID, and the Type Id
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the language                                    
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        // we don't have the codepage or the font name
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, (WORD)-1, &dwBufSize);
                                                       
        // Let's put null were we don;t have the strings     
        uiOffset = sizeof(RESITEM);
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ClassName
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // FaceName
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)(lpItem+uiOffset), &dwBufSize);   // Caption
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ResItem
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // TypeItem
    
        // Get the text
        BYTE bstrlen = *lpImage++; 
        dwImageSize -= 1;
        TRACE1("StrLen: %hd\t", bstrlen);
        if ((bstrlen+1)>dwBufSize) {
            dwOverAllSize += bstrlen+1;
            dwImageSize -= bstrlen;
            lpImage += bstrlen;
            dwBufSize -= bstrlen+1;
            TRACE1("BufferSize: %ld\n", dwBufSize);
        } else {
            if (bstrlen)
                memcpy( (char*)lpBuf, (char*)lpImage, bstrlen );
        
            *(lpBuf+(bstrlen)) = 0; 
            TRACE1("Caption: %Fs\n", lpBuf);
            lpImage += bstrlen;
            lpBuf += bstrlen+1;
            dwImageSize -= bstrlen;
            dwBufSize -= bstrlen+1;
            dwOverAllSize += bstrlen+1;
        }              
    
    
        // Put the size of the resource             
        uiOffset += bstrlen+1;
        // Check if we are alligned
        lDummy = Allign( &lpBuf, &dwBufSize, (LONG)uiOffset);
        dwOverAllSize += lDummy;
        uiOffset += lDummy;
        lDummy = 4;
        if(dwBufSize>=0)
            PutDWord( &lpItem, (DWORD)uiOffset, &lDummy);
        
        // Move to the next position
        lpItem = lpBuf;
        if ((dwImageSize<=16) && (bIdCount==16)) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));                        
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==dwImageSize)
                dwImageSize = -1;
        }
    }      


    return (UINT)(dwOverAllSize);
}    

static
UINT
UpdateString( LPVOID lpNewBuf, LONG dwNewSize,  
            LPVOID lpOldI, LONG dwOldImageSize,
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{
    UINT uiError = ERROR_NO_ERROR;

    LONG dwNewImageSize = *pdwNewImageSize;
    BYTE far * lpNewImage = (BYTE far *) lpNewI;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                               
    LPRESITEM lpResItem = LPNULL;

    // We have to read the information from the lpNewBuf
    BYTE bLen;
    char szTxt[MAXSTR];
    WORD wPos = 0;

    // Updated info
    WORD wUpdPos = 0;       
    char szUpdTxt[MAXSTR];

    DWORD dwOriginalOldSize = dwOldImageSize;
    LONG dwOverAllSize = 0l;

    while(dwOldImageSize>0) {
        wPos++;
        // Get the information from the old image
        GetByte( &lpOldImage, &bLen, &dwOldImageSize );

        // Copy the text
        if (bLen>MAXSTR) {
        
        } else {
            memcpy( szTxt, (char*)lpOldImage, bLen );
            lpOldImage += bLen;
            dwOldImageSize -= bLen;
            szTxt[bLen]='\0';
        } 
    
        if ((!wUpdPos) && dwNewSize ) {
            /*
            GetUpdatedItem( 
                            &lpNewBuf, &dwNewSize,
                            &wDummy, &wDummy,
                            &wDummy, &wDummy,
                            &dwPosId, 
                            &dwDummy, &dwDummy, 
                            &szUpdTxt[0]);
                        
            wUpdPos = HIWORD(dwPosId);
            */
            lpResItem = (LPRESITEM) lpBuf;
                        
            wUpdPos = HIWORD(lpResItem->dwItemID);
            strcpy( szUpdTxt, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;
            dwNewSize -= lpResItem->dwSize;
        }
    
        if ((wPos==wUpdPos)) {
            strcpy(szTxt, szUpdTxt);
            wUpdPos = 0;
        }           
                  
        bLen = strlen(szTxt);
        //dwOverAllSize += PutByte( &lpNewImage, (BYTE)bLen, &dwNewImageSize);
    
        // Write the text             
        dwOverAllSize += PutPascalString( &lpNewImage, &szTxt[0], bLen, &dwNewImageSize );
    
        if ((dwOldImageSize<=16) && (wPos==16)) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwOriginalOldSize-dwOldImageSize));                        
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==dwOldImageSize)
                dwOldImageSize = -1;
        }
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}

static
UINT
GenerateString( LPVOID lpNewBuf, LONG dwNewSize,  
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{
    UINT uiError = ERROR_NO_ERROR;

    LONG dwNewImageSize = *pdwNewImageSize;
    BYTE far * lpNewImage = (BYTE far *) lpNewI;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                               
    LPRESITEM lpResItem = LPNULL;

    // We have to read the information from the lpNewBuf
    BYTE bLen;
    static char szTxt[MAXSTR];
    WORD wPos = 0;

    LONG dwOverAllSize = 0l;

    while(dwNewSize>0) {
        if ( dwNewSize ) {
            lpResItem = (LPRESITEM) lpBuf;
                        
            strcpy( szTxt, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;
            dwNewSize -= lpResItem->dwSize;
        }
    
        bLen = strlen(szTxt);
    
        // Write the text             
        dwOverAllSize += PutPascalString( &lpNewImage, &szTxt[0], bLen, &dwNewImageSize );
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}


static                                                  
UINT
ParseDialog( LPVOID lpImageBuf, DWORD dwISize,  LPVOID lpBuffer, DWORD dwSize )
{                                  

    // Should be almost impossible for a Dialog to be Huge
    BYTE far * lpImage = (BYTE far *)lpImageBuf;
    LONG dwImageSize = dwISize; 

    BYTE far * lpBuf = (BYTE far *)lpBuffer;
    LONG dwBufSize = dwSize;           

    LPRESITEM lpResItem = (LPRESITEM)lpBuffer;
    UINT uiOffset = 0;

    char far * lpStrBuf = (char far *)(lpBuf+sizeof(RESITEM));

    LONG dwOverAllSize = 0L;            

    BYTE    bIdCount = 0;
    
    // Dialog Elements
    DWORD   dwStyle = 0L;
    BYTE    bNumOfElem = 0;
    WORD    wX = 0;
    WORD    wY = 0;
    WORD    wcX = 0;
    WORD    wcY = 0;
    WORD    wId = 0;
    static char    szMenuName[MAXID];
    WORD    wMenuName;
    static char    szClassName[MAXID];
    BYTE    bClassName, bControlClassName;
    static char    szCaption[MAXSTR];
    WORD    wOrd;
    WORD    wPointSize = 0;
    static char    szFaceName[MAXID];

    // read the dialog header         
    GetDWord( &lpImage, &dwStyle, &dwImageSize );
    GetByte( &lpImage, &bNumOfElem, &dwImageSize );
    GetWord( &lpImage, &wX, &dwImageSize );
    GetWord( &lpImage, &wY, &dwImageSize );
    GetWord( &lpImage, &wcX, &dwImageSize );
    GetWord( &lpImage, &wcY, &dwImageSize );
    GetNameOrOrd( &lpImage, &wMenuName, &szMenuName[0], &dwImageSize );
    GetClassName( &lpImage, &bClassName, &szClassName[0], &dwImageSize );
    GetCaptionOrOrd( &lpImage, &wOrd, &szCaption[0], &dwImageSize,
    	bClassName, dwStyle );
    if( dwStyle & DS_SETFONT ) {
        GetWord( &lpImage, &wPointSize, &dwImageSize );
        GetString( &lpImage, &szFaceName[0], &dwImageSize );
    }

    TRACE("Win16.DLL ParseDialog\t");       
    TRACE1("NumElem: %hd\t", bNumOfElem);
    TRACE1("X %hd\t", wX);
    TRACE1("Y: %hd\t", wY);
    TRACE1("CX: %hd\t", wcX);
    TRACE1("CY: %hd\t", wcY);
    TRACE1("Id: %hd\t", wId);
    TRACE1("Style: %lu\n", dwStyle);
    TRACE1("Caption: %s\n", szCaption);
    TRACE2("ClassName: %s\tClassId: %hd\n", szClassName, bClassName );
    TRACE2("MenuName: %s\tMenuId: %hd\n", szMenuName, wMenuName );
    TRACE2("FontName: %s\tPoint: %hd\n", szFaceName, wPointSize );

    // Fixed field                                    
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);

    dwOverAllSize += PutWord( &lpBuf, wX, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, wY, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, wcX, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, wcY, &dwBufSize);
    
    // we don't have checksum and extended style                        
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, dwStyle, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
    //Put the Id 0 for the main dialog
    dwOverAllSize += PutDWord( &lpBuf, bIdCount++, &dwBufSize);
            
    // we don't have the resID, and the Type Id
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
    // we don't have the language                                    
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
    // we don't have the codepage
    dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);

    dwOverAllSize += PutWord( &lpBuf, bClassName, &dwBufSize);
    dwOverAllSize += PutWord( &lpBuf, wPointSize, &dwBufSize);
                               
    // Let's put null were we don;t have the strings     
    uiOffset = sizeof(RESITEM);           
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ClassName
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // FaceName
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // Caption
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ResItem
    dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // TypeItem

    lpResItem->lpszClassName = strcpy( lpStrBuf, szClassName );
    lpStrBuf += strlen(lpResItem->lpszClassName)+1;

    lpResItem->lpszFaceName = strcpy( lpStrBuf, szFaceName );
    lpStrBuf += strlen(lpResItem->lpszFaceName)+1;

    lpResItem->lpszCaption = strcpy( lpStrBuf, szCaption );
    lpStrBuf += strlen(lpResItem->lpszCaption)+1;

    // Put the size of the resource             
    if (dwBufSize>0) {
        uiOffset += strlen((LPSTR)(lpResItem->lpszClassName))+1;
        uiOffset += strlen((LPSTR)(lpResItem->lpszFaceName))+1;
        uiOffset += strlen((LPSTR)(lpResItem->lpszCaption))+1;
    }

    // Check if we are alligned
    uiOffset += Allign( (BYTE**)&lpStrBuf, &dwBufSize, (LONG)uiOffset);

    dwOverAllSize += uiOffset-sizeof(RESITEM);
    lpResItem->dwSize = (DWORD)uiOffset;
    
    // Move to the next position
    lpResItem = (LPRESITEM) lpStrBuf;
    lpBuf = (BYTE far *)lpStrBuf;
    lpStrBuf = (char far *)(lpBuf+sizeof(RESITEM));

    while( (dwImageSize>0) && (bNumOfElem>0) ) {
        // Read the COntrols
        GetWord( &lpImage, &wX, &dwImageSize );
        GetWord( &lpImage, &wY, &dwImageSize );
        GetWord( &lpImage, &wcX, &dwImageSize );
        GetWord( &lpImage, &wcY, &dwImageSize );
        GetWord( &lpImage, &wId, &dwImageSize );
        GetDWord( &lpImage, &dwStyle, &dwImageSize );
        GetControlClassName( &lpImage, &bControlClassName, &szClassName[0], &dwImageSize );
        GetCaptionOrOrd( &lpImage, &wOrd, &szCaption[0], &dwImageSize,
    		bControlClassName, dwStyle );
        SkipByte( &lpImage, 1, &dwImageSize );
        bNumOfElem--;
        // Fixed field                                    
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);
    
        dwOverAllSize += PutWord( &lpBuf, wX, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, wY, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, wcX, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, wcY, &dwBufSize);
        
        // we don't have checksum and extended style                        
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, dwStyle, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        
        //Put the Id 
        dwOverAllSize += PutDWord( &lpBuf, wId, &dwBufSize);
                
        // we don't have the resID, and the Type Id
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        
        // we don't have the language                                    
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
        
        // we don't have the codepage
        dwOverAllSize += PutDWord( &lpBuf, (DWORD)-1, &dwBufSize);
    
        dwOverAllSize += PutWord( &lpBuf, bControlClassName, &dwBufSize);
        dwOverAllSize += PutWord( &lpBuf, wPointSize, &dwBufSize);
                                   
        // Let's put null were we don;t have the strings     
        uiOffset = sizeof(RESITEM);           
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ClassName
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // FaceName
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // Caption
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // ResItem
        dwOverAllSize += PutDWord( &lpBuf, 0, &dwBufSize);  // TypeItem
    
        lpResItem->lpszClassName = strcpy( lpStrBuf, szClassName );
        lpStrBuf += strlen(lpResItem->lpszClassName)+1;
    
        lpResItem->lpszFaceName = strcpy( lpStrBuf, szFaceName );
        lpStrBuf += strlen(lpResItem->lpszFaceName)+1;
    
        lpResItem->lpszCaption = strcpy( lpStrBuf, szCaption );
        lpStrBuf += strlen(lpResItem->lpszCaption)+1;
    
        // Put the size of the resource             
        if (dwBufSize>0) {
            uiOffset += strlen((LPSTR)(lpResItem->lpszClassName))+1;
            uiOffset += strlen((LPSTR)(lpResItem->lpszFaceName))+1;
            uiOffset += strlen((LPSTR)(lpResItem->lpszCaption))+1;
        }
    
        // Check if we are alligned
        uiOffset += Allign( (BYTE**)&lpStrBuf, &dwBufSize, (LONG)uiOffset);
        dwOverAllSize += uiOffset-sizeof(RESITEM);
        lpResItem->dwSize = (DWORD)uiOffset;
        
        // Move to the next position
        lpResItem = (LPRESITEM) lpStrBuf;
        lpBuf = (BYTE far *)lpStrBuf;
        lpStrBuf = (char far *)(lpBuf+sizeof(RESITEM));
    
        TRACE1("\tControl: X: %hd\t", wX);
        TRACE1("Y: %hd\t", wY);
        TRACE1("CX: %hd\t", wcX);
        TRACE1("CY: %hd\t", wcY);
        TRACE1("Id: %hd\t", wId);
        TRACE1("Style: %lu\n", dwStyle);
        TRACE1("Caption: %s\n", szCaption);
    
        if (dwImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwISize-dwImageSize));
            //TRACE3(" dwRead: %lu\t dwImageSize: %lu\t Pad: %hd\n", dwRead, dwImageSize, bPad );
            if (bPad==dwImageSize)
                dwImageSize = -1;
        }
    }      


    return (UINT)(dwOverAllSize);
}   

static
UINT
UpdateDialog( LPVOID lpNewBuf, LONG dwNewSize,  
            LPVOID lpOldI, LONG dwOldImageSize,
            LPVOID lpNewI, DWORD* pdwNewImageSize )
{   
    // Should be almost impossible for a Dialog to be Huge
    UINT uiError = ERROR_NO_ERROR;              

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpOldImage = (BYTE far *) lpOldI;
    DWORD dwOriginalOldSize = dwOldImageSize;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                                   
    LPRESITEM lpResItem = LPNULL;

    LONG dwOverAllSize = 0L;            

    BYTE    bIdCount = 0;
    
    // Dialog Elements
    DWORD   dwStyle = 0L;
    BYTE    bNumOfElem = 0;
    WORD    wX = 0;
    WORD    wY = 0;
    WORD    wcX = 0;
    WORD    wcY = 0;
    WORD    wId = 0;
    static char    szMenuName[MAXID];
    WORD    wMenuName;
    static char    szClassName[MAXID];
    BYTE    bClassName, bControlClassName;
    static char    szCaption[MAXSTR];
    WORD    wOrd = 0;
    WORD    wPointSize = 0;
    static char    szFaceName[MAXID];
    WORD    wPos = 1;

    // Updated elements
    WORD    wUpdX = 0;
    WORD    wUpdY = 0;
    WORD    wUpdcX = 0;
    WORD    wUpdcY = 0;
    DWORD   dwUpdStyle = 0l;
    DWORD   dwPosId = 0l;
    static char    szUpdCaption[MAXSTR];
    static char    szUpdFaceName[MAXID];
    WORD    wUpdPointSize = 0;
    WORD    wUpdPos = 0;

    // read the dialog header         
    GetDWord( &lpOldImage, &dwStyle, &dwOldImageSize );
    GetByte( &lpOldImage, &bNumOfElem, &dwOldImageSize );
    GetWord( &lpOldImage, &wX, &dwOldImageSize );
    GetWord( &lpOldImage, &wY, &dwOldImageSize );
    GetWord( &lpOldImage, &wcX, &dwOldImageSize );
    GetWord( &lpOldImage, &wcY, &dwOldImageSize );
    GetNameOrOrd( &lpOldImage, &wMenuName, &szMenuName[0], &dwOldImageSize );
    GetClassName( &lpOldImage, &bClassName, &szClassName[0], &dwOldImageSize );
    GetCaptionOrOrd( &lpOldImage, &wOrd, &szCaption[0], &dwOldImageSize,
    	bClassName, dwStyle );
    if( dwStyle & DS_SETFONT ) {
        GetWord( &lpOldImage, &wPointSize, &dwOldImageSize );
        GetString( &lpOldImage, &szFaceName[0], &dwOldImageSize );
    }

    // Get the infrmation from the updated resource
    if ((!wUpdPos) && dwNewSize ) {
        lpResItem = (LPRESITEM) lpBuf;
        wUpdX = lpResItem->wX;
        wUpdY = lpResItem->wY;
        wUpdcX = lpResItem->wcX;
        wUpdcY = lpResItem->wcY;
        wUpdPointSize = lpResItem->wPointSize;
        dwUpdStyle = lpResItem->dwStyle;
        dwPosId = lpResItem->dwItemID;
        strcpy( szUpdCaption, lpResItem->lpszCaption );
        strcpy( szUpdFaceName, lpResItem->lpszFaceName );
        lpBuf += lpResItem->dwSize;        
        dwNewSize -= lpResItem->dwSize;
    }
    // check if we have to update the header
    if ((HIWORD(dwPosId)==wPos) && (LOWORD(dwPosId)==wId)) {
        wX = wUpdX;
        wY = wUpdY;
        wcX = wUpdcX;
        wcY = wUpdcY;                     
        wPointSize = wUpdPointSize;
        dwStyle = dwUpdStyle;
        strcpy(szCaption, szUpdCaption);
        strcpy(szFaceName, szUpdFaceName);
    }

    // Write the header informations
    dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
    dwOverAllSize += PutByte( &lpNewImage, bNumOfElem, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
    dwOverAllSize += PutNameOrOrd( &lpNewImage, wMenuName, &szMenuName[0], &dwNewImageSize );
    dwOverAllSize += PutClassName( &lpNewImage, bClassName, &szClassName[0], &dwNewImageSize );
    dwOverAllSize += PutCaptionOrOrd( &lpNewImage, wOrd, &szCaption[0], &dwNewImageSize,
        	bClassName, dwStyle );
    if( dwStyle & DS_SETFONT ) {
        dwOverAllSize += PutWord( &lpNewImage, wPointSize, &dwNewImageSize );
        dwOverAllSize += PutString( &lpNewImage, &szFaceName[0], &dwNewImageSize );
    }

    while( (dwOldImageSize>0) && (bNumOfElem>0) ) {
        wPos++;
        // Get the info for the control
        // Read the COntrols
        GetWord( &lpOldImage, &wX, &dwOldImageSize );
        GetWord( &lpOldImage, &wY, &dwOldImageSize );
        GetWord( &lpOldImage, &wcX, &dwOldImageSize );
        GetWord( &lpOldImage, &wcY, &dwOldImageSize );
        GetWord( &lpOldImage, &wId, &dwOldImageSize );
        GetDWord( &lpOldImage, &dwStyle, &dwOldImageSize );
        GetControlClassName( &lpOldImage, &bControlClassName, &szClassName[0], &dwOldImageSize );
        GetCaptionOrOrd( &lpOldImage, &wOrd, &szCaption[0], &dwOldImageSize,
    		bControlClassName, dwStyle );
        SkipByte( &lpOldImage, 1, &dwOldImageSize );
        bNumOfElem--;
    
        if ((!wUpdPos) && dwNewSize ) { 
            TRACE1("\t\tUpdateDialog:\tdwNewSize=%ld\n",(LONG)dwNewSize);
            TRACE1("\t\t\t\tlpszCaption=%Fs\n",lpResItem->lpszCaption);
            lpResItem = (LPRESITEM) lpBuf;
            wUpdX = lpResItem->wX;
            wUpdY = lpResItem->wY;
            wUpdcX = lpResItem->wcX;
            wUpdcY = lpResItem->wcY;
            dwUpdStyle = lpResItem->dwStyle;
            dwPosId = lpResItem->dwItemID;
            strcpy( szUpdCaption, lpResItem->lpszCaption );
            lpBuf += lpResItem->dwSize;
            dwNewSize -= lpResItem->dwSize;
        }                                       
    
        // check if we have to update the header
        if ((HIWORD(dwPosId)==wPos) && (LOWORD(dwPosId)==wId)) {
            wX = wUpdX;
            wY = wUpdY;
            wcX = wUpdcX;
            wcY = wUpdcY;
            dwStyle = dwUpdStyle;
            strcpy(szCaption, szUpdCaption);
        }
    
        //write the control 
        dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wId, &dwNewImageSize );
        dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
        dwOverAllSize += PutControlClassName( &lpNewImage, bControlClassName, &szClassName[0], &dwNewImageSize );
        dwOverAllSize += PutCaptionOrOrd( &lpNewImage, wOrd, &szCaption[0], &dwNewImageSize,
    		bControlClassName, dwStyle );                           
    	dwOverAllSize += PutByte( &lpNewImage, 0, &dwNewImageSize );
	
        if (dwOldImageSize<=16) {
            // Check if we are at the end and this is just padding
            BYTE bPad = (BYTE)Pad16((DWORD)(dwOriginalOldSize-dwOldImageSize));                        
            if (bPad==dwOldImageSize) 
                dwOldImageSize = 0;  
        }
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    return uiError;
}                                               


static
UINT
GenerateDialog( LPVOID lpNewBuf, LONG dwNewSize,  
                LPVOID lpNewI, DWORD* pdwNewImageSize )
{   
    // Should be almost impossible for a Dialog to be Huge
    UINT uiError = ERROR_NO_ERROR;              

    BYTE far * lpNewImage = (BYTE far *) lpNewI;
    LONG dwNewImageSize = *pdwNewImageSize;

    BYTE far * lpBuf = (BYTE far *) lpNewBuf;                                               
    LPRESITEM lpResItem = LPNULL;

    LONG dwOverAllSize = 0L;            

    BYTE    bIdCount = 0;
        
    // Dialog Elements
    DWORD   dwStyle = 0L;
    BYTE    bNumOfElem = 0;
    WORD    wX = 0;
    WORD    wY = 0;
    WORD    wcX = 0;
    WORD    wcY = 0;
    WORD    wId = 0;
    char    szClassName[128];
    BYTE    bClassName='\0', bControlClassName='\0';
    char    szCaption[128];
    WORD    wPointSize = 0;
    char    szFaceName[128];
    WORD    wPos = 1;

    // Get the infrmation from the updated resource
    if ( dwNewSize ) {
        lpResItem = (LPRESITEM) lpBuf;
        wX = lpResItem->wX;
        wY = lpResItem->wY;
        wcX = lpResItem->wcX;
        wcY = lpResItem->wcY;
        wId = LOWORD(lpResItem->dwItemID);
        wPointSize = lpResItem->wPointSize;
        dwStyle = lpResItem->dwStyle;                
        bClassName = LOBYTE(lpResItem->wClassName);
        strcpy( szCaption, lpResItem->lpszCaption );
        strcpy( szClassName, lpResItem->lpszClassName );
        strcpy( szFaceName, lpResItem->lpszFaceName );
        lpBuf += lpResItem->dwSize;        
        dwNewSize -= lpResItem->dwSize;
    }

    // Write the header informations
    dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );

    // Store the position of the numofelem for a later fixup
    BYTE far * lpNumOfElem = lpNewImage;
    dwOverAllSize += PutByte( &lpNewImage, bNumOfElem, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
    dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
    dwOverAllSize += PutNameOrOrd( &lpNewImage, 0, "", &dwNewImageSize );
    dwOverAllSize += PutClassName( &lpNewImage, bClassName, &szClassName[0], &dwNewImageSize );
    dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
        	bClassName, dwStyle );
    if( dwStyle & DS_SETFONT ) {
        dwOverAllSize += PutWord( &lpNewImage, wPointSize, &dwNewImageSize );
        dwOverAllSize += PutString( &lpNewImage, &szFaceName[0], &dwNewImageSize );
    }

    while( dwNewSize>0 ) {
        bNumOfElem++;
    
        if ( dwNewSize ) { 
            /*
            TRACE1("\t\tGenerateDialog:\tdwNewSize=%ld\n",(LONG)dwNewSize);
            TRACE1("\t\t\t\tlpszCaption=%Fs\n",lpResItem->lpszCaption);
            */
            lpResItem = (LPRESITEM) lpBuf;
            wX = lpResItem->wX;
            wY = lpResItem->wY;
            wcX = lpResItem->wcX;
            wcY = lpResItem->wcY;
            wId = LOWORD(lpResItem->dwItemID);
            dwStyle = lpResItem->dwStyle;
            bClassName = LOBYTE(lpResItem->wClassName);
            strcpy( szCaption, lpResItem->lpszCaption );
            strcpy( szClassName, lpResItem->lpszClassName );
            lpBuf += lpResItem->dwSize;
            dwNewSize -= lpResItem->dwSize;
        }           
            
        //write the control 
        dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
        dwOverAllSize += PutWord( &lpNewImage, wId, &dwNewImageSize );
        dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
        dwOverAllSize += PutControlClassName( &lpNewImage, bControlClassName, &szClassName[0], &dwNewImageSize );
        dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
        	bControlClassName, dwStyle );
        dwOverAllSize += PutByte( &lpNewImage, 0, &dwNewImageSize );
    }                             

    if (dwOverAllSize>(LONG)*pdwNewImageSize) {
        // calc the padding as well
        dwOverAllSize += (BYTE)Pad4((DWORD)(dwOverAllSize));
        *pdwNewImageSize = dwOverAllSize;
        return uiError;
    }
    
    *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;

    if(*pdwNewImageSize>0) {
        // calculate padding
        BYTE bPad = (BYTE)Pad4((DWORD)(*pdwNewImageSize));
        if (bPad>dwNewImageSize) {
            *pdwNewImageSize += bPad;
            return uiError;
        }
        memset(lpNewImage, 0x00, bPad);
        *pdwNewImageSize += bPad;
    }

    // fixup the number of items
    PutByte( &lpNumOfElem, bNumOfElem, &dwNewImageSize );

    return uiError;
}                       


static
BYTE
SkipByte( BYTE far * far * lplpBuf, UINT uiSkip, LONG* pdwSize )
{                
    if(*pdwSize>=(int)uiSkip) {
        *lplpBuf += uiSkip;;
        *pdwSize -= uiSkip;
    }
    return uiSkip;
}       

static 
BYTE
PutDWord( BYTE far * far* lplpBuf, DWORD dwValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofDWord && (*pdwSize != -1)){
        memcpy(*lplpBuf, &dwValue, sizeofDWord);
        *lplpBuf += sizeofDWord;
        *pdwSize -= sizeofDWord;
    } else *pdwSize = -1;
    return sizeofDWord;
}       

static 
BYTE
GetDWord( BYTE far * far* lplpBuf, DWORD* dwValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofDWord){
        memcpy( dwValue, *lplpBuf, sizeofDWord);
        *lplpBuf += sizeofDWord;
        *pdwSize -= sizeofDWord;
    }
    return sizeofDWord;
}       

static 
BYTE
PutWord( BYTE far * far* lplpBuf, WORD wValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofWord && (*pdwSize != -1)){
        memcpy(*lplpBuf, &wValue, sizeofWord);
        *lplpBuf += sizeofWord;
        *pdwSize -= sizeofWord;
    } else *pdwSize = -1;
    return sizeofWord;
}       

static 
BYTE
GetWord( BYTE far * far* lplpBuf, WORD* wValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofWord){
        memcpy( wValue, *lplpBuf, sizeofWord);
        *lplpBuf += sizeofWord;
        *pdwSize -= sizeofWord;
    }
    return sizeofWord;
}       

static 
BYTE
PutByte( BYTE far * far* lplpBuf, BYTE bValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofByte && (*pdwSize != -1)){
        memcpy(*lplpBuf, &bValue, sizeofByte);
        *lplpBuf += sizeofByte;
        *pdwSize -= sizeofByte;
    } else *pdwSize = -1;
    return sizeofByte;
}       

static 
BYTE
GetByte( BYTE far * far* lplpBuf, BYTE* bValue, LONG* pdwSize )
{                     
    if (*pdwSize>=sizeofByte){
        memcpy(bValue, *lplpBuf, sizeofByte);
        *lplpBuf += sizeofByte;
        *pdwSize -= sizeofByte;
    }
    return sizeofByte;
}

static
UINT
GetCaptionOrOrd( BYTE far * far* lplpBuf,  WORD* wOrd, LPSTR lpszText, LONG* pdwSize,
	BYTE bClass, DWORD dwStyle )
{
    UINT uiSize = 0; 

    // Icon might not have an ID so check first
    *wOrd = 0;
    // read the first BYTE to see if it is a string or an ordinal
    uiSize += GetByte( lplpBuf, (BYTE*)wOrd, pdwSize );     
    if(LOBYTE(*wOrd)==0xFF) {
        // This is an Ordinal
        uiSize += GetWord( lplpBuf, wOrd, pdwSize );    
        *lpszText = '\0';          
        uiSize = 3;
    } else {
        *lpszText++ = LOBYTE(*wOrd); 
        if (LOBYTE(*wOrd))
        uiSize += GetString( lplpBuf, lpszText, pdwSize);
        *wOrd = 0;
    }
    return uiSize;
}

static
UINT
GetNameOrOrd( BYTE far * far* lplpBuf,  WORD* wOrd, LPSTR lpszText, LONG* pdwSize )
{
    UINT uiSize = 0; 

    *wOrd = 0;
    // read the first BYTE to see if it is a string or an ordinal
    uiSize += GetByte( lplpBuf, (BYTE*)wOrd, pdwSize ); 
    if(LOBYTE(*wOrd)==0xFF) {
        // This is an Ordinal
        uiSize += GetWord( lplpBuf, wOrd, pdwSize );    
        *lpszText = '\0';          
        uiSize = 3;
    } else {
        *lpszText++ = LOBYTE(*wOrd); 
        if (LOBYTE(*wOrd))
            uiSize += GetString( lplpBuf, lpszText, pdwSize);
        *wOrd = 0;
    }
    return uiSize;
}

static
UINT
PutCaptionOrOrd( BYTE far * far* lplpBuf,  WORD wOrd, LPSTR lpszText, LONG* pdwSize,
	BYTE bClass, DWORD dwStyle )
{
    UINT uiSize = 0; 

    // If this is an ICON then can just be an ID
    if (wOrd) {
        uiSize += PutByte(lplpBuf, 0xFF, pdwSize);
        uiSize += PutWord(lplpBuf, wOrd, pdwSize);
    } else {
        uiSize += PutString(lplpBuf, lpszText, pdwSize);
    }
    return uiSize;
}


static
UINT
PutNameOrOrd( BYTE far * far* lplpBuf,  WORD wOrd, LPSTR lpszText, LONG* pdwSize )
{
    UINT uiSize = 0; 

    if (wOrd) {
        uiSize += PutByte(lplpBuf, 0xFF, pdwSize);
        uiSize += PutWord(lplpBuf, wOrd, pdwSize);
    } else {
        uiSize += PutString(lplpBuf, lpszText, pdwSize);
    }
    return uiSize;
}


static
UINT
GetClassName( BYTE far * far* lplpBuf,  BYTE* bClass, LPSTR lpszText, LONG* pdwSize )
{   
    UINT uiSize = 0; 

    *bClass = 0;
    // read the first BYTE to see if it is a string or an ordinal
    uiSize += GetByte( lplpBuf, bClass, pdwSize );  

    if( !(*bClass)) {
        // This is an Ordinal
        *lpszText = '\0';          
    } else {
        *lpszText++ = *bClass; 
        if (*bClass)
            uiSize += GetString( lplpBuf, lpszText, pdwSize);
        *bClass = 0;
    }
    return uiSize;
}

static
UINT
GetControlClassName( BYTE far * far* lplpBuf,  BYTE* bClass, LPSTR lpszText, LONG* pdwSize )
{   
    UINT uiSize = 0; 

    *bClass = 0;
    // read the first BYTE to see if it is a string or an ordinal
    uiSize += GetByte( lplpBuf, bClass, pdwSize );  

    if( (*bClass) & 0x80) {
        // This is an Ordinal
        *lpszText = '\0';          
    } else {
        *lpszText++ = *bClass; 
        if (*bClass)
            uiSize += GetString( lplpBuf, lpszText, pdwSize);
        *bClass = 0;
    }
    return uiSize;
}

static
UINT
PutClassName( BYTE far * far* lplpBuf,  BYTE bClass, LPSTR lpszText, LONG* pdwSize )
{   
    UINT uiSize = 0; 

    if( !(lpszText[0])) {
        // This is an Ordinal
        uiSize += PutByte(lplpBuf, bClass, pdwSize);
    } else {
        uiSize += PutString(lplpBuf, lpszText, pdwSize);
    }
    return uiSize;
}

static
UINT
PutControlClassName( BYTE far * far* lplpBuf,  BYTE bClass, LPSTR lpszText, LONG* pdwSize )
{   
    UINT uiSize = 0; 

    if( bClass & 0x80) {
        // This is an Ordinal
        uiSize += PutByte(lplpBuf, bClass, pdwSize);
    } else {
        uiSize += PutString(lplpBuf, lpszText, pdwSize);
    }
    return uiSize;
}


static
UINT
PutString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize )
{
    int iSize = strlen(lpszText)+1;
    if (*pdwSize>=iSize && (*pdwSize != -1)){
        memcpy(*lplpBuf, lpszText, iSize);
        *lplpBuf += iSize;
        *pdwSize -= iSize;
    } else *pdwSize = -1;
    return iSize;
}

static
UINT
PutPascalString( BYTE far * far* lplpBuf, LPSTR lpszText, BYTE bLen, LONG* pdwSize )
{             
    BYTE bSize = PutByte( lplpBuf, bLen, pdwSize );
    if (*pdwSize>=bLen && (*pdwSize != -1)){
        memcpy(*lplpBuf, lpszText, bLen);
        *lplpBuf += bLen;
        *pdwSize -= bLen;
    } else *pdwSize = -1;
    return bSize+bLen;
}


static
UINT
GetString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize )
{                               
    int iSize = strlen((char*)*lplpBuf)+1;
    if (*pdwSize>=iSize){
        memcpy( lpszText, *lplpBuf, iSize);
        *lplpBuf += iSize;    
        *pdwSize -= iSize;
    } else *lplpBuf = '\0';
    return iSize;
}

static
int
GetVSString( BYTE far * far* lplpBuf, LPSTR lpszText, LONG* pdwSize, int cMaxLen )
{                               
    // We have to stop at Maxlen to avoid read too much.
    // This is to fix a bug where some string that are supposed to be NULL
    // terminated are not.
    int iSize = strlen((char*)*lplpBuf)+1;
    if (iSize>cMaxLen)
        iSize = cMaxLen;
    if (*pdwSize>=iSize){
        memcpy( lpszText, *lplpBuf, iSize);
        *lplpBuf += iSize;    
        *pdwSize -= iSize;
    } else *lplpBuf = '\0';
    *(lpszText+iSize) = '\0';
    return iSize;
}

static
UINT
CopyText( BYTE far * far * lplpTgt, BYTE far * far * lplpSrc, LONG* pdwTgtSize, LONG* pdwSrcSize)
{
    if(!*lplpSrc) return 1;
    int uiStrlen = strlen((char*)*lplpSrc)+1;
    TRACE("Len: %d\tTgtSize: %ld\tImageSize: %ld", uiStrlen, *pdwTgtSize, *pdwSrcSize);
    if (uiStrlen>*pdwTgtSize) {
        TRACE("\n");
        *pdwTgtSize = -1;
        return uiStrlen;       
    }
    else {
        strcpy( (char*)*lplpTgt, (char*)*lplpSrc);
        TRACE1("\tCaption: %Fs\n", (char*)*lplpTgt);
        if(*pdwSrcSize>=uiStrlen) {
            *lplpSrc += uiStrlen;
            *pdwSrcSize -= uiStrlen;
        }
        *lplpTgt += uiStrlen;
        *pdwTgtSize -= uiStrlen;
        return uiStrlen;
    }              
}

static LPRESITEM
GetItem( BYTE far * lpBuf, LONG dwNewSize, LPSTR lpStr )
{
    LPRESITEM lpResItem = (LPRESITEM) lpBuf;

    while(strcmp(lpResItem->lpszClassName, lpStr)) {
        lpBuf += lpResItem->dwSize;        
        dwNewSize -= lpResItem->dwSize;    
        if (dwNewSize<=0)
            return LPNULL;                 
        lpResItem = (LPRESITEM) lpBuf;
    }       
    return lpResItem;
}

static DWORD CalcID( WORD wId, BOOL bFlag )
{
    // We want to calculate the ID Relative to the WORD wId
    // If we have any other ID with the same value then we return
    // the incremental number + the value.
    // If no other Item have been found then the incremental number will be 0.
    // If bFlag = TRUE then the id get added to the present list.
    // If bFlag = FALSE then the list is reseted and the function return

    // Clean the array if needed
    if(!bFlag) {
        wIDArray.RemoveAll();
        return 0;
    }

    // Add the value to the array
    wIDArray.Add(wId);

    // Walk the array to get the number of duplicated ID
    short c = -1; // will be 0 based
    for(short i=wIDArray.GetUpperBound(); i>=0 ; i-- ) {
        if (wIDArray.GetAt(i)==wId)
            c++;
    }  
    TRACE3("CalcID: ID: %hd\tPos: %hd\tFinal: %lx\n", wId, c, MAKELONG( wId, c ));
    return MAKELONG( wId, c );
}

static LONG Allign( BYTE** lplpBuf, LONG* plBufSize, LONG lSize )
{
   LONG lRet = 0;
   BYTE bPad = (BYTE)Pad4(lSize);
   lRet = bPad;
   if (bPad && *plBufSize>=bPad) {
      while(bPad && *plBufSize)  {
         **lplpBuf = 0x00;
         *lplpBuf += 1;
         *plBufSize -= 1;
         bPad--;
      }
   }
   return lRet;
}

static void ChangeLanguage( LPVOID lpBuffer, UINT uiBuffSize )
{
    BYTE * pBuf = (BYTE*)lpBuffer;
    LONG lSize = 0;

    while(uiBuffSize)
    {
        // Skip 
        lSize += SkipByte( &pBuf, 2, (LONG*)&uiBuffSize );
        lSize += SkipByte( &pBuf, strlen((LPCSTR)pBuf)+1, (LONG*)&uiBuffSize );
        lSize += SkipByte( &pBuf, Pad4(lSize), (LONG*)&uiBuffSize );
        
        lSize += SkipByte( &pBuf, 2, (LONG*)&uiBuffSize );
        lSize += SkipByte( &pBuf, strlen((LPCSTR)pBuf)+1, (LONG*)&uiBuffSize );
        lSize += SkipByte( &pBuf, Pad4(lSize), (LONG*)&uiBuffSize );
        
        lSize += PutDWord( &pBuf, gLang, (LONG*)&uiBuffSize );
    
        lSize += SkipByte( &pBuf, 4, (LONG*)&uiBuffSize );
    
        lSize += SkipByte( &pBuf, 4, (LONG*)&uiBuffSize );
    }


}

////////////////////////////////////////////////////////////////////////////
// DLL Specific code implementation

////////////////////////////////////////////////////////////////////////////
// This function should be used verbatim.  Any initialization or termination
// requirements should be handled in InitPackage() and ExitPackage().
//
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		// NOTE: global/static constructors have already been called!
		// Extension DLL one-time initialization - do not allocate memory 
		// here, use the TRACE or ASSERT macros or call MessageBox
		AfxInitExtensionModule(extensionDLL, hInstance);
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		// Terminate the library before destructors are called
		AfxWinTerm();
	}

	if (dwReason == DLL_PROCESS_DETACH || dwReason == DLL_THREAD_DETACH) 
		return 0;		// CRT term	Failed

	return 1;   // ok
}

/////////////////////////////////////////////////////////////////////////////