|
|
//+---------------------------------------------------------------------------
//
// File: mac.cpp
//
// Contents: Implementation for the Macintosh Read/Write module
//
// History: 23-Aug-94 alessanm created
//
//----------------------------------------------------------------------------
#include <afxwin.h>
#include <limits.h>
#include <malloc.h>
#include "..\common\rwdll.h"
#include "..\common\m68k.h"
#include "..\common\helper.h"
#include "mac.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 RWTAG "MAC"
static ULONG gType; static ULONG gLng; static ULONG gResId; static WCHAR gwszResId[256];
HINSTANCE g_IODLLInst = 0; DWORD (PASCAL * g_lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD); DWORD (PASCAL * g_lpfnUpdateResImage)(HANDLE, LPSTR, LPSTR, DWORD, DWORD, LPVOID, DWORD); HANDLE (PASCAL * g_lpfnHandleFromName)(LPCSTR);
/////////////////////////////////////////////////////////////////////////////
// Public C interface implementation
//[registration]
extern "C" BOOL FAR PASCAL RWGetTypeString(LPSTR lpszTypeName) { strcpy( lpszTypeName, RWTAG ); return FALSE; }
//=============================================================================
//
// To validate a mac res binary file we will walk the resource header and see
// if it matches with what we have.
//
//=============================================================================
extern "C" BOOL FAR PASCAL RWValidateFileType (LPCSTR lpszFilename) { BOOL bRet = FALSE; TRACE("MAC.DLL: RWValidateFileType()\n");
CFile file;
// we Open the file to see if it is a file we can handle
if (!file.Open( lpszFilename, CFile::typeBinary | CFile::modeRead | CFile::shareDenyNone )) return bRet;
// Check if this is a MAC Resource file ...
if(IsMacResFile( &file )) bRet = TRUE;
file.Close(); return bRet; }
//=============================================================================
//
// We will walk the resource header, walk the resource map and then normalize
// the Mac it to Windows id and pass this info to the RW.
//
//=============================================================================
extern "C" DllExport UINT APIENTRY RWReadTypeInfo( LPCSTR lpszFilename, LPVOID lpBuffer, UINT* puiSize
) { TRACE("MAC.DLL: RWReadTypeInfo()\n"); UINT uiError = ERROR_NO_ERROR; BYTE far * lpBuf = (BYTE far *)lpBuffer; UINT uiBufSize = *puiSize; CFile file; int iFileNameLen = strlen(lpszFilename)+1;
if (!file.Open(lpszFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) return ERROR_FILE_OPEN;
UINT uiBufStartSize = uiBufSize;
////////////////////////////////////
// Check if it is a valid mac file
// Is a Mac Resource file ...
if(IsMacResFile( &file )) { // load the file in memory
// NOTE: WIN16 This might be to expensive in memory allocation
// on a 16 bit platform
BYTE * pResources = (BYTE*)malloc(file.GetLength()); if(!pResources) { file.Close(); return ERROR_NEW_FAILED; } file.Seek(0, CFile::begin); file.ReadHuge(pResources, file.GetLength());
IMAGE_SECTION_HEADER Sect; memset(&Sect, 0, sizeof(IMAGE_SECTION_HEADER)); ParseResourceFile(pResources, &Sect, (BYTE**)&lpBuffer, (LONG*)puiSize, iFileNameLen); free(pResources);
*puiSize = uiBufSize - *puiSize; file.Close(); return uiError; }
file.Close(); return uiError; }
/////////////////////////////////////////////////////////////////////////////
// We will prepend to the image the file name. This will be usefull later on
// to retrive the dialog item list
/////////////////////////////////////////////////////////////////////////////
extern "C" DllExport DWORD APIENTRY RWGetImage( LPCSTR lpszFilename, DWORD dwImageOffset, LPVOID lpBuffer, DWORD dwSize ) { UINT uiError = ERROR_NO_ERROR; BYTE far * lpBuf = (BYTE far *)lpBuffer; int iNameLen = strlen(lpszFilename)+1; DWORD dwBufSize = dwSize - iNameLen; // 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;
// copy the file name at the beginning of the buffer
memcpy((BYTE*)lpBuf, lpszFilename, iNameLen); lpBuf = ((BYTE*)lpBuf+iNameLen);
if (dwBufSize>UINT_MAX) { // we have to read the image in different steps
return (DWORD)0L; } else uiError = file.Read( lpBuf, (UINT)dwBufSize)+iNameLen; file.Close();
return (DWORD)uiError; }
extern "C" DllExport UINT APIENTRY RWParseImage( LPCSTR lpszType, LPVOID lpImageBuf, DWORD dwImageSize, LPVOID lpBuffer, DWORD dwSize ) { UINT uiError = ERROR_NO_ERROR; BYTE * lpBuf = (BYTE *)lpBuffer; DWORD dwBufSize = dwSize;
// Remove the filename...
if( !strcmp(lpszType, "MENU") || !strcmp(lpszType, "STR ") || !strcmp(lpszType, "STR#") || !strcmp(lpszType, "TEXT") ) { int iFileNameLen = strlen((LPSTR)lpImageBuf)+1; lpImageBuf = ((BYTE*)lpImageBuf+iFileNameLen); dwImageSize -= iFileNameLen; }
//===============================================================
// Menus
if( !strcmp(lpszType, "MENU") ) return ParseMENU( lpImageBuf, dwImageSize, lpBuffer, dwSize );
//===============================================================
// Dialogs
if( !strcmp(lpszType, "WDLG") ) return ParseWDLG( lpImageBuf, dwImageSize, lpBuffer, dwSize );
if( !strcmp(lpszType, "DLOG") ) return ParseDLOG( lpImageBuf, dwImageSize, lpBuffer, dwSize );
if( !strcmp(lpszType, "ALRT") ) return ParseALRT( lpImageBuf, dwImageSize, lpBuffer, dwSize );
//===============================================================
// Strings
if( !strcmp(lpszType, "STR ") ) return ParseSTR( lpImageBuf, dwImageSize, lpBuffer, dwSize );
if( !strcmp(lpszType, "STR#") ) return ParseSTRNUM( lpImageBuf, dwImageSize, lpBuffer, dwSize );
if( !strcmp(lpszType, "TEXT") ) return ParseTEXT( lpImageBuf, dwImageSize, lpBuffer, dwSize );
if( !strcmp(lpszType, "WIND") ) return ParseWIND( lpImageBuf, dwImageSize, lpBuffer, dwSize ); return uiError; }
extern"C" DllExport UINT APIENTRY RWWriteFile( LPCSTR lpszSrcFilename, LPCSTR lpszTgtFilename, HANDLE hResFileModule, LPVOID lpBuffer, UINT uiSize, HINSTANCE hDllInst, LPCSTR lpszSymbolPath ) { TRACE("RWMAC.DLL: Source: %s\t Target: %s\n", lpszSrcFilename, lpszTgtFilename); UINT uiError = ERROR_NO_ERROR; PUPDATEDRESLIST pUpdList = LPNULL;
// Get the handle to the IODLL
if(InitIODLLLink()) hDllInst = g_IODLLInst; else return ERROR_DLL_LOAD;
CFile fileIn; CFile fileOut;
if (!fileIn.Open(lpszSrcFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) return (DWORD)ERROR_FILE_OPEN;
if (!fileOut.Open(lpszTgtFilename, CFile::modeWrite | CFile::typeBinary)) return (DWORD)ERROR_FILE_OPEN;
MACRESHEADER fileHeader; // Read the header of the file...
fileIn.Read(&fileHeader, sizeof(MACRESHEADER));
// allocate a buffer to hold the new resource map
// The buffer will be as big as the other one since there is no
// need, for now, to support the adding of resource
LONG lMapSize = MacLongToLong(fileHeader.mulSizeOfResMap); BYTE * pNewMap = (BYTE*)malloc(lMapSize);
if(!pNewMap) { uiError = ERROR_NEW_FAILED; goto exit; } { // This is for the goto. Check error:C2362
PUPDATEDRESLIST pListItem = LPNULL; // Create the list of update resource
pUpdList = UpdatedResList( lpBuffer, uiSize );
// set the map buffer to 0 ...
memset(pNewMap, 0, lMapSize);
////////////////////////////////////////////////////////////////////////////////
// Read each resource from the resource map and check if the resource has been
// updated. If it has been updated, get the new resource image. Otherwise use
// the original resource data.
// Write the resource data in the Tgt file and write the info on the offset etc.
// in the pNewMap buffer so, when all the resources have been read and written
// the only thing left is to fix up some sizes and to write the buffer to disk.
////////////////////////////////////////////////////////////////////////////////
// Write the resource header in the Tgt file
fileOut.Write(&fileHeader, sizeof(MACRESHEADER));
BYTE * pByte = (BYTE*)malloc(256); if(!pByte) { uiError = ERROR_NEW_FAILED; goto exit; }
// Copy the Reserved and user data
fileIn.Read(pByte, 240); fileOut.Write(pByte, 240); free(pByte);
// store the position of the beginning of the res data
DWORD dwBeginOfResData = fileOut.GetPosition();
MACRESMAP resMap; // Read the resource map ...
fileIn.Seek(MacLongToLong(fileHeader.mulOffsetToResMap), CFile::begin); fileIn.Read(&resMap, sizeof(MACRESMAP));
BYTE * pTypeList = pNewMap+28; BYTE * pTypeInfo = pTypeList+2; BYTE * pRefList = LPNULL; BYTE * pNameList = LPNULL; BYTE * pName = LPNULL;
DWORD dwOffsetToTypeList = fileIn.GetPosition(); WORD wType; fileIn.Read(&wType, sizeof(WORD)); memcpy( pNewMap+sizeof(MACRESMAP), &wType, sizeof(WORD)); // number of types - 1
wType = MacWordToWord((BYTE*)&wType)+1;
MACRESTYPELIST TypeList; MACRESREFLIST RefList; WORD wOffsetToRefList = wType*sizeof(MACRESTYPELIST)+sizeof(WORD); DWORD dwOffsetToLastTypeInfo = 0; DWORD dwOffsetToLastRefList = 0; DWORD dwOffsetToNameList = MacLongToLong(fileHeader.mulOffsetToResMap)+MacWordToWord(resMap.mwOffsetToNameList); DWORD dwSizeOfData = 0;
while(wType) { // Read the type info ...
fileIn.Read(&TypeList, sizeof(MACRESTYPELIST)); dwOffsetToLastTypeInfo = fileIn.GetPosition();
// ... and update the newmap buffer
memcpy( pTypeInfo, &TypeList, sizeof(MACRESTYPELIST)); // Fix up the offset to the ref list
memcpy(((PMACRESTYPELIST)pTypeInfo)->mwOffsetToRefList, WordToMacWord(wOffsetToRefList), sizeof(WORD)); pRefList = pTypeList+wOffsetToRefList; pTypeInfo = pTypeInfo+sizeof(MACRESTYPELIST);
// go to the refence list ...
fileIn.Seek(dwOffsetToTypeList+MacWordToWord(TypeList.mwOffsetToRefList), CFile::begin);
WORD wItems = MacWordToWord(TypeList.mwNumOfThisType)+1; while(wItems){ // and read the reference list for this type
fileIn.Read( &RefList, sizeof(MACRESREFLIST)); dwOffsetToLastRefList = fileIn.GetPosition();
// is this a named resource ...
if(MacWordToWord(RefList.mwOffsetToResName)!=0xffff) { // read the string
fileIn.Seek(dwOffsetToNameList+MacWordToWord(RefList.mwOffsetToResName), CFile::begin); BYTE bLen = 0; fileIn.Read(&bLen, 1); if(!pNameList) { pName = pNameList = (BYTE*)malloc(1024); if(!pNameList) { uiError = ERROR_NEW_FAILED; goto exit; } } // check the free space we have
if((1024-((pName-pNameList)%1024))<=bLen+1){ BYTE * pNew = (BYTE*)realloc(pNameList, _msize(pNameList)+1024); if(!pNew) { uiError = ERROR_NEW_FAILED; goto exit; } pName = pNew+(pName-pNameList); pNameList = pNew; }
// Update the pointer to the string
memcpy(RefList.mwOffsetToResName, WordToMacWord((WORD)(pName-pNameList)), 2);
memcpy(pName++, &bLen, 1); // we have room for the string
fileIn.Read(pName, bLen);
pName = pName+bLen; }
// check if this item has been updated
if(pListItem = IsResUpdated(&TypeList.szResName[0], RefList, pUpdList)) { // Save the offset to the resource
DWORD dwOffsetToData = fileOut.GetPosition(); DWORD dwSize = *pListItem->pSize;
// allocate the buffer to hold the resource data
pByte = (BYTE*)malloc(dwSize); if(!pByte){ uiError = ERROR_NEW_FAILED; goto exit; }
// get the data from the iodll
LPSTR lpType = LPNULL; LPSTR lpRes = LPNULL; if (*pListItem->pTypeId) { lpType = (LPSTR)((WORD)*pListItem->pTypeId); } else { lpType = (LPSTR)pListItem->pTypeName; } if (*pListItem->pResId) { lpRes = (LPSTR)((WORD)*pListItem->pResId); } else { lpRes = (LPSTR)pListItem->pResName; }
DWORD dwImageBufSize = (*g_lpfnGetImage)( hResFileModule, lpType, lpRes, *pListItem->pLang, pByte, *pListItem->pSize );
// Remove the file name from the image
int iFileNameLen = strlen((LPSTR)pByte)+1; dwSize -= iFileNameLen;
// write the size of the data block
fileOut.Write(LongToMacLong(dwSize), sizeof(DWORD)); dwSizeOfData += dwSize+sizeof(DWORD);
fileOut.Write((pByte+iFileNameLen), dwSize);
free(pByte);
// fix up the offset to the resource in the ref list
memcpy(RefList.bOffsetToResData, LongToMacOffset(dwOffsetToData-dwBeginOfResData), 3); } else { // Get the data from the Src file
// get to the data
fileIn.Seek(MacLongToLong(fileHeader.mulOffsetToResData)+ MacOffsetToLong(RefList.bOffsetToResData), CFile::begin);
// read the size of the data block
DWORD dwSize = 0; fileIn.Read(&dwSize, sizeof(DWORD));
// Save the offset to the resource
DWORD dwOffsetToData = fileOut.GetPosition();
// write the size of the data block
fileOut.Write(&dwSize, sizeof(DWORD)); dwSizeOfData += sizeof(DWORD);
// allocate the buffer to hold the resource data
dwSizeOfData += dwSize = MacLongToLong((BYTE*)&dwSize); pByte = (BYTE*)malloc(dwSize); if(!pByte){ uiError = ERROR_NEW_FAILED; goto exit; }
// copy the data
fileIn.Read(pByte, dwSize); fileOut.Write(pByte, dwSize);
free(pByte);
// fix up the offset to the resource in the ref list
memcpy(RefList.bOffsetToResData, LongToMacOffset(dwOffsetToData-dwBeginOfResData), 3);
}
// return in the right place
fileIn.Seek(dwOffsetToLastRefList, CFile::begin);
// copy this data in the new map buffer
memcpy(pRefList, &RefList, sizeof(MACRESREFLIST)); wOffsetToRefList+=sizeof(MACRESREFLIST);
// move to the new ref list
pRefList = pTypeList+wOffsetToRefList; wItems--; }
fileIn.Seek(dwOffsetToLastTypeInfo, CFile::begin); wType--; }
// copy the resource map header info
memcpy( pNewMap, &resMap, sizeof(MACRESMAP));
// copy the name list at the end of the res map
dwOffsetToNameList = 0; if(pNameList) { dwOffsetToNameList = (DWORD)(pRefList-pNewMap); // copy the name list
memcpy(pRefList, pNameList, (size_t)(pName-pNameList)); free(pNameList); }
// write the resource map
DWORD dwOffsetToResMap = fileOut.GetPosition(); fileOut.Write(pNewMap, lMapSize);
// We need to fix up the file header ...
fileOut.Seek(4, CFile::begin); fileOut.Write(LongToMacLong(dwOffsetToResMap), sizeof(DWORD)); fileOut.Write(LongToMacLong(dwSizeOfData), sizeof(DWORD));
// ... and the resource map header
fileOut.Seek(dwOffsetToResMap+4, CFile::begin); fileOut.Write(LongToMacLong(dwOffsetToResMap), sizeof(DWORD)); fileOut.Write(LongToMacLong(dwSizeOfData), sizeof(DWORD));
fileOut.Seek(dwOffsetToResMap+26, CFile::begin); fileOut.Write(WordToMacWord(LOWORD(dwOffsetToNameList)), sizeof(WORD));
} exit: fileIn.Close(); fileOut.Close(); if(pNewMap) free(pNewMap); if(pUpdList) free(pUpdList);
return (UINT)uiError; }
extern "C" DllExport UINT APIENTRY RWUpdateImage( LPCSTR lpszType, LPVOID lpNewBuf, DWORD dwNewSize, LPVOID lpOldImage, DWORD dwOldImageSize, LPVOID lpNewImage, DWORD* pdwNewImageSize ) { UINT uiError = ERROR_RW_NOTREADY;
//===============================================================
// Since all the Type are named in the mac at this stage we need to
// know the original name of the Type and not the Windows type.
// Use the typeID stored in the new ites buffer
LPSTR lpRealType = ((PRESITEM)lpNewBuf)->lpszTypeID;
if(!HIWORD(lpRealType)) // something is wrong if this is not valid
return uiError;
//===============================================================
// Menus
if( !strcmp(lpRealType, "MENU") ) return UpdateMENU( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize );
//===============================================================
// Strings
if( !strcmp(lpRealType, "STR ") ) return UpdateSTR( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize );
if( !strcmp(lpRealType, "STR#") ) return UpdateSTRNUM( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize );
if( !strcmp(lpRealType, "WIND") ) return UpdateWIND( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize );
//===============================================================
// Dialogs
if( !strcmp(lpRealType, "DLOG") ) return UpdateDLOG( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize ); if( !strcmp(lpRealType, "ALRT") ) return UpdateALRT( lpNewBuf, dwNewSize, lpOldImage, dwOldImageSize, lpNewImage, pdwNewImageSize );
*pdwNewImageSize = 0L; return uiError; }
///////////////////////////////////////////////////////////////////////////
// Functions implementation
//=============================================================================
// MapToWindowsRes
//
// Map a Mac resource name to a Windows resource
//=============================================================================
WORD MapToWindowsRes( char * pResName ) { if( !strcmp(pResName, "PICT") || !strcmp(pResName, "WBMP")) return 2; if( !strcmp(pResName, "MENU") || !strcmp(pResName, "WMNU")) return 4;
if( !strcmp(pResName, "DLOG") || !strcmp(pResName, "ALRT") || !strcmp(pResName, "WDLG")) return 5;
if( !strcmp(pResName, "STR ")) return STR_TYPE;
if( !strcmp(pResName, "STR#") || !strcmp(pResName, "TEXT")) return MSG_TYPE;
if( !strcmp(pResName, "vers") || !strcmp(pResName, "VERS")) return 16;
// For the Item list return 17. This means nothing to windows and will
// give us the flexibility to update the DITL list from the RW, without user
// input.
if( !strcmp(pResName, "DITL")) return DITL_TYPE;
// For the Frame Window Caption mark it as type 18
if( !strcmp(pResName, "WIND")) return WIND_TYPE;
return 0; }
//=============================================================================
// WriteResInfo
//
// Fill the buffer to pass back to the iodll
//=============================================================================
LONG WriteResInfo( BYTE** lplpBuffer, LONG* plBufSize, WORD wTypeId, LPSTR lpszTypeId, BYTE bMaxTypeLen, WORD wNameId, LPSTR lpszNameId, BYTE bMaxNameLen, DWORD dwLang, DWORD dwSize, DWORD dwFileOffset ) { LONG lSize = 0; lSize = PutWord( lplpBuffer, wTypeId, plBufSize ); lSize += PutStringA( lplpBuffer, lpszTypeId, plBufSize ); // Check if it is alligned
lSize += Allign( lplpBuffer, plBufSize, lSize);
lSize += PutWord( lplpBuffer, wNameId, plBufSize ); lSize += PutStringA( lplpBuffer, lpszNameId, plBufSize ); lSize += Allign( lplpBuffer, plBufSize, lSize);
lSize += PutDWord( lplpBuffer, dwLang, plBufSize );
lSize += PutDWord( lplpBuffer, dwSize, plBufSize );
lSize += PutDWord( lplpBuffer, dwFileOffset, plBufSize );
return (LONG)lSize; }
BOOL InitIODLLLink() { if(!g_IODLLInst) { // Init the link with the iodll
g_IODLLInst = LoadLibrary("iodll.dll"); if(!g_IODLLInst) return FALSE;
if((g_lpfnGetImage = (DWORD (PASCAL *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD)) GetProcAddress( g_IODLLInst, "RSGetResImage" ))==NULL) return FALSE;
if((g_lpfnHandleFromName = (HANDLE (PASCAL *)(LPCSTR)) GetProcAddress( g_IODLLInst, "RSHandleFromName" ))==NULL) return FALSE;
if((g_lpfnUpdateResImage = (DWORD (PASCAL *)(HANDLE, LPSTR, LPSTR, DWORD, DWORD, LPVOID, DWORD)) GetProcAddress( g_IODLLInst, "RSUpdateResImage" ))==NULL) return FALSE;
} else { if(g_lpfnGetImage==NULL || g_lpfnHandleFromName==NULL) return FALSE; }
return TRUE; }
////////////////////////////////////////////////////////////////////////////
// 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();
// remove the link with iodll
if(g_IODLLInst) FreeLibrary(g_IODLLInst);
}
if (dwReason == DLL_PROCESS_DETACH || dwReason == DLL_THREAD_DETACH) return 0; // CRT term Failed
return 1; // ok
}
/////////////////////////////////////////////////////////////////////////////
|