/***************************************************************************** Copyright (c) 2001, Microsoft Corporation All rights reserved. Module Name: muirct.cpp Abstract: The main funtion of muirct program Revision History: 2001-10-01 sunggch created. Revision. *******************************************************************************/ #include "muirct.h" #include "res.h" //#include "resource.h" #include "cmf.h" #define MAX_NUM_RESOURCE_TYPES 40 #define LANG_CHECKSUM_DEFAULT 0x409 BOOL GetFileNames(CMuiCmdInfo* pcmci, LPTSTR * pszSource, LPTSTR * pszNewFile, LPTSTR * pszMuiFile ) /*++ Abstract: Get the file names from the CMuiCmdInfo. Arguments: pcmci - CMuiCmdInof object; has values of these files.. pszSource - destination of source file pszNewFile - destination of new dll, which is same with source file without selected resource pszMuiRes - destination of new mui file. Return: TRUE/FALSE --*/ { DWORD dwCount = 0; LPTSTR *ppsz = NULL; if ( pcmci == NULL || pszSource == NULL || pszNewFile == NULL || pszMuiFile == NULL) return FALSE; ppsz = pcmci ->GetValueLists (_T("source"),dwCount ); if ( ! ppsz ) { return FALSE; } *pszSource = *ppsz; ppsz = pcmci ->GetValueLists (_T("muidll"), dwCount ); if ( ! ppsz ) { return FALSE; } *pszNewFile = *ppsz; ppsz = pcmci ->GetValueLists (_T("muires"), dwCount ); if ( ! ppsz ) { return FALSE; } *pszMuiFile = *ppsz; return TRUE; } BOOL FilterRemRes ( cvcstring * cvRemovedResTypes, LPTSTR * ppRemoveRes, const UINT dwRemoveCount, BOOL fSanityCheck ) /*++ Abstract: Compare the resource types between cvRemovedResTypes and ppRemoveRes, and leave the ppRemoveRes values in the cvRemovedResTypes Arguments: cvRemovedResTypes - contains a resources types, which will be trimmed by ppRemoveRes ppRemoveRes - new resource types dwRemoveCount - number of count in ppRemoveRes Return: true/false --*/ { DWORD dwCountofSameTypes =0; cvcstring * cvRemovedResTypesTemp = NULL; if ( cvRemovedResTypes == NULL || ppRemoveRes == NULL) return FALSE; cvRemovedResTypesTemp = new cvcstring(MAX_NUM_RESOURCE_TYPES); if (!cvRemovedResTypesTemp) return FALSE; for (UINT i = 0; i < cvRemovedResTypes -> Size() ; i ++ ) { BOOL fIsResourceSame = FALSE ; LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(i); for (UINT j = 0; j < dwRemoveCount; j ++ ) { if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // strings if (! _tcsicmp(ppRemoveRes[j],lpResourceTypeInFile ) ) { fIsResourceSame = TRUE; // remove resours has value break; } } else { if (! ( _tcstod (ppRemoveRes[j],NULL ) - (DWORD)PtrToUlong(lpResourceTypeInFile) ) ) { fIsResourceSame = TRUE; // remove resource has value break; } } } if (fIsResourceSame) { // we need to keep the order of resource types in cvRemovedResTypes because it affects // checksum cvRemovedResTypesTemp -> Push_back(cvRemovedResTypes -> GetValue (i) ); dwCountofSameTypes++; } } if (fSanityCheck && (dwCountofSameTypes < dwRemoveCount) ) { _tprintf(_T(" One of resource types isn't contained target source files\n")); _tprintf(_T(" You can avoid type check when you use -o argument\n")); _tprintf(_T(" Standard Resource Types: CURSOR(1) BITMAP(2) ICON(3) MENU(4) DIALOG(5)\n") ); _tprintf(_T(" STRING(6) FONTDIR(7) FONT(8) ACCELERATORS(9) RCDATA(10) MESSAGETABLE(11)\n") ); _tprintf(_T(" GROUP_CURSOR(12) GROUP_ICON(14) VERSION(16)\n") ); delete cvRemovedResTypesTemp; return FALSE; } cvRemovedResTypes -> Clear(); for ( i = 0; i < cvRemovedResTypesTemp ->Size(); i ++ ) { cvRemovedResTypes ->Push_back ( cvRemovedResTypesTemp ->GetValue( i ) ); } delete cvRemovedResTypesTemp; return TRUE; } cvcstring * FilterKeepRes ( cvcstring * cvRemovedResTypes, LPTSTR * ppKeepRes, cvcstring * cvKeepResTypes, UINT dwKeepCount, BOOL fSanityCheck ) /*++ Abstract: Fill cvKeepResTypes(cvcstring type) and check values existence inside cvRemovedResTypes(removed resource types) then return error when fSanityCheck is true. Arguments: cvRemovedResTypes - contains a resources types, which will be trimmed by ppRemoveRes ppKeepRes - new resource types dwRemoveCount - number of count in ppRemoveRes cvKeepResTypes - filtered resource types will be saved. fSanityCheck - do sanity check if it is true. Return: cvcstring, which include resource that should be removed. --*/ { cvcstring * cvRemovedResTypesTemp = NULL; if ( cvRemovedResTypes == NULL || ppKeepRes == NULL || cvKeepResTypes == NULL) return FALSE; cvRemovedResTypesTemp = new cvcstring(MAX_NUM_RESOURCE_TYPES); BOOL fRet; // // this is just checking if value of -k is included in the -i value. // if (fSanityCheck) { for ( UINT i = 0; i < dwKeepCount; i ++ ) { fRet = TRUE ; for (UINT j = 0; j < cvRemovedResTypes -> Size(); j ++ ) { LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(j); if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // strings if (! _tcsicmp(ppKeepRes[i],lpResourceTypeInFile ) ) { fRet = FALSE; // remove resource has value break; } } else { if (! ( _tcstoul (ppKeepRes[i],NULL,10 ) - (DWORD)PtrToUlong(lpResourceTypeInFile ) ) ) { fRet = FALSE; // remove resours has value break; } } } if ( fRet ) { _tprintf(_T(" Resource Type %s does not exist in the -i value or file, \n "), ppKeepRes[i] ); _tprintf(_T("You can't use this value for -k argument") ); return NULL; }; } } // // Delete -k argument value from -i value lists // for ( UINT i = 0; i < cvRemovedResTypes->Size(); i ++ ) { fRet = TRUE; LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(i); for ( UINT j = 0; j < dwKeepCount; j ++ ) { if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // REVISIT for Win64 . e.g. xxxxxxxx000000000 if (! _tcsicmp(ppKeepRes[j],lpResourceTypeInFile ) ) { fRet = FALSE; // remove resource has value break; } } else { if (! ( _tcstoul(ppKeepRes[j],NULL,10 ) - (DWORD)PtrToUlong(cvRemovedResTypes->GetValue(i) ) ) ) { fRet = FALSE; // remove resours has value break; } } } if ( !fRet ) { cvKeepResTypes ->Push_back(lpResourceTypeInFile); } else { cvRemovedResTypesTemp->Push_back(lpResourceTypeInFile);// -i value, which is not in the -k value } } // if all values in -i and -k (-y) are identical. if (! cvRemovedResTypesTemp->Size() ) return NULL; return cvRemovedResTypesTemp; } /************************************************************************************* void CheckTypePairs( cvstring * cvRemovedResTypes, cvstring * cvKeepResTypes ) return : no. **************************************************************************************/ void CheckTypePairs( cvcstring * cvRemovedResTypes, cvcstring * cvKeepResTypes ) /*++ Abstract: Some resource type should be pairs, in this case <1, 12 > < 3, 14>. Arguments: cvRemovedResTypes - resource types of being removed cvKeepResTypes - resource types of being mui created but not removed. Return: none --*/ { if (cvRemovedResTypes == NULL || cvKeepResTypes == NULL) return ; if ( cvRemovedResTypes->Find((DWORD)3) && ! cvRemovedResTypes->Find((DWORD)14) ) { cvRemovedResTypes->Push_back( MAKEINTRESOURCE(14) ); } else if ( ! cvRemovedResTypes->Find(3) && cvRemovedResTypes->Find(14) ) { cvRemovedResTypes->Push_back( MAKEINTRESOURCE(3) ); } if ( cvRemovedResTypes->Find(1) && ! cvRemovedResTypes->Find(12) ) { cvRemovedResTypes->Push_back( MAKEINTRESOURCE(12) ); } else if ( ! cvRemovedResTypes->Find(1) && cvRemovedResTypes->Find(12) ) { cvRemovedResTypes->Push_back( MAKEINTRESOURCE(1) ); } if ( cvKeepResTypes->Find((DWORD)3) && ! cvKeepResTypes->Find((DWORD)14) ) { cvKeepResTypes->Push_back( MAKEINTRESOURCE(14) ); } else if ( ! cvKeepResTypes->Find(3) && cvKeepResTypes->Find(14) ) { cvKeepResTypes->Push_back( MAKEINTRESOURCE(3) ); } if ( cvKeepResTypes->Find(1) && ! cvKeepResTypes->Find(12) ) { cvKeepResTypes->Push_back( MAKEINTRESOURCE(12) ); } else if ( ! cvKeepResTypes->Find(1) && cvKeepResTypes->Find(12) ) { cvKeepResTypes->Push_back( MAKEINTRESOURCE(1) ); } } #ifdef NEVER BOOL CompareArgValues(cvcstring * cvAArgValues, cvcstring * cvBArgValues) /*++ Abstract: Comapre the values of arguments Arguments: cvAArgValues : values of arugments cvBArgValues : values of arugments Return: true/false --*/ { if (cvAArgValues == NULL || cvBArgValues == NULL) return FALSE; // // compare its values by while routine because values is initialzed NULL in the CMUICmdInfo. // LPTSTR * ppSrcValues = cvAArgValues; LPTSTR * ppDestValues = cvBArgValues; BOOL fNotIdentical = FALSE; for (UINT i = 0; i < cvAArgValues while (ppSrcValues ) { while ( ppDestValues ) { if ( _tcsicmp(*ppSrcValues,*ppDestValues) ) { fNotIdentical = TRUE; } ppDestValues ++; } ppSrcValues; } return fNotIdentical; } #endif /****************************************************************************************************** BOOL CompactMui(CMuiCmdInfo* pcmci) *******************************************************************************************************/ BOOL CompactMui(CMuiCmdInfo* pcmci) /*++ Abstract: Called by main to call CCompactMUIFile for compacting mui files. Arguments: pcmci - arguments parser class. Return: true/false --*/ { if ( pcmci == NULL) return FALSE; // // Read the arguments list // LPTSTR *ppszMuiFiles = NULL; LPTSTR *ppszCMFFile = NULL; LPTSTR *ppszCodeFileDir = NULL; CCompactMUIFile *pccmf = NULL; DWORD dwcMuiFiles = 0; DWORD dwCount = 0; ppszMuiFiles = pcmci->GetValueLists(_T("m"), dwcMuiFiles); if (! (ppszCMFFile = pcmci->GetValueLists(_T("f"),dwCount) )) { CError ce; ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(f),dwCount)") ); return FALSE; } if(! (ppszCodeFileDir = pcmci->GetValueLists(_T("e"),dwCount)) ) { CError ce; ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(e),dwCount)") ); return FALSE; } // // Create CCompactMUIFile and write files. // pccmf = new CCompactMUIFile; if(!pccmf) return FALSE; if (pccmf->Create(*ppszCMFFile, ppszMuiFiles, dwcMuiFiles) ) { if (pccmf->WriteCMFFile()) { if (pccmf->UpdateCodeFiles(*ppszCodeFileDir, dwcMuiFiles )) { delete pccmf; return TRUE; } } } if(pccmf) delete pccmf; return FALSE; } BOOL UnCompactMui(PSTR pszCMFFile) /*++ Abstract: Calling CCompactMUIFile for uncompact files Arguments: pszCMFFile - CMF file, which will be uncompacted to indivisual MUI files. Return: true/false --*/ { BOOL bRet = FALSE; CCompactMUIFile *pccmf = NULL; if (pszCMFFile == NULL) return FALSE; // // Call CCompactMUIFile::UnCompactMUI // pccmf = new CCompactMUIFile(); if(!pccmf) goto exit; if ( pccmf->UnCompactCMF(pszCMFFile)) { pccmf->WriteCMFFile(); bRet = TRUE; // REVIST ; how about uddating a binary files. } exit: if (pccmf) delete pccmf; return bRet; } BOOL DisplayHeader(PSTR pszCMFFile) /*++ Abstract: Calling CCompactMUIFile for displaying the CMF headers information Arguments: pszCMFFile - CMF file. Return: true/false --*/ { BOOL bRet = FALSE; CCompactMUIFile *pccmf = NULL; if (pszCMFFile == NULL) return FALSE; pccmf = new CCompactMUIFile(); if(!pccmf) goto exit; if( pccmf->DisplayHeaders(pszCMFFile) ) { bRet = TRUE; } exit: if (pccmf) delete pccmf; return bRet; } BOOL AddNewMUIFile(CMuiCmdInfo* pcmci) /*++ Abstract: Calling CCompactMUIFile for adding MUI files into exsiting CMF file. Arguments: pcmci - argument parser class Return: true/false --*/ { if (pcmci == NULL) return FALSE; // Read the arguments list // LPTSTR *ppszNewMuiFile = NULL; LPTSTR *ppszCMFFile = NULL; LPTSTR *ppszCodeFileDir = NULL; CCompactMUIFile *pccmf = NULL; DWORD dwcMuiFiles = 0; DWORD dwCount = 0; BOOL bRet = FALSE; // we don't have to check if it has value for this routine is called by the "a" arg. existence ppszNewMuiFile = pcmci->GetValueLists(_T("a"), dwcMuiFiles); if (! (ppszCMFFile = pcmci->GetValueLists(_T("f"),dwCount) )) { CError ce; ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(f),dwCount)") ); goto exit; } if(! (ppszCodeFileDir = pcmci->GetValueLists(_T("e"),dwCount)) ) { CError ce; ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(e),dwCount)") ); goto exit; } // // Add new mui file into existing cmf file. // pccmf = new CCompactMUIFile; if(!pccmf) goto exit; // TCHAR pszCMFName[MAX_PATH]; if (pccmf->AddFile(*ppszCMFFile, ppszNewMuiFile, dwcMuiFiles ) ) { // _tcscpy(pszCMFName, *ppszCMFFile); if( pccmf->Create(*ppszCMFFile)) { if (pccmf->WriteCMFFile()) { if (pccmf->UpdateCodeFiles(*ppszCodeFileDir, dwcMuiFiles )) { bRet = TRUE; goto exit; } } } } _tprintf(_T("Error happened on AddNewMUIFile, GetLastError(): %ld"), GetLastError() ); exit: if (pccmf) delete pccmf; return bRet; } BOOL AddChecksumToFile(CMuiCmdInfo* pcmci) /*++ Abstract: Adding checksum to external component. this is separted feature Arguments: pcmci - arguments parser class Return: true/false --*/ { cvcstring * cvKeepResTypes= NULL; CMUIResource * pcmui = NULL; BOOL bRet = FALSE; if( pcmci == NULL ) { return FALSE; } LPTSTR *ppChecksumFile = NULL; LPTSTR *ppszTargetFileName = NULL; DWORD dwCount, dwRemoveCount, dwRemoveCountNoSanity; ppszTargetFileName = pcmci->GetValueLists(_T("z"), dwCount); if (!(ppChecksumFile=pcmci->GetValueLists(_T("c"), dwCount))) { _tprintf(_T("Checksum file NOT exist")); goto exit; } LPTSTR * ppRemoveRes = pcmci ->GetValueLists (_T("i"), dwRemoveCount ); // pszTmp would be copied to pszRemove LPTSTR * ppRemoveResNoSanity = pcmci ->GetValueLists (_T("o"), dwRemoveCountNoSanity ); // // Create CMUIResource, which is main class for mui resource handling. // pcmui = new CMUIResource(); if(!pcmui) goto exit; // load checksum file if (! pcmui -> Create(*ppChecksumFile )) // load the file for EnumRes.. goto exit; // // Reorganise removing resource types. // cvcstring * cvRemovedResTypes = pcmui -> EnumResTypes (reinterpret_cast ( pcmui )); // need to change : return LPCTSTR* rather than CVector; if ( cvRemovedResTypes -> Empty() ) { _tprintf(_T("The %s does not contain any resource \n"), *ppChecksumFile ); goto exit; } else { // when there is remove argument and its value e.g. -i 3 4 Anvil .. if ( dwRemoveCount && !!_tcscmp(*ppRemoveRes,_T("ALL") ) ) { if (! FilterRemRes(cvRemovedResTypes,ppRemoveRes,dwRemoveCount, TRUE ) ) { goto exit; } } //if ( dwRemoveCount && _tcscmp(*ppRemoveRes,_T("ALL") ) ){ else if (dwRemoveCountNoSanity) { // This is -o arg. build team does not know what resource type are included in the module, so // they use localizable resource, but -i return false when specified resourc type is not found in the // module. -o does not check sanity of resource type like -i arg. if (! FilterRemRes(cvRemovedResTypes, ppRemoveResNoSanity, dwRemoveCountNoSanity, FALSE ) ) { goto exit; } } // Stop if source only includes type 16. very few case, so use couple of api instead moving the module to front. if (cvRemovedResTypes->Size() == 1 && ! ( PtrToUlong(cvRemovedResTypes->GetValue(0)) - 16 ) ) { _tprintf(_T("The %s contains only VERSION resource \n"), *ppChecksumFile ); goto exit; } } // cvRemovedResTypes.Empty() // // Some resource should be pairs <1, 12> <3, 14> // // we create bogus cvKeepResTypes for calling exisiting ChecktypePairs routine. cvKeepResTypes = new cvcstring (MAX_NUM_RESOURCE_TYPES); if(!cvKeepResTypes) goto exit; CheckTypePairs(cvRemovedResTypes, cvKeepResTypes); // // Create a checksum data // MD5_CTX * pMD5 = NULL; BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE]; DWORD dwLangCount =0; LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount); WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT; if (dwLangCount) { wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0); } pMD5 = pcmui-> CreateChecksum(cvRemovedResTypes, wChecksumLangId); #ifdef CHECKSMU_ALL pMD5 = pcmui-> CreateChecksumWithAllRes(wChecksumLangId); #endif memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE); pcmui -> FreeLibrary(); // // Add a checksum data to target file // if ( !pcmui->Create(*ppszTargetFileName)) goto exit; if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into MUI file _tprintf(_T("Fail to add checksum to version ( %s)\n"),*ppszTargetFileName ); goto exit; } pcmui -> FreeLibrary(); bRet = TRUE; exit: if (pcmui) delete pcmui; return bRet; } /************************************************************************************************************* void _cdecl main (INT argc, void * argv[] ) **************************************************************************************************************/ void _cdecl main (INT argc, void * argv[] ) { WORD wLangID; CMuiCmdInfo* pcmci = NULL; CMUIResource * pcmui = NULL; cvcstring * cvKeepResTypes = NULL; cvcstring * cvKeepResTypesIfExist = NULL; cvcstring * vRemnantRes = NULL; CMUIResource * pcmui2 = NULL; pcmci = new CMuiCmdInfo; if (!pcmci) goto exit; // // SetArgLists(Arglist, NeedValue, AllowFileValue, AllowMultipleFileValue) // pcmci->SetArgLists(_T("abcdefiklmopuvxyz"),_T("abcdefklmopuvyz"), _T("acdefmuz"), _T("am")); //set arg. lists. if (! pcmci->CreateArgList (argc,(TCHAR **) argv ) ) { goto exit; } DWORD dwCount = 0; if ( pcmci->GetValueLists(_T("m"),dwCount ) ){ CompactMui(pcmci); goto exit; } if ( pcmci->GetValueLists(_T("a"),dwCount ) ){ AddNewMUIFile(pcmci); goto exit; } LPTSTR *ppCMFFile = NULL; if ( ppCMFFile = pcmci->GetValueLists(_T("u"),dwCount ) ){ UnCompactMui(*ppCMFFile); goto exit; } if ( ppCMFFile = pcmci->GetValueLists(_T("d"),dwCount ) ){ DisplayHeader(*ppCMFFile); goto exit; } if (pcmci->GetValueLists(_T("z"),dwCount ) ){ AddChecksumToFile(pcmci); goto exit; } // // Fill the CMUIResource intenal data : we don't care languge at this time, but soon add more code to // // handle the languge case. LPCTSTR lpLangID = NULL; LPTSTR * ppsz = NULL; BOOL fForceLocalizedLangID = FALSE; if ( ppsz = pcmci ->GetValueLists (_T("l"), dwCount ) ) { lpLangID = *ppsz; wLangID = (WORD)_tcstol(lpLangID, NULL, 0 ); } else if(ppsz = pcmci ->GetValueLists (_T("x"), dwCount ) ) { lpLangID = *ppsz; wLangID = (WORD)_tcstol(lpLangID, NULL, 0 ); fForceLocalizedLangID = TRUE; } else { _tprintf(_T(" Language ID is not specified, you need to specify the launge id. e.g. -l 0x0409 ") ); goto exit; } // // get the source name and new resource free file, mui resource file name. // LPTSTR pszSource,pszNewFile,pszMuiFile ; pszSource = pszNewFile =pszMuiFile = NULL; if ( ! GetFileNames(pcmci, &pszSource, &pszNewFile, &pszMuiFile ) ) { _tprintf(_T("\n Can't find source name, or Name does not format of *.* \n") ); _tprintf(_T("MUIRCT [-h|?] -l langid [-i resource_type] [-k resource_type] [-y resource_type] \n") ); _tprintf(_T("source_filename, [language_neutral_filename], [MUI_filename] \n\n")); goto exit; } // // we need to change the attribute of source as read/write before copy. new file inherit old one attribute. // SetFileAttributes (pszSource, FILE_ATTRIBUTE_ARCHIVE ); if ( _tcsicmp(pszSource,pszNewFile) ) { // new file name is same with source file. if (! CopyFile (pszSource, pszNewFile, FALSE ) ) { printf("GetLastError () : %d \n", GetLastError() ); _tprintf (_T(" Copy File error, GetLastError() : %d \n "), GetLastError() ); goto exit; } } // // Read the value of r (remove resource) , k (keep resource) // DWORD dwKeepCount, dwRemoveCount,dwKeepIfExistCount, dwRemoveCountNoSanity; dwKeepCount = dwRemoveCount = dwKeepIfExistCount = dwRemoveCountNoSanity = 0; LPTSTR * ppKeepRes = pcmci ->GetValueLists (_T("k"), dwKeepCount ); LPTSTR * ppRemoveRes = pcmci ->GetValueLists (_T("i"), dwRemoveCount ); // pszTmp would be copied to pszRemove LPTSTR * ppRemoveResNoSanity = pcmci ->GetValueLists (_T("o"), dwRemoveCountNoSanity ); LPSTR * ppKeepIfExists = pcmci->GetValueLists(_T("y"), dwKeepIfExistCount); #ifdef NEVER if (! CompareArgValues(ppRemoveRes,ppKeepRes ) ) { // if same, goto 0. goto exit; } #endif // // Create CMUIResource, which is main class for mui resource handling. // pcmui = new CMUIResource(); //(pszNewFile); if (! pcmui) { _tprintf(_T("Insufficient resource \n") ); goto exit; } // // Create checksum data with all resource except version.Disabled at this time. // #ifdef CHECKSMU_ALL LPTSTR lpChecksumFile = NULL; BOOL fChecksum = FALSE; MD5_CTX * pMD5 = NULL; BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE]; if ( ppsz = pcmci ->GetValueLists (_T("c"), dwCount ) ) { lpChecksumFile = *ppsz ; // load checksum file if ( ! pcmui -> Create(lpChecksumFile ) ) // load the file for EnumRes.. goto exit; // create a checksum MD5_CTX format ( 16 byte: all resources are caculated based on some algorithm. DWORD dwLangCount =0; LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount); WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT; if (dwLangCount) { wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0); } pMD5 = pcmui-> CreateChecksumWithAllRes(wChecksumLangId); memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE); pcmui -> FreeLibrary(); fChecksum = TRUE; } #endif // // load new MUI file // if (! pcmui -> Create(pszNewFile) ) { // load the file . goto exit; } // // Reorganise removing resource types. // cvcstring * cvRemovedResTypes = pcmui -> EnumResTypes (reinterpret_cast ( pcmui )); // need to change : goto LPCTSTR* rather than CVector; if ( cvRemovedResTypes -> Empty() ) { _tprintf(_T("The %s does not contain any resource \n"), pszSource ); goto exit; } else { // when there is remove argument and its value e.g. -i 3 4 Anvil .. if ( dwRemoveCount && !!_tcscmp(*ppRemoveRes,_T("ALL") ) ) { if (! FilterRemRes(cvRemovedResTypes,ppRemoveRes,dwRemoveCount, TRUE ) ) { goto exit; } } //if ( dwRemoveCount && _tcscmp(*ppRemoveRes,_T("ALL") ) ){ else if (dwRemoveCountNoSanity) { // This is -o arg. build team does not know what resource type are included in the module, so // they use localizable resource, but -i goto false when specified resourc type is not found in the // module. -o does not check sanity of resource type like -i arg. if (! FilterRemRes(cvRemovedResTypes, ppRemoveResNoSanity, dwRemoveCountNoSanity, FALSE ) ) { goto exit; } } // Stop if source only includes type 16. very few case, so use couple of api instead moving the module to front. if (cvRemovedResTypes->Size() == 1 && ! ( PtrToUlong(cvRemovedResTypes->GetValue(0)) - 16 ) ) { if ( _tcsicmp(pszSource, pszNewFile) ) { pcmui->FreeLibrary(); DeleteFile(pszNewFile); } _tprintf(_T("The %s contains only VERSION resource \n"), pszSource ); goto exit; } } // cvRemovedResTypes.Empty() // // we need to get -k argument and check its sanity and save its valus into cvcstring format. // we also need to check if -i values and those of -k, -y are identical. // rethink : what if remove sanity check from -k arg. then we can delete -y arg. as well as most of below. // cvKeepResTypes = new cvcstring (MAX_NUM_RESOURCE_TYPES); if(!cvKeepResTypes) goto exit; cvKeepResTypesIfExist = new cvcstring (MAX_NUM_RESOURCE_TYPES); if(!cvKeepResTypesIfExist) goto exit; if ( dwKeepCount && dwKeepIfExistCount ) { // both of -k, -y arg. exist. if (!( vRemnantRes = FilterKeepRes(cvRemovedResTypes,ppKeepRes,cvKeepResTypes,dwKeepCount,TRUE ) ) ){ goto exit; } if (! FilterKeepRes( vRemnantRes, ppKeepIfExists, cvKeepResTypesIfExist, dwKeepIfExistCount,FALSE) ) { goto exit; } } else if ( dwKeepCount) { // only -k arg. exist. if (!( vRemnantRes = FilterKeepRes(cvRemovedResTypes,ppKeepRes,cvKeepResTypes,dwKeepCount,TRUE ) ) ){ goto exit; } } else if (dwKeepIfExistCount) { if ( ! FilterKeepRes( cvRemovedResTypes, ppKeepIfExists, cvKeepResTypesIfExist, dwKeepIfExistCount,FALSE)) { goto exit; } } // // Some resource should be pairs <1, 12> <3, 14> // CheckTypePairs(cvRemovedResTypes,cvKeepResTypes); // #ifndef CHECKSUM_ALL // // Create checksum with only selected resource types. // LPTSTR lpChecksumFile = NULL; BOOL fChecksum = FALSE; MD5_CTX * pMD5 = NULL; BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE]; if ( ppsz = pcmci ->GetValueLists (_T("c"), dwCount ) ) { pcmui2 = new CMUIResource(); lpChecksumFile = *ppsz ; // load checksum file if ( ! pcmui2 -> Create(lpChecksumFile ) ) // load the file for EnumRes.. goto exit; DWORD dwLangCount =0; LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount); WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT; if (dwLangCount) { wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0); } // create a checksum MD5_CTX format ( 16 byte: all resources are caculated based on some algorithm. pMD5 = pcmui2-> CreateChecksum(cvRemovedResTypes, wChecksumLangId); memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE); pcmui2 -> FreeLibrary(); fChecksum = TRUE; } // #endif // // Fill CMUIData field. it goto false when there is no LangID specified. // Is there any chance of no resource name when resource type exist ? // if ( !pcmui -> FillMuiData( cvRemovedResTypes, wLangID, fForceLocalizedLangID) ) { _tprintf (_T("Fail to get resouce name or lang id \n " ) ); goto exit; }; // // -p arugment; the valules of this argument(resourc type) should not be included in new MUI File. // although delete them from source file. // dwCount =0; if ( ppsz = pcmci ->GetValueLists (_T("p"), dwCount ) ) { for (UINT i =0; i < dwCount; i ++) { LPCSTR lpDelResourceType = NULL; LPTSTR pszResType = *ppsz++; LPTSTR pszStopped = NULL; DWORD dwTypeID = _tcstoul(pszResType,&pszStopped,10 ); if ( 0 == dwTypeID || *pszStopped != _T('\0')) { // string type lpDelResourceType = pszResType ; } else { // id lpDelResourceType = MAKEINTRESOURCE(dwTypeID); } pcmui->DeleteResItem( lpDelResourceType ); } } DWORD dwVerbose = 0; if ( ppsz = pcmci ->GetValueLists (_T("v"), dwCount ) ) dwVerbose = _tcstoul(*ppsz,NULL, 10 ); // Set the link.exe path, link options. TCHAR lpCommandLine[] = _T(" /noentry /dll /nologo /nodefaultlib /SUBSYSTEM:WINDOWS,5.01"); // // Create the mui resource files with the information from FillMuiData // We can use both of these way : WriteResFile : call link.exe inside after creation of RES file // CreatePE : using UpdateResource using // UpdateResource has bug to fail when udpated data is large. so we use link. // if ( ! pcmui -> WriteResFile (pszSource, pszMuiFile, lpCommandLine, wLangID ) ) { // if ( ! pcmui -> CreatePE ( pszMuiFile , pszSource ) ) { // this can be used after more investigation(if it is used, we can remove -s ) _tprintf (_T(" Muirct fail to creat new mui rc file. GetLastError() : %d \n "), GetLastError() ); } else { if ( dwVerbose == 1 || dwVerbose == 2) { _tprintf (_T(" MUI resource file(%s) is successfully created \n\n"), pszMuiFile ); } if ( dwVerbose == 2) { pcmui ->PrtVerbose( 1 ); _tprintf("\n"); } } // // delete values of -k from -i values. // if (dwKeepCount) { for (UINT i = 0; i < cvKeepResTypes->Size(); i ++ ) { pcmui->DeleteResItem( cvKeepResTypes->GetValue (i) ); } } // // handling of -y argument; it is same with -k argument except skip the checking of its existence. // if ( dwKeepIfExistCount ) { for (UINT i = 0; i < cvKeepResTypesIfExist->Size(); i++) { pcmui->DeleteResItem(cvKeepResTypesIfExist->GetValue(i) ); } #ifdef NEVER for (UINT i = 0; i < dwKeepIfExistCount; i ++ ) { LPCSTR lpDelResourceType = NULL; LPTSTR pszValue = ppKeepIfExists[i]; LPTSTR pszStopped = NULL; DWORD dwTypeID = _tcstoul(pszValue,&pszStopped,10 ); if ( 0 == dwTypeID || *pszStopped != _T('\0')) { // string type lpDelResourceType = pszValue ; } else { // id lpDelResourceType = MAKEINTRESOURCE(dwTypeID); } pcmui->DeleteResItem( lpDelResourceType ); } #endif } // // Delete resource from the pszNewFile // if ( ! pcmui -> DeleteResource () ) { _tprintf (_T(" Muirct fail to remove the resource from the file\n" ) ); } else { if ( dwVerbose == 1 || dwVerbose == 2) { _tprintf (_T(" New Resource removed file(%s) is successfully created\n\n" ), pszNewFile ); } if ( dwVerbose == 2) { _tprintf(_T(" Removed resource types \n\n") ); pcmui ->PrtVerbose( 1 ); _tprintf("\n"); } } // // Adding a resource checksum into two files ( lang-neutral binary and mui file ) // if ( fChecksum ){ pcmui->Create(pszMuiFile); if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into MUI file _tprintf(_T("Fail to add checksum to version ( %s)\n"),pszMuiFile ); } pcmui->Create(pszNewFile); if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into lang-neutral binary. _tprintf(_T("Fail to add checksum to version ( %s); \n"),pszNewFile ); } } // // Updating file checksum in language-free binary // BOOL fSuccess = pcmui->UpdateNtHeader(pszNewFile,pcmui->CHECKSUM ); exit: if (pcmci) delete pcmci; if (pcmui) delete pcmui; if(pcmui2) delete pcmui2; if (cvKeepResTypes) delete cvKeepResTypes; return; }