//+--------------------------------------------------------------------------- // // File: mac.cpp // // Contents: Implementation for the Macintosh Read/Write module // // History: 23-Aug-94 alessanm created // //---------------------------------------------------------------------------- #include #include #include #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 } /////////////////////////////////////////////////////////////////////////////