//+---------------------------------------------------------------------------
//
//  File:	res32.cpp
//
//  Contents:	Implementation for the Resource 32 Read/Write module
//
//  Classes:    one
//
//  History:	31-May-93   alessanm    created
//----------------------------------------------------------------------------

#include <afxwin.h>

#include "..\common\rwdll.h"
#include "..\common\rw32hlpr.h"

#include <limits.h>

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

static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };

/////////////////////////////////////////////////////////////////////////////
// General Declarations
#define RWTAG "RES32"

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

static UINT GetResInfo(
				 CFile*,
				 WORD* wTypeId, LPSTR lplpszTypeId, BYTE bMaxTypeLen,
				 WORD* wNameId, LPSTR lplpszNameId, BYTE bMaxNameLen,
				 DWORD* pdwDataVersion,
				 WORD* pwFlags, WORD* pwLang,
				 DWORD* pdwVersion, DWORD* pdwCharact,
				 DWORD* dwSize, DWORD* dwFileOffset, DWORD );

static UINT WriteHeader(
				 CFile* pFile,
				 DWORD dwSize,
				 WORD wTypeId, LPSTR lpszwTypeId,
				 WORD wNameId, LPSTR lpszwNameId,
				 DWORD dwDataVersion,
				 WORD wFlags, WORD wLang,
				 DWORD dwVersion, DWORD dwCharact );

static UINT WriteImage(
				 CFile*,
				 LPVOID lpImage, DWORD dwSize );

static UINT GetUpdatedRes(
				 LPVOID far * lplpBuffer,
				 LONG* lSize,
				 WORD* wTypeId, LPSTR lplpszTypeId,
				 WORD* wNameId, LPSTR lplpszNameId,
				 DWORD* dwlang, DWORD* dwSize );

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

static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen );


/////////////////////////////////////////////////////////////////////////////
// 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;

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

	WORD wTypeId;
	static char szTypeId[128];

	WORD wNameId;
	static char szNameId[128];
	WORD wDummy;
	DWORD dwDummy;
	WORD wLang;
	DWORD dwSize;
	DWORD dwFileOffset;

	DWORD filelen = file.GetLength();

	// File begins with a null resource entry. Check for signature.
	{  DWORD datasize, headsize;

	   // Filelen to at least 32 bytes, the size of a resource entry with
	   // datasize = 0...  Note: A file consisting of just a null header is accepted.
	   if (filelen < 32) {
	       file.Close();
	       return FALSE;
	       }

	   // datasize to be 0 (although >0 everywhere else)
	   file.Read(&datasize, 4);
	   if (datasize != 0) {
	       file.Close();
	       return FALSE;
	       }

	   // headsize to be 32 (although >=32 everywhere else)
	   file.Read(&headsize, 4);
	   if (headsize != 32) {
	       file.Close();
	       return FALSE;
	       }

	   // Other tests possible here

	   // Skip to end of first (null) resource entry
	   file.Seek(headsize, CFile::begin);
	   }

	// See that rest of file contains recognizable resource entries
	while(filelen - file.GetPosition()>0) {
		if (!GetResInfo( &file,
					  &wTypeId, &szTypeId[0], 128,
					  &wNameId, &szNameId[0], 128,
					  &dwDummy,
					  &wDummy, &wLang,
					  &dwDummy, &dwDummy,
					  &dwSize, &dwFileOffset, filelen) ) {
			// This is not a valid resource file
			file.Close();
			return FALSE;
		}
	}

	file.Close();
	return TRUE;
}


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

	)
{
	UINT uiError = ERROR_NO_ERROR;
	BYTE far * lpBuf = (BYTE far *)lpBuffer;
	LONG lBufSize = (LONG)*puiSize;
	// we can consider the use of a CMemFile so we get the same speed as memory access.
	CFile file;

	if (!RWValidateFileType(lpszFilename))
		return ERROR_RW_INVALID_FILE;
	
    // Make sure we are using the right code page and global settings
    // Get the pointer to the function
	HINSTANCE hDllInst = LoadLibrary("iodll.dll");
    if (hDllInst)
    {
        UINT (FAR PASCAL * lpfnGetSettings)(LPSETTINGS);
        // Get the pointer to the function to get the settings
        lpfnGetSettings = (UINT (FAR PASCAL *)(LPSETTINGS))
                            GetProcAddress( hDllInst, "RSGetGlobals" );
        if (lpfnGetSettings!=NULL) {
            SETTINGS settings;
	        (*lpfnGetSettings)(&settings);

    	    g_cp      = settings.cp;
            g_bAppend = settings.bAppend;
            strcpy( g_char, settings.szDefChar );
		}

        FreeLibrary(hDllInst);
    }

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

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

	WORD wTypeId;
	static char szTypeId[128];

	WORD wNameId;
	static char szNameId[128];
	WORD wDummy;
	DWORD dwDummy;
	WORD wLang;
	DWORD dwSize;
	DWORD dwFileOffset;

	UINT uiOverAllSize = 0;

	// The first resource should be: Null. Skipp it
	file.Seek( 32, CFile::begin);
	DWORD filelen =	file.GetLength();
	while(filelen-file.GetPosition()>0) {
		GetResInfo( &file,
					  &wTypeId, &szTypeId[0], 128,
					  &wNameId, &szNameId[0], 128,
					  &dwDummy,
					  &wDummy, &wLang,
					  &dwDummy, &dwDummy,
					  &dwSize, &dwFileOffset, filelen);

		uiOverAllSize += PutWord( &lpBuf, wTypeId, &lBufSize );
		uiOverAllSize += PutStringA( &lpBuf, szTypeId, &lBufSize );
		// Check if it is alligned
 		uiOverAllSize += Allign( &lpBuf, &lBufSize , (LONG)uiOverAllSize);

		uiOverAllSize += PutWord( &lpBuf, wNameId, &lBufSize  );
		uiOverAllSize += PutStringA( &lpBuf, szNameId, &lBufSize );
		// Check if it is alligned
 		uiOverAllSize += Allign( &lpBuf, &lBufSize, (LONG)uiOverAllSize);

		uiOverAllSize += PutDWord( &lpBuf, (DWORD)wLang, &lBufSize );

		uiOverAllSize += PutDWord( &lpBuf, dwSize, &lBufSize  );

		uiOverAllSize += PutDWord( &lpBuf, dwFileOffset, &lBufSize );
	}

	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::modeRead | CFile::typeBinary | CFile::shareDenyNone))
		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 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;
		case 11:
			uiError = ParseMsgTbl( lpImageBuf, dwImageSize,  lpBuffer, dwSize );
		break;
        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;

	// 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);
	}

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

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

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

		FreeLibrary(hDllInst);
		return uiError;
	}

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

	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) {
		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

	WORD wTypeId;
	char szTypeId[128];

	WORD wNameId;
	char szNameId[128];

	WORD wFlags;
	WORD wLang;
	DWORD dwDataVersion;
	DWORD dwVersion;
	DWORD dwCharact;

	DWORD dwSize;
	DWORD dwFileOffset;

	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;
	DWORD filelen = fileIn.GetLength();
	DWORD dwHeadSize = 0l;
	static BYTE buf[32];
	DWORD pad = 0l;

	// The first resource should be: Null. Skipp it
	fileIn.Read( &buf, 32 );
	fileOut.Write( &buf, 32 );

	while(filelen-fileIn.GetPosition()>0) {
		GetResInfo( &fileIn,
					&wTypeId, &szTypeId[0], 128,
					&wNameId, &szNameId[0], 128,
					&dwDataVersion,
					&wFlags, &wLang,
					&dwVersion, &dwCharact,
					&dwSize, &dwFileOffset, filelen
					);

		if ((!wUpdTypeId) && (uiBufSize))
			GetUpdatedRes( &lpBuffer,
					(LONG*)&uiBufSize,
					&wUpdTypeId, &szUpdTypeId[0],
					&wUpdNameId, &szUpdNameId[0],
					&dwUpdLang,
					&dwUpdSize
					);
		if ( (wUpdTypeId==wTypeId) &&
			 ( (CString)szUpdTypeId==(CString)szTypeId) &&
			 (wUpdNameId==wNameId) &&
			 ( (CString)szUpdNameId==(CString)szNameId)
			 ) {
			// The resource has been updated get the image from the IODLL
			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;
				}
			}

			wUpdTypeId = 0;

		} else {

			// The fileIn is now correctly positioned at next resource. Save posit.
			DWORD dwNextResFilePos = fileIn.GetPosition();

			// The resource hasn't been updated copy the image from the file
			if(!dwSize) {
				FreeLibrary(hDllInst);
				return ERROR_NEW_FAILED;
			}
			lpImageBuf = new BYTE[dwSize];
			if(!lpImageBuf) {
				FreeLibrary(hDllInst);
				return ERROR_NEW_FAILED;
			}
			if ( dwFileOffset!=(DWORD)fileIn.Seek( dwFileOffset, CFile::begin) ) {
				delete []lpImageBuf;
				FreeLibrary(hDllInst);
				return (DWORD)ERROR_FILE_INVALID_OFFSET;
			}
			if (dwSize>UINT_MAX) {
				// we have to read the image in different steps
				delete []lpImageBuf;
				FreeLibrary(hDllInst);
				return (DWORD)ERROR_RW_IMAGE_TOO_BIG;
			} else fileIn.Read( lpImageBuf, (UINT)dwSize);
			dwImageBufSize = dwSize;

			// This moves us past any pad bytes, to start of next resource.
			fileIn.Seek(dwNextResFilePos, CFile::begin);
		}

		dwHeadSize = WriteHeader(&fileOut,
					dwImageBufSize,
					wTypeId, &szTypeId[0],
					wNameId, &szNameId[0],
					dwDataVersion,
					wFlags, wLang,
					dwVersion, dwCharact );

		WriteImage( &fileOut,
					lpImageBuf, dwImageBufSize);

		BYTE bPad = (BYTE)Pad4((DWORD)dwHeadSize+dwImageBufSize);
		if(bPad)
			fileOut.Write( &pad, bPad );

		if (lpImageBuf) delete []lpImageBuf;
	}

	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 );
        break;

        case 11:
            if (lpOldImage)
                uiError = UpdateMsgTbl( lpNewBuf, dwNewSize,
                                  lpOldImage, dwOldImageSize,
                                  lpNewImage, pdwNewImageSize );
        break;

        case 16:
            if (lpOldImage)
                uiError = UpdateVerst( lpNewBuf, dwNewSize,
                                   lpOldImage, dwOldImageSize,
                                   lpNewImage, pdwNewImageSize );
        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::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;

	// First write the NULL resource to make it different from res16
	static BYTE bNullHeader[32] = {0,0,0,0,0x20,0,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

	fileOut.Write(bNullHeader, 32);

	while(uiBufSize>0) {
		if ((!wUpdTypeId) && (uiBufSize))
			GetUpdatedRes( &lpBuffer, 
					(LONG*)&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,
						dwImageBufSize,
						wUpdTypeId, &szUpdTypeId[0], 
						wUpdNameId, &szUpdNameId[0],
						0l, 0, 0, 0l, 0l );
			
			WriteImage( &fileOut,
						lpImageBuf, dwImageBufSize);    
						
			if (lpImageBuf) delete []lpImageBuf;
			wUpdTypeId = 0;
			
		} else wUpdTypeId = 0;
		
	}
	
	fileOut.Close();
	
	return uiError;
}
        
static UINT GetUpdatedRes( 
				 LPVOID far * lplpBuffer,
				 LONG* lSize,
				 WORD* wTypeId, LPSTR lpszTypeId,
				 WORD* wNameId, LPSTR lpszNameId,
				 DWORD* dwLang, DWORD* dwSize )
{                            
    BYTE** lplpBuf = (BYTE**)lplpBuffer;

    UINT uiSize = GetWord( lplpBuf, wTypeId, lSize );
    uiSize += GetStringA( lplpBuf, lpszTypeId, lSize );
    uiSize += Allign( lplpBuf, lSize, (LONG)uiSize);

    uiSize += GetWord( lplpBuf, wNameId, lSize );
    uiSize += GetStringA( lplpBuf, lpszNameId, lSize );
    uiSize += Allign( lplpBuf, lSize, (LONG)uiSize);

    uiSize += GetDWord( lplpBuf, dwLang, lSize );
    uiSize += GetDWord( lplpBuf, dwSize, lSize );

    return uiSize;
}	

static UINT
GetResInfo( CFile* pfile,
			WORD* pwTypeId, LPSTR lpszTypeId, BYTE bMaxTypeLen,
			WORD* pwNameId, LPSTR lpszNameId, BYTE bMaxNameLen,
			DWORD* pdwDataVersion,
			WORD* pwFlags, WORD* pwLang, 
			DWORD* pdwVersion, DWORD* pdwCharact,
		 	DWORD* pdwSize, DWORD* pdwFileOffset,
		 	DWORD dwFileSize )
{                       
	static UINT uiSize;
	static LONG lOfsCheck;
	static DWORD dwSkip;
	static DWORD dwHeadSize;
	//Get the data size
	pfile->Read( pdwSize, 4 );
	if (*pdwSize==0)
		// size id 0 the resource file is corrupted or is not a res file
		return FALSE;
	
	//Get the Header size
	pfile->Read( &dwHeadSize, 4 );
	if (dwHeadSize<32)
		// should never be smaller than 32
		return FALSE;
	                   
	// get the Type info
	uiSize = GetNameOrOrdFile( pfile, pwTypeId, lpszTypeId, bMaxTypeLen);
	if (!uiSize) 
		return FALSE;
		
	// get the Name info
	uiSize = GetNameOrOrdFile( pfile, pwNameId, lpszNameId, bMaxNameLen);
    if (!uiSize) 
		return FALSE;
	
	// Skip the Data Version
	pfile->Read( pdwDataVersion, 4 );
	
	// Get the Flags
	pfile->Read( pwFlags, 2 );
	
	// Get the language ID    
	pfile->Read( pwLang, 2 );
		
	// Skip the version and the characteristics
	pfile->Read( pdwVersion, 4 );	
	pfile->Read( pdwCharact, 4 );
	
	*pdwFileOffset = pfile->GetPosition();
	
	// calculate if padding nedeed
	BYTE bPad = (BYTE)Pad4((DWORD)((*pdwSize)+dwHeadSize));
	if(bPad)
		pfile->Seek( bPad, CFile::current ); 
	
	if (*pdwFileOffset>dwFileSize)
		return FALSE;
	// check if the size is valid
	TRY {
		lOfsCheck = pfile->Seek(*pdwSize, CFile::current);
	} CATCH(CFileException, e) {
		// Check is the right exception
		return FALSE;
	} END_CATCH
	if (lOfsCheck!=(LONG)(*pdwFileOffset+*pdwSize+bPad)) 
			return FALSE;
			
	return TRUE;
}

static UINT WriteHeader( 
				 CFile* pFile,
				 DWORD dwSize,
				 WORD wTypeId, LPSTR lpszTypeId,
				 WORD wNameId, LPSTR lpszNameId,
				 DWORD dwDataVersion,
				 WORD wFlags, WORD wLang,
				 DWORD dwVersion, DWORD dwCharact )
{
	UINT uiError = ERROR_NO_ERROR;
	static WCHAR szwName[128];
	static WORD wFF = 0xFFFF;
	DWORD dwHeadSize = 0l;
	static DWORD Pad = 0L;
	
	
	DWORD dwOffset = pFile->GetPosition();
	pFile->Write( &dwSize, 4 );
	// we will have to fix up laxter the size of the resource
	pFile->Write( &dwHeadSize, 4 );
	
	if(wTypeId) {
		// It is an ordinal   
		pFile->Write( &wFF, 2 );
		pFile->Write( &wTypeId, 2 );
		dwHeadSize += 4;
	} else {          
		WORD wLen = (_MBSTOWCS( szwName, lpszTypeId, strlen(lpszTypeId)+1))*sizeof(WORD);
		pFile->Write( szwName, wLen );
		BYTE bPad = (BYTE)Pad4(wLen);
		if(bPad)
			pFile->Write( &Pad, bPad ); 	
		dwHeadSize += wLen+bPad;
	}                                                 
	
	if(wNameId) {
		// It is an ordinal   
		pFile->Write( &wFF, 2 );
		pFile->Write( &wNameId, 2 );
		dwHeadSize += 4;
	} else {                                        
		WORD wLen = (_MBSTOWCS( szwName, lpszNameId, strlen(lpszNameId)+1))*sizeof(WORD);
		pFile->Write( szwName, wLen );
		BYTE bPad = (BYTE)Pad4(wLen);
		if(bPad)
			pFile->Write( &Pad, bPad ); 	
		dwHeadSize += wLen+bPad;
	}                                            
	
	pFile->Write( &dwDataVersion, 4 );
	pFile->Write( &wFlags, 2 );
	pFile->Write( &wLang, 2 );
	pFile->Write( &dwVersion, 4 );
	pFile->Write( &dwCharact, 4 );
	
	dwHeadSize += 24;
	
	// write the size of the resource
	pFile->Seek( dwOffset+4, CFile::begin );
	pFile->Write( &dwHeadSize, 4 );
	pFile->Seek( dwOffset+dwHeadSize, CFile::begin );	
	return (UINT)dwHeadSize;
}				 

static DWORD dwZeroPad = 0x00000000;				 
static UINT WriteImage( 
				 CFile* pFile,
				 LPVOID lpImage, DWORD dwSize )
{                  
	UINT uiError = ERROR_NO_ERROR;
	if(lpImage) 
    {
		pFile->Write( lpImage, (UINT)dwSize );

        // check if we need to have the image alligned
        if(Pad4(dwSize))   
            pFile->Write( &dwZeroPad, Pad4(dwSize) );
    }
	
	return uiError;
}

static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen )
{
	UINT uiSize = 0; 
	
	*pwId = 0;
	
	// read the first WORD to see if it is a string or an ordinal
	pfile->Read( pwId, sizeof(WORD) );	
	if(*pwId==0xFFFF) {
		// This is an Ordinal
		pfile->Read( pwId, sizeof(WORD) );	
		*lpszId = '\0';          
		uiSize = 2;
	} else {
        uiSize++;
	    _WCSTOMBS( lpszId, pwId, 3);
	    while((*lpszId++) && (bMaxStrLen-2)) {
	    	pfile->Read( pwId, sizeof(WORD) );	
	    	_WCSTOMBS( lpszId, pwId, 3);
	        uiSize++;
	    	bMaxStrLen--;
	    }
	    if ( (!(bMaxStrLen-2)) && (*pwId) ) {
	    	// Failed
	    	return 0;
	    }
	    // Check padding
		BYTE bPad = Pad4(uiSize*sizeof(WORD));
		if(bPad)
			pfile->Read( pwId, sizeof(WORD) );	
	}
	
	return uiSize;
}   	

////////////////////////////////////////////////////////////////////////////////
// Helper
////////////////////////////////////////////////////////////////////////////////
static char szCaption[MAXSTR];

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 += PutStringW( &lpNewImage, &szUpdTxt[0], &dwNewImageSize);
		
	}                             
	
	if (dwOverAllSize>(LONG)*pdwNewImageSize) {
		// calc the padding as well
		dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
		*pdwNewImageSize = dwOverAllSize;
		return uiError;
	}
		
	*pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
	
	if(*pdwNewImageSize>0) {
		// calculate padding
		BYTE bPad = (BYTE)Pad16((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
	WORD wLen;
	WORD wPos = 0;
	
	LONG dwOverAllSize = 0l;
	
	while(dwNewSize>0) {
		if ( dwNewSize ) {
			lpResItem = (LPRESITEM) lpBuf;
				 			
			strcpy( szCaption, lpResItem->lpszCaption );
			lpBuf += lpResItem->dwSize;
			dwNewSize -= lpResItem->dwSize;
		}
		
		wLen = strlen(szCaption);

        // Write the text
        dwOverAllSize += PutPascalStringW( &lpNewImage, &szCaption[0], wLen, &dwNewImageSize );
	}                             
	
	if (dwOverAllSize>(LONG)*pdwNewImageSize) {
		// calc the padding as well
		dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
		*pdwNewImageSize = dwOverAllSize;
		return uiError;
	}
	
	*pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
	
	if(*pdwNewImageSize>0) {
		// calculate padding
		BYTE bPad = (BYTE)Pad16((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;
	DWORD 	dwExtStyle = 0L;
	WORD    wNumOfElem = 0;
	WORD	wX = 0;
	WORD	wY = 0;
	WORD	wcX = 0;
	WORD	wcY = 0;
	WORD	wId = 0;
	char	szClassName[128];
	WORD	wClassName;
	//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;                
		dwExtStyle = lpResItem->dwExtStyle;                
		wClassName = lpResItem->wClassName;
		strcpy( szCaption, lpResItem->lpszCaption );
		strcpy( szClassName, lpResItem->lpszClassName );
		strcpy( szFaceName, lpResItem->lpszFaceName );
		if (*szFaceName != '\0')
		{
			dwStyle |= DS_SETFONT;
		}
		lpBuf += lpResItem->dwSize;        
		dwNewSize -= lpResItem->dwSize;
	}
	
	DWORD dwPadCalc = dwOverAllSize;
	// Header info
	dwOverAllSize = PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
	dwOverAllSize += PutDWord( &lpNewImage, dwExtStyle, &dwNewImageSize );
	
    // Store the position of the numofelem for a later fixup
	BYTE far * lpNumOfElem = lpNewImage;
    LONG lSizeOfNum = sizeof(WORD);
	dwOverAllSize += PutWord( &lpNewImage, wNumOfElem, &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, wClassName, &szClassName[0], &dwNewImageSize );
    dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
    	wClassName, dwStyle );
    if( dwStyle & DS_SETFONT ) { 
    	dwOverAllSize += PutWord( &lpNewImage, wPointSize, &dwNewImageSize );
        dwOverAllSize += PutStringW( &lpNewImage, &szFaceName[0], &dwNewImageSize );
    }
    
    // Check if padding is needed
    BYTE bPad = (BYTE)Pad4((WORD)(dwOverAllSize-dwPadCalc));
    if (bPad) {
        if( (bPad)<=dwNewImageSize )
            memset( lpNewImage, 0x00, bPad );
        dwNewImageSize -= (bPad);
        dwOverAllSize += (bPad);
        lpNewImage += (bPad);
    }

	while( dwNewSize>0 ) {
		wNumOfElem++;
	    
	    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;
			dwExtStyle = lpResItem->dwExtStyle;                
			wClassName = LOBYTE(lpResItem->wClassName);
			strcpy( szCaption, lpResItem->lpszCaption );
			strcpy( szClassName, lpResItem->lpszClassName );
			lpBuf += lpResItem->dwSize;
			dwNewSize -= lpResItem->dwSize;
		}		 	
				
        dwPadCalc = dwOverAllSize;
        //write the control 
       	dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
       	dwOverAllSize += PutDWord( &lpNewImage, dwExtStyle, &dwNewImageSize );

        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 += PutClassName( &lpNewImage, wClassName, &szClassName[0], &dwNewImageSize );
        dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
        	wClassName, dwStyle );
        dwOverAllSize += PutWord( &lpNewImage, 0, &dwNewImageSize );
        
        // Check if padding is needed
        bPad = (BYTE)Pad4((WORD)(dwOverAllSize-dwPadCalc));
        if (bPad) {
            if( (bPad)<=dwNewImageSize )
                memset( lpNewImage, 0x00, bPad );
            dwNewImageSize -= (bPad);
            dwOverAllSize += (bPad);
            lpNewImage += (bPad);
        }

	}                             
	
	if (dwOverAllSize>(LONG)*pdwNewImageSize) {
		// calc the padding as well
		dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
		*pdwNewImageSize = dwOverAllSize;
		return uiError;
	}
		
	*pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
	
	if(*pdwNewImageSize>0) {
		// calculate padding
		BYTE bPad = (BYTE)Pad16((DWORD)(*pdwNewImageSize));
		if (bPad>dwNewImageSize) {
			*pdwNewImageSize += bPad;
			return uiError;
		}
		memset(lpNewImage, 0x00, bPad);
		*pdwNewImageSize += bPad;
	}
	
	// fixup the number of items
	PutWord( &lpNumOfElem, wNumOfElem, &lSizeOfNum );
	
	return uiError;
}						

////////////////////////////////////////////////////////////////////////////
// DLL Specific helpers
////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////
// DLL Specific code implementation
////////////////////////////////////////////////////////////////////////////
// Library init

////////////////////////////////////////////////////////////////////////////
// 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
}

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