//************************************************************************************** // Filename: GrimRipperCM.cp // Part of Contextual Menu Workshop by Abracode Inc. // http://free.abracode.com/cmworkshop/ // Copyright © 2002-2003 Abracode, Inc. All rights reserved. // // Description: Resource fork stripper // //************************************************************************************** #include "CFAbstractCMPlugin.h" #include "CMUtils.h" #include "MoreFilesExtras.h" #include "CFObjDel.h" #include "StAEDesc.h" #include "StAllocThrowDisable.h" #include "DebugSettings.h" // Strings enum { kCommandStrings = 130, // STR# id kRipStrIndx = 1, //standard: kAreYouSureStrIndx = 2, kYesStrIndx = 3, kNoStrIndx = 4, //pro: kDoItNowStrIndx = 2, kMaybeLaterStrIndx = 3 }; OSStatus FSRefCheckFileOrFolder(const FSRef *inRef, void *ioData); OSStatus FSRefProcessFileOrFolder(const FSRef *inRef, void *ioData); struct RipperProcessData { AEDescList filesToKick; }; // --------------------------------------------------------------------------- // CMPluginExamineContext // --------------------------------------------------------------------------- // Have a look at the selection and decides whether to display any commands OSStatus CMPluginExamineContext( void *thisInstance, const AEDesc *inContext, AEDescList *outCommandPairs ) { StAllocThrowDisable disableNewThrows;//for MSL operator new TRACE_STR( "\pRipperCM->CMPluginExamineContext" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; if(inContext == NULL) return errAENotAEDesc; if(inContext->descriptorType == typeNull) return errAENotAEDesc; UInt32 theFlags = kProcBreakOnFirst; if( CMUtils::ProcessObjectList( inContext, theFlags, FSRefCheckFileOrFolder ) ) { StBundleResOpen resOpen( theThis->bundleRef ); if( resOpen.IsValid() ) { #if (_GR_MODE_ == 0)//root level: extreme TRACE_STR( "\pRipperCM Extreme" ); OSStatus err = CMUtils::AddResCommand( outCommandPairs, kCommandStrings, kRipStrIndx, kCMImplCommand ); #elif (_GR_MODE_ == 1)//1st level: pro TRACE_STR( "\pRipperCM Pro" ); StAEDesc theSubOneCommands; OSStatus err = ::AECreateList( NULL, 0, false, theSubOneCommands ); if(err != noErr) return err; err = CMUtils::AddResCommand( theSubOneCommands, kCommandStrings, kDoItNowStrIndx, kCMImplCommand ); if(err != noErr) return err; err = CMUtils::AddResCommand( theSubOneCommands, kCommandStrings, kMaybeLaterStrIndx, 0 ); if(err != noErr) return err; err = CMUtils::AddSubmenu( outCommandPairs, kCommandStrings, kRipStrIndx, theSubOneCommands ); #elif (_GR_MODE_ == 2) //2nd level: standard TRACE_STR( "\pRipperCM Standard" ); StAEDesc theSubOneCommands; OSStatus err = ::AECreateList( NULL, 0, false, theSubOneCommands ); if(err != noErr) return err; StAEDesc theSubTwoCommands; err = ::AECreateList( NULL, 0, false, theSubTwoCommands ); if(err != noErr) return err; err = CMUtils::AddResCommand( theSubTwoCommands, kCommandStrings, kYesStrIndx, kCMImplCommand ); if(err != noErr) return err; err = CMUtils::AddResCommand( theSubTwoCommands, kCommandStrings, kNoStrIndx, 0 ); if(err != noErr) return err; err = CMUtils::AddSubmenu( theSubOneCommands, kCommandStrings, kAreYouSureStrIndx, theSubTwoCommands ); if(err != noErr) return err; err = CMUtils::AddSubmenu( outCommandPairs, kCommandStrings, kRipStrIndx, theSubOneCommands ); #endif //_GR_MODE_ return err; } } return noErr; } // --------------------------------------------------------------------------- // CMPluginHandleSelection // --------------------------------------------------------------------------- // Carry out the command that the user selected. The commandID indicates // which command was selected OSStatus CMPluginHandleSelection( void *thisInstance, AEDesc *inContext, SInt32 inCommandID ) { StAllocThrowDisable disableNewThrows;//for MSL operator new TRACE_STR( "\pRipperCM->CMPluginHandleSelection" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; if(inCommandID == kCMImplCommand) { RipperProcessData processData; processData.filesToKick.descriptorType = typeNull; processData.filesToKick.dataHandle = NULL; OSStatus err = ::AECreateList( NULL, 0, false, &(processData.filesToKick) ); UInt32 theFlags = kListClear; CMUtils::ProcessObjectList( inContext, theFlags, FSRefProcessFileOrFolder, (void *)&processData ); StAEDesc theDel(processData.filesToKick); if(processData.filesToKick.dataHandle != NULL) { SInt32 listItemsCount = 0; if( ::AECountItems( &processData.filesToKick, &listItemsCount) == noErr ) { if(listItemsCount > 0) {//tell Finder to update the modified items look CMUtils::SendAppleEventToFinder( kAEFinderSuite, kAESync, processData.filesToKick, false, false ); } } } } return noErr; } // --------------------------------------------------------------------------- // CMPluginPostMenuCleanup // --------------------------------------------------------------------------- void CMPluginPostMenuCleanup( void *thisInstance ) { StAllocThrowDisable disableNewThrows;//for MSL operator new TRACE_STR( "\pRipperCM->CMPluginPostMenuCleanup" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; } #pragma mark - OSStatus FSRefCheckFileOrFolder(const FSRef *inRef, void *ioData) { #pragma unused (ioData) if(inRef == NULL) return paramErr; //we are interested in real files //sometimes we get FSRef not valid (InternetExplorer) FSCatalogInfo theInfo; OSStatus err = ::FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags | kFSCatInfoRsrcSizes, &theInfo, NULL, NULL, NULL); if( err == noErr ) {//if resource fork len is 0 then it is considered that there is no resource fork //you cannot have a resource fork of len 0 if( ((theInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0) && (theInfo.rsrcLogicalSize > 0) && (theInfo.rsrcPhysicalSize > 0) )//just to be sure {//we are interested in files only return noErr; } else return fnfErr; } return err; } OSStatus FSRefProcessFileOrFolder(const FSRef *inRef, void *ioData) { TRACE_STR( "\pRipperCM->ProcessFileOrFolder" ); if( (inRef == NULL) || (ioData == NULL) ) return paramErr; RipperProcessData *processData = (RipperProcessData *)ioData; OSStatus err = noErr; #if _DEBUG_ CFURLRef urlRef = ::CFURLCreateFromFSRef( kCFAllocatorDefault, inRef ); if(urlRef != NULL) { CFObjDel urlDel(urlRef); CFStringRef strRef = ::CFURLGetString( urlRef ); if(strRef != NULL) { Str255 theString; if( ::CFStringGetPascalString(strRef, theString, sizeof(Str255), kCFStringEncodingMacRoman) ) { DEBUG_STR( theString ); } else { DEBUG_STR( "\pRipperCM. CFStringGetPascalString failed" ); } } else { DEBUG_STR( "\pRipperCM. CFURLGetString failed" ); } } else { DEBUG_STR( "\pRipperCM. CFURLCreateFromFSRef failed" ); } #endif //_DEBUG_ FSCatalogInfo theInfo; err = ::FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &theInfo, NULL, NULL, NULL); if( err == noErr ) { if((theInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0) {//we are interested in files only TRACE_STR( "\pRipperCM. Executing now!" ); HFSUniStr255 resourceForkName; err = ::FSGetResourceForkName( &resourceForkName ); if( err == noErr ) { err = ::FSDeleteFork( inRef, resourceForkName.length, resourceForkName.unicode ); if( err == noErr) { FileInfo *finderInfo = (FileInfo *)theInfo.finderInfo; finderInfo->finderFlags &= ~kHasCustomIcon; //clear custom icon bit err = ::FSSetCatalogInfo( inRef, kFSCatInfoFinderInfo, &theInfo ); } if(err == noErr) {//add file to kick-list StAEDesc fileDesc; err = CMUtils::CreateAliasDesc( inRef, fileDesc ); if(err == noErr) { err = ::AEPutDesc( &(processData->filesToKick), 0, fileDesc ); } } } } } else { DEBUG_STR( "\pRipperCM. FSGetCatalogInfo failed" ); } return err; }