//************************************************************************************** // Filename: FileUtilsCM.cp // Part of Contextual Menu Workshop by Abracode Inc. // http://free.abracode.com/cmworkshop/ // Copyright © 2002-2003 Abracode, Inc. All rights reserved. // // Description: File Utils Contextual Menu plugin // //************************************************************************************** #include "MoreFilesExtras.h" #include "CFAbstractCMPlugin.h" #include "CMUtils.h" #include "CFObjDel.h" #include "StAEDesc.h" #include "CInternetConfig.h" #include "StAllocThrowDisable.h" #include "DebugSettings.h" #include #include OSStatus FSRefCheckFileOrFolder(const FSRef *inRef, void *ioData); OSStatus FSRefProcessFileOrFolder(const FSRef *inRef, void *ioData); OSStatus AddPathToHandle(const FSRef *inRef, Handle *textHPtr); OSStatus CopyTextToClipboard(Handle textH); OSStatus ToggleExtensionVisibility(const FSRef *inRef); OSStatus SetTypeAndCreator(const FSRef *inRef); OSStatus FindEntryForExtension(StringPtr inFileName, ICMapEntry &outEntry); OSStatus FindEntryForTypeCreator(OSType inType, OSType inCreator, Str255 inName, ICMapEntry &outEntry); Boolean BoolArrayIsAnyTrue(const Boolean inArray[], UInt32 inCount); Boolean BoolArrayAreAllTrue(const Boolean inArray[], UInt32 inCount); Boolean IsItemInTheList(SInt32 inItem, const SInt32 inArray[], UInt32 inCount); void AppendPString(StringPtr inBaseStr, SInt32 inBaseSize, ConstStringPtr inAppendStr); void AppendText(StringPtr inBaseStr, SInt32 inBaseSize, const char* inAppendStr, SInt32 inAppendCount); char * UInt64ToCStr(UInt64 &inNum); const OSType kAppSig = 'fuCM'; enum { kOtherStrings = 132, kBytesStrIndx = 1 }; // Strings enum FU_CM_StringIndexes { kFUCommandStrings = 130, // STR# id kFileUtilsSuperStrIndx = 1, kRefreshStrIndx, kCopyPathStrIndx, kCopyPathsStrIndx, kTouchModifStrIndx, kTouchModifsStrIndx, kTouchCreationStrIndx, kToggleLockStrIndx, kLockStrIndx, kUnlockStrIndx, kToggleExtVisStrIndx, kShowExtensionStrIndx, kHideExtensionStrIndx, kSetTypeStrIndx }; enum FI_CM_StringIndexes { kFICommandStrings = 131, kFileInfoSuperStrIndx = 1, kFITypeStrIndx, kFICreatorStrIndx, kCreateDateStrIndex, kModifDateStrIndex, kDataLogicalSizeStrIndx, kDataPhysicalSizeStrIndx, kResLogicalSizeStrIndx, kResPhysicalSizeStrIndx }; enum FU_CM_CommandIndexes { kRefreshIndex = 0, kCopyPathIndex, kTouchModifIndex, kTouchCreationIndex, kToggleLockIndex, kToggleExtVisIndex, kSetTypeIndex, kFUCommandCount }; enum FI_CM_CommandIndexes { kTypeIndex, kCreatorIndex, kCreateDateIndex, kModifDateIndex, kDataLogicalSizeIndex, kDataPhysicalSizeIndex, kResLogicalSizeIndex, kResPhysicalSizeIndex, kFICommandCount }; static SInt32 sFUCommandIDs[kFUCommandCount] = { kRefreshCommand, kCopyPathCommand, kTouchModifCommand, kTouchCreationCommand, kToggleLockCommand, kToggleExtVisCommand, kSetTypeCommand }; static SInt32 sFICommandIDs[kFICommandCount] = { kFITypeCommand, kFICreatorCommand, kFICreateDateCommand, kFIModifDateCommand, kFIDataLogicalSizeCommand, kFIDataPhysicalSizeCommand, kFIResLogicalSizeCommand, kFIResPhysicalSizeCommand }; static char * sFUPrefKeys[kFUCommandCount] = { "ACTIVE_REFRESH", "ACTIVE_COPY_PATH", "ACTIVE_TOUCH_MODIF", "ACTIVE_TOUCH_CREAT", "ACTIVE_TOGGLE_LOCK", "ACTIVE_TOGGLE_EXT_VIS", "ACTIVE_SET_TYPE" }; struct FU_CM_StringChoice { SInt16 single[2];//2 choices for 2 states SInt16 multi[2]; }; //single multi // 0 1 0 1 static FU_CM_StringChoice sFUStringIDs[kFUCommandCount] = { { { kRefreshStrIndx, kRefreshStrIndx }, { kRefreshStrIndx, kRefreshStrIndx } }, //kRefreshIndex { { kCopyPathStrIndx, kCopyPathStrIndx }, { kCopyPathsStrIndx, kCopyPathsStrIndx } }, //kCopyPathIndex { { kTouchModifStrIndx, kTouchModifStrIndx }, { kTouchModifsStrIndx, kTouchModifsStrIndx } },//kTouchModifIndex { { kTouchCreationStrIndx, kTouchCreationStrIndx }, { kTouchCreationStrIndx, kTouchCreationStrIndx } },//kTouchCreationIndex //Q: is locked? false true { { kLockStrIndx, kUnlockStrIndx }, { kToggleLockStrIndx, kToggleLockStrIndx } }, //kToggleLockIndex //Q: is hidden? false true { { kHideExtensionStrIndx, kShowExtensionStrIndx }, { kToggleExtVisStrIndx, kToggleExtVisStrIndx } }, //kToggleExtVisIndex { { kSetTypeStrIndx, kSetTypeStrIndx }, { kSetTypeStrIndx, kSetTypeStrIndx } } //kSetTypeIndex }; struct FI_CM_StringChoice { SInt16 single[2];//2 choices for 2 states }; static FI_CM_StringChoice sFIStringIDs[kFICommandCount] = { { kFITypeStrIndx, kFITypeStrIndx }, { kFICreatorStrIndx, kFICreatorStrIndx }, { kCreateDateStrIndex, kCreateDateStrIndex }, { kModifDateStrIndex, kModifDateStrIndex }, { kDataLogicalSizeStrIndx, kDataLogicalSizeStrIndx }, { kDataPhysicalSizeStrIndx, kDataPhysicalSizeStrIndx }, { kResLogicalSizeStrIndx, kResLogicalSizeStrIndx }, { kResPhysicalSizeStrIndx, kResPhysicalSizeStrIndx } }; struct FileInfoCheckData { Str255 fileName; LongDateTime creationDate; LongDateTime modificationDate; UInt64 dataLogicalSize; UInt64 dataPhysicalSize; UInt64 rsrcLogicalSize; UInt64 rsrcPhysicalSize; LSItemInfoFlags flags; OSType fileType; OSType fileCreator; Boolean okToAct[kFICommandCount]; Boolean isActive[kFICommandCount]; SInt16 currState[kFICommandCount]; Boolean isFilledOnce;//fill this data only once - for muliple selections we do not show file info }; struct FileUtilsCheckData { Boolean okToAct[kFUCommandCount]; Boolean isActive[kFUCommandCount]; SInt16 currState[kFUCommandCount]; FileInfoCheckData fiData; }; struct FileUtilsProcessData { SInt32 commandID; UTCDateTime currTime; Handle textH; AEDescList filesToKick; }; OSStatus AddFileInfoCommands( AEDescList* ioCommands, FileInfoCheckData &fiData ); void ReadPreferences(FileUtilsCheckData &checkData); // --------------------------------------------------------------------------- // CMPluginExamineContext // --------------------------------------------------------------------------- // Have a look at the selection and decides whether to display any commands OSStatus CMPluginExamineContext( void *thisInstance, const AEDesc *inContext, AEDescList *outCommandPairs ) { TRACE_STR( "\pFileUtilsCM->CMPluginExamineContext" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; if(inContext == NULL) return errAENotAEDesc; if(inContext->descriptorType == typeNull) return errAENotAEDesc; OSStatus err = noErr; UInt32 theFlags = kProcBreakOnFirst; FileUtilsCheckData checkData; std::memset( &checkData, 0, sizeof(checkData) ); ReadPreferences( checkData ); CMUtils::ProcessObjectList( inContext, theFlags, FSRefCheckFileOrFolder, (void*)&checkData ); Boolean isMultiSelection = ((theFlags & kListOutMultipleObjects) != 0); if( BoolArrayIsAnyTrue( checkData.okToAct, kFUCommandCount) ) { StBundleResOpen resOpen( theThis->bundleRef ); if( resOpen.IsValid() ) { StAEDesc theSubmenuCommands; OSErr err = ::AECreateList( NULL, 0, false, theSubmenuCommands ); if(err == noErr) { UInt32 stringIndex = 0; for(UInt32 i = 0; i < kFUCommandCount; i++ ) { if( (err == noErr) && checkData.okToAct[i] ) { if(isMultiSelection) stringIndex = sFUStringIDs[i].multi[ checkData.currState[i] ]; else stringIndex = sFUStringIDs[i].single[ checkData.currState[i] ]; err = CMUtils::AddResCommand( theSubmenuCommands, kFUCommandStrings, stringIndex, sFUCommandIDs[i] ); } } if(err == noErr) err = CMUtils::AddSubmenu( outCommandPairs, kFUCommandStrings, kFileUtilsSuperStrIndx, theSubmenuCommands ); } } } if( !isMultiSelection && BoolArrayIsAnyTrue( checkData.fiData.okToAct, kFICommandCount) ) { StBundleResOpen resOpen( theThis->bundleRef ); if( resOpen.IsValid() ) { StAEDesc theSubmenuCommands; OSErr err = ::AECreateList( NULL, 0, false, theSubmenuCommands ); if(err == noErr) { err = AddFileInfoCommands(theSubmenuCommands, checkData.fiData); if(err == noErr) err = CMUtils::AddSubmenu( outCommandPairs, kFICommandStrings, kFileUtilsSuperStrIndx, theSubmenuCommands ); } } } return err; } // --------------------------------------------------------------------------- // CMPluginHandleSelection // --------------------------------------------------------------------------- // Carry out the command that the user selected. The commandID indicates // which command was selected OSStatus CMPluginHandleSelection( void *thisInstance, AEDesc *inContext, SInt32 inCommandID ) { TRACE_STR( "\pFileUtilsCM->CMPluginHandleSelection" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; OSStatus err = noErr; if( IsItemInTheList(inCommandID, sFUCommandIDs, kFUCommandCount) ) { FileUtilsProcessData processData; processData.commandID = inCommandID; processData.textH = NULL; processData.filesToKick.descriptorType = typeNull; processData.filesToKick.dataHandle = NULL; if( (inCommandID == kRefreshCommand) || (inCommandID == kTouchModifCommand) || (inCommandID == kTouchCreationCommand) || (inCommandID == kToggleLockCommand) || (inCommandID == kToggleExtVisCommand) || (inCommandID == kSetTypeCommand) ) { err = ::AECreateList( NULL, 0, false, &(processData.filesToKick) ); } if( (inCommandID == kTouchModifCommand) || (inCommandID == kTouchCreationCommand) ) { err = ::GetUTCDateTime( &processData.currTime, kUTCDefaultOptions ); } if(err == noErr) { UInt32 theFlags = kListClear; CMUtils::ProcessObjectList( inContext, theFlags, FSRefProcessFileOrFolder, (void *)&processData ); } StAEDesc theDel(processData.filesToKick); if(inCommandID == kCopyPathCommand) err = CopyTextToClipboard(processData.textH); if( processData.textH != NULL ) { ::DisposeHandle(processData.textH); processData.textH = NULL; } 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 err; } // --------------------------------------------------------------------------- // CMPluginPostMenuCleanup // --------------------------------------------------------------------------- void CMPluginPostMenuCleanup( void *thisInstance ) { TRACE_STR( "\pFileUtilsCM->CMPluginPostMenuCleanup" ); AbstractCMPluginType *theThis = (AbstractCMPluginType *)thisInstance; } #pragma mark - OSStatus FSRefCheckFileOrFolder(const FSRef *inRef, void *ioData) { TRACE_STR( "\pFileUtilsCM->FSRefCheckFileOrFolder" ); if( (inRef == NULL) || (ioData == NULL) ) return paramErr; FileUtilsCheckData *checkData = (FileUtilsCheckData *)ioData; //we are interested in real files or folders //sometimes we get FSRef not valid (InternetExplorer) FSCatalogInfo theInfo; OSStatus err = ::FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags, &theInfo, NULL, NULL, NULL); if( err == noErr ) { if( ! checkData->fiData.isFilledOnce ) { //file info section CMUtils::GetPStringName(inRef, checkData->fiData.fileName); FSCatalogInfoBitmap whichInfo = kFSCatInfoContentMod | kFSCatInfoCreateDate; Boolean checkSizes = false; if( (theInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0 ) { whichInfo |= (kFSCatInfoDataSizes | kFSCatInfoRsrcSizes); checkSizes = true; } err = ::FSGetCatalogInfo(inRef, whichInfo, &theInfo, NULL, NULL, NULL); LocalDateTime locCreateDate; err = ::ConvertUTCToLocalDateTime( &theInfo.createDate, &locCreateDate); LocalDateTime locModifDate; err = ::ConvertUTCToLocalDateTime( &theInfo.contentModDate, &locModifDate); LongDateCvt *longDate = (LongDateCvt *)&checkData->fiData.creationDate; longDate->hl.lHigh = locCreateDate.highSeconds; longDate->hl.lLow = locCreateDate.lowSeconds; longDate = (LongDateCvt *)&checkData->fiData.modificationDate; longDate->hl.lHigh = locModifDate.highSeconds; longDate->hl.lLow = locModifDate.lowSeconds; if(checkSizes) { checkData->fiData.dataLogicalSize = theInfo.dataLogicalSize; checkData->fiData.dataPhysicalSize = theInfo.dataPhysicalSize; checkData->fiData.rsrcLogicalSize = theInfo.rsrcLogicalSize; checkData->fiData.rsrcPhysicalSize = theInfo.rsrcPhysicalSize; } else { checkData->fiData.dataLogicalSize = 0; checkData->fiData.dataPhysicalSize = 0; checkData->fiData.rsrcLogicalSize = 0; checkData->fiData.rsrcPhysicalSize = 0; } for(int i = 0; i < kFICommandCount; i++) { checkData->fiData.okToAct[i] = checkData->fiData.isActive[i]; checkData->fiData.currState[i] = 0; } LSItemInfoRecord itemInfo; std::memset( &itemInfo, 0, sizeof(itemInfo) ); LSRequestedInfo ls_whichInfo = 0; ls_whichInfo |= kLSRequestTypeCreator; ls_whichInfo |= kLSRequestBasicFlagsOnly; ls_whichInfo |= kLSRequestExtensionFlagsOnly; err = ::LSCopyItemInfoForRef( inRef, ls_whichInfo, &itemInfo ); if(err == noErr) { checkData->fiData.flags = itemInfo.flags; checkData->fiData.fileType = itemInfo.filetype; checkData->fiData.fileCreator = itemInfo.creator; } checkData->fiData.isFilledOnce = true; } //file utils section checkData->okToAct[kRefreshIndex] = checkData->isActive[kRefreshIndex]; checkData->currState[kRefreshIndex] = 0; checkData->okToAct[kCopyPathIndex] = checkData->isActive[kCopyPathIndex]; checkData->currState[kCopyPathIndex] = 0; checkData->okToAct[kTouchModifIndex] = checkData->isActive[kTouchModifIndex]; checkData->currState[kTouchModifIndex] = 0; checkData->okToAct[kTouchCreationIndex] = checkData->isActive[kTouchCreationIndex]; checkData->currState[kTouchCreationIndex] = 0; checkData->okToAct[kToggleLockIndex] = checkData->isActive[kToggleLockIndex]; checkData->currState[kToggleLockIndex] = ( (theInfo.nodeFlags & kFSNodeLockedMask) != 0 ) ? 1 : 0;//is locked? if( checkData->isActive[kToggleExtVisIndex] || checkData->isActive[kSetTypeIndex]) { LSItemInfoRecord itemInfo; std::memset( &itemInfo, 0, sizeof(itemInfo) ); LSRequestedInfo whichInfo = 0; if(checkData->isActive[kToggleExtVisIndex]) whichInfo |= kLSRequestExtensionFlagsOnly; if(checkData->isActive[kSetTypeIndex]) whichInfo |= kLSRequestExtension; err = ::LSCopyItemInfoForRef( inRef, whichInfo, &itemInfo ); if(err == noErr) { if(checkData->isActive[kToggleExtVisIndex]) { checkData->okToAct[kToggleExtVisIndex] = true; checkData->currState[kToggleExtVisIndex] = ( (itemInfo.flags & kLSItemInfoExtensionIsHidden) != 0 ) ? 1 : 0;//is hidden? } CFObjDel extDel(itemInfo.extension); if(checkData->isActive[kSetTypeIndex]) { if(itemInfo.extension != NULL) { checkData->okToAct[kSetTypeIndex] = (::CFStringGetLength(itemInfo.extension) > 0); checkData->currState[kSetTypeIndex] = 0; } } } } //only when all options are OK'ed we can break if( BoolArrayAreAllTrue(checkData->okToAct, kFUCommandCount) ) return noErr;//file loop will break now } return fnfErr;//return error - meaning: loop more } OSStatus FSRefProcessFileOrFolder(const FSRef *inRef, void *ioData) { TRACE_STR( "\pFileUtilsCM->ProcessFileOrFolder" ); if( (inRef == NULL) || (ioData == NULL) ) return paramErr; FileUtilsProcessData *processData = (FileUtilsProcessData *)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( "\pCFStringGetPascalString failed" ); } } else { DEBUG_STR( "\pCFURLGetString failed" ); } } else { DEBUG_STR( "\pCFURLCreateFromFSRef failed" ); } #endif //_DEBUG_ Boolean kickFinder = false; FSCatalogInfo theInfo; err = ::FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags, &theInfo, NULL, NULL, NULL); if ( err == noErr ) {//if valid file or folder switch(processData->commandID) { case kRefreshCommand: { err = noErr; kickFinder = true; } break; case kCopyPathCommand: { err = AddPathToHandle(inRef, &(processData->textH) ); kickFinder = false; } break; case kTouchModifCommand: case kTouchCreationCommand: { FSCatalogInfoBitmap whichInfo = kFSCatInfoContentMod; theInfo.contentModDate = processData->currTime; if( processData->commandID == kTouchCreationCommand ) {//all dates whichInfo |= kFSCatInfoCreateDate | kFSCatInfoAttrMod | kFSCatInfoAccessDate | kFSCatInfoBackupDate; theInfo.createDate = processData->currTime; theInfo.attributeModDate = processData->currTime; theInfo.accessDate = processData->currTime; theInfo.backupDate = processData->currTime; } err = ::FSSetCatalogInfo(inRef, whichInfo, &theInfo); kickFinder = true; } break; case kToggleLockCommand: { FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeFlags; if( (theInfo.nodeFlags & kFSNodeLockedMask) != 0 ) {//is locked, unlock it theInfo.nodeFlags &= ~kFSNodeLockedMask; } else {//is unlocked, lock it theInfo.nodeFlags |= kFSNodeLockedMask; } err = ::FSSetCatalogInfo(inRef, whichInfo, &theInfo); kickFinder = true; } break; case kToggleExtVisCommand: { err = ToggleExtensionVisibility(inRef); kickFinder = true; } break; case kSetTypeCommand: { err = SetTypeAndCreator(inRef); kickFinder = true; } break; default: { DEBUG_STR( "\pUnknown command requested" ); err = fnfErr; kickFinder = false; } break; } } else { DEBUG_STR( "\pFSGetCatalogInfo failed" ); } if( kickFinder && (err == noErr) && (processData->filesToKick.dataHandle != NULL) ) { StAEDesc fileDesc; err = CMUtils::CreateAliasDesc( inRef, fileDesc ); if(err == noErr) { err = ::AEPutDesc( &(processData->filesToKick), 0, fileDesc ); } } return err; } #pragma mark - OSStatus AddPathToHandle(const FSRef *inRef, Handle *textHPtr) { TRACE_STR( "\pAddPathToHandle" ); if( (inRef == NULL) || (textHPtr == NULL) ) return paramErr; OSStatus err = noErr; CFURLRef urlRef = CFURLCreateFromFSRef( kCFAllocatorDefault, inRef ); if(urlRef == NULL) return fnfErr; CFObjDel urlDel(urlRef); CFStringRef strRef = CFURLGetString( urlRef ); if(strRef != NULL) { CFStringEncoding sysEnc = ::CFStringGetSystemEncoding(); CFIndex uniCount = ::CFStringGetLength(strRef); CFIndex maxCount = ::CFStringGetMaximumSizeForEncoding(uniCount, sysEnc); Ptr theString = ::NewPtrClear(maxCount +1);//one more for 0-termination if(theString != NULL) { if( ::CFStringGetCString( strRef, theString, maxCount +1, sysEnc) ) { SInt32 actualLen = std::strlen(theString); Size oldHSize = 0; if( *textHPtr == NULL) { *textHPtr = ::NewHandle(actualLen); } else { oldHSize = ::GetHandleSize( *textHPtr ); //if anything has been put into the handle already - we add CR before next URL (if not present already) if(oldHSize > 0 && (*(*textHPtr))[oldHSize-1] != 0x0D) { ::SetHandleSize( *textHPtr, oldHSize + 1 + actualLen); if( (err = ::MemError()) == noErr) (*(*textHPtr))[oldHSize] = 0x0D;//insert carriage return oldHSize++; } } if(*textHPtr == NULL) { err = memFullErr; } else { ::HLock( *textHPtr ); ::BlockMoveData(theString, **textHPtr + oldHSize, actualLen); ::HUnlock( *textHPtr ); } } ::DisposePtr(theString); } } return err; } OSStatus CopyTextToClipboard(Handle textH) { OSStatus err = noErr; if(textH != NULL) { Size handleSize = ::GetHandleSize(textH); if(handleSize > 0) { ::HLock(textH); err = ::ClearCurrentScrap(); if(err == noErr) { ScrapRef scrap; if( (err = ::GetCurrentScrap(&scrap)) == noErr ) { err = ::PutScrapFlavor( scrap, 'TEXT', kScrapFlavorMaskNone, handleSize, *textH ); } } } } return err; } OSStatus ToggleExtensionVisibility(const FSRef *inRef) { OSStatus err = noErr; LSItemInfoRecord itemInfo; LSRequestedInfo whichInfo = kLSRequestExtensionFlagsOnly; err = ::LSCopyItemInfoForRef( inRef, whichInfo, &itemInfo ); if(err == noErr) { Boolean isHidden = ((itemInfo.flags & kLSItemInfoExtensionIsHidden) != 0); err = ::LSSetExtensionHiddenForRef( inRef, !isHidden ); } return err; } OSStatus SetTypeAndCreator(const FSRef *inRef) { TRACE_STR( "\pFileUtilsCM->SetTypeAndCreator" ); OSStatus err = noErr; FSCatalogInfo theFileInfo; FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeFlags | kFSCatInfoFinderInfo | kFSCatInfoTextEncoding; HFSUniStr255 uniFileName; err = ::FSGetCatalogInfo( inRef, whichInfo, &theFileInfo, &uniFileName, NULL, NULL); if( err == noErr ) { if( theFileInfo.textEncodingHint == kTextEncodingUnknown) theFileInfo.textEncodingHint = ::CFStringGetSystemEncoding(); CFStringRef theStrRef = ::CFStringCreateWithCharacters( kCFAllocatorDefault, uniFileName.unicode, uniFileName.length ); if(theStrRef != NULL) { CFObjDel strDel(theStrRef); Str255 fileName; Boolean isOK = ::CFStringGetPascalString(theStrRef, fileName, sizeof(fileName), theFileInfo.textEncodingHint); if(isOK) { ICMapEntry theEntry; err = FindEntryForExtension( fileName, theEntry ); if(err == noErr) { whichInfo = kFSCatInfoFinderInfo; FileInfo *theInfo = (FileInfo *)theFileInfo.finderInfo; theInfo->fileType = theEntry.fileType; theInfo->fileCreator = theEntry.fileCreator; err = ::FSSetCatalogInfo( inRef, whichInfo, &theFileInfo); } else { DEBUG_STR( "\p\tSetTypeAndCreator: FindEntryForExtension failed" ); } } else { err = -1; DEBUG_STR( "\p\tSetTypeAndCreator: CFStringGetPascalString failed" ); } } else { err = -1; DEBUG_STR( "\p\tSetTypeAndCreator: CFStringCreateWithCharacters failed" ); } } else { DEBUG_STR( "\p\tSetTypeAndCreator: FSGetCatalogInfo failed" ); } return err; } OSStatus FindEntryForExtension(StringPtr inFileName, ICMapEntry &outEntry) { CInternetConfig theIC(kAppSig); OSStatus status = theIC.Start(); if(status != noErr) { DEBUG_STR( "\p\tFindEntryForExtension: theIC.Start() failed" ); return status; } status = theIC.MapFilename(inFileName, outEntry); if(status != noErr) { DEBUG_STR( "\p\tFindEntryForExtension: theIC.MapFilename() failed" ); } return status; } OSStatus FindEntryForTypeCreator(OSType inType, OSType inCreator, Str255 inName, ICMapEntry &outEntry) { CInternetConfig theIC(kAppSig); OSStatus status = theIC.Start(); if(status != noErr) return status; status = theIC.MapTypeCreator(inType, inCreator, inName, outEntry); return status; } #pragma mark - void ReadPreferences(FileUtilsCheckData &checkData) { TRACE_STR( "\pFileUtilsCM->ReadPreferences" ); //set defaults for(UInt32 i = 0; i < kFUCommandCount; i++) { checkData.isActive[i] = true; } for(UInt32 i = 0; i < kFICommandCount; i++) { checkData.fiData.isActive[i] = true; } ::CFPreferencesAppSynchronize( CFSTR(CM_IMPL_PLUGIN_PREFS_INDENTIFIER) ); Boolean isValid = false; CFIndex theVer = ::CFPreferencesGetAppIntegerValue( CFSTR("VERSION"), CFSTR(CM_IMPL_PLUGIN_PREFS_INDENTIFIER), &isValid ); if( isValid && (theVer != 0) ) { CFStringRef theKey = NULL; CFIndex theState = 0; for(UInt32 i = 0; i < kFUCommandCount; i++) { isValid = false; theKey = ::CFStringCreateWithCString( kCFAllocatorDefault, sFUPrefKeys[i], kTextEncodingMacRoman ); if(theKey != NULL) { theState = ::CFPreferencesGetAppIntegerValue(theKey, CFSTR(CM_IMPL_PLUGIN_PREFS_INDENTIFIER), &isValid ); } if( isValid ) { checkData.isActive[i] = (theState != 0); } } isValid = false; theState = ::CFPreferencesGetAppIntegerValue(CFSTR("ACTIVE_FILE_INFO"), CFSTR(CM_IMPL_PLUGIN_PREFS_INDENTIFIER), &isValid ); if( isValid ) { if(theState == 0) { DEBUG_STR( "\pFileUtilsCM->ReadPreferences FileInfo disabled" ); for(UInt32 i = 0; i < kFICommandCount; i++) { checkData.fiData.isActive[i] = false; } } else { DEBUG_STR( "\pFileUtilsCM->ReadPreferences FileInfo enabled" ); } } else { DEBUG_STR( "\pFileUtilsCM->ReadPreferences ACTIVE_FILE_INFO key not found" ); } } else { DEBUG_STR( "\pFileUtilsCM->ReadPreferences VERSION key not found" ); } } OSStatus AddFileInfoCommands( AEDescList* ioCommands, FileInfoCheckData &fiData ) { OSStatus err = noErr; Str255 commandString = "\p"; Boolean addNames = false; ICMapEntry icEntry; std::memset( &icEntry, 0, sizeof(icEntry) ); /* wrong descriptions are given by FindEntryForTypeCreator, so we abandon the idea because it will be more confusing for users if( (fiData.fileType != 'APPL') && (fiData.fileType != 0) ) { err = FindEntryForTypeCreator(fiData.fileType, fiData.fileCreator, fiData.fileName, icEntry); if(err == noErr) addNames = true; err = noErr; } */ for(UInt32 i = 0; i < kFICommandCount; i++ ) { if( fiData.okToAct[i] ) { UInt32 stringIndex = sFIStringIDs[i].single[ fiData.currState[i] ]; SInt32 theCmd = sFICommandIDs[i]; commandString[0] = 0; ::GetIndString(commandString, kFICommandStrings, stringIndex); switch(theCmd) { case kFITypeCommand: { if(fiData.fileType == 0) { AppendText(commandString, sizeof(commandString), "", 6); } else { char *fourChars = (char *)&(fiData.fileType); AppendText(commandString, sizeof(commandString), "\'", 1); AppendText(commandString, sizeof(commandString), fourChars, 4); AppendText(commandString, sizeof(commandString), "\'", 1); if(addNames) { AppendPString(commandString, sizeof(commandString), "\p ("); AppendPString(commandString, sizeof(commandString), icEntry.entryName); AppendPString(commandString, sizeof(commandString), "\p)"); } } } break; case kFICreatorCommand: { if(fiData.fileCreator == 0) { AppendText(commandString, sizeof(commandString), "", 6); } else { char *fourChars = (char *)&(fiData.fileCreator); AppendText(commandString, sizeof(commandString), "\'", 1); AppendText(commandString, sizeof(commandString), fourChars, 4); AppendText(commandString, sizeof(commandString), "\'", 1); if(addNames) { AppendPString(commandString, sizeof(commandString), "\p ("); AppendPString(commandString, sizeof(commandString), icEntry.creatorAppName); AppendPString(commandString, sizeof(commandString), "\p)"); } } } break; case kFICreateDateCommand: { Str255 dateStr = "\p"; ::LongDateString( &fiData.creationDate, abbrevDate, dateStr, NULL); AppendPString(commandString, sizeof(commandString), dateStr); dateStr[0]=0; ::LongTimeString( &fiData.creationDate, true, dateStr, NULL); AppendPString(commandString, sizeof(commandString), "\p "); AppendPString(commandString, sizeof(commandString), dateStr); } break; case kFIModifDateCommand: { Str255 dateStr = "\p"; ::LongDateString( &fiData.modificationDate, abbrevDate, dateStr, NULL); AppendPString(commandString, sizeof(commandString), dateStr); dateStr[0]=0; ::LongTimeString( &fiData.modificationDate, true, dateStr, NULL); AppendPString(commandString, sizeof(commandString), "\p "); AppendPString(commandString, sizeof(commandString), dateStr); } break; case kFIDataLogicalSizeCommand: { char * cStr = UInt64ToCStr(fiData.dataLogicalSize); AppendText(commandString, sizeof(commandString), cStr, std::strlen(cStr) ); delete [] cStr; Str255 bytesStr = "\p"; ::GetIndString(bytesStr, kOtherStrings, kBytesStrIndx); AppendPString(commandString, sizeof(commandString), bytesStr); } break; case kFIDataPhysicalSizeCommand: { char * cStr = UInt64ToCStr(fiData.dataPhysicalSize); AppendText(commandString, sizeof(commandString), cStr, std::strlen(cStr) ); delete [] cStr; Str255 bytesStr = "\p"; ::GetIndString(bytesStr, kOtherStrings, kBytesStrIndx); AppendPString(commandString, sizeof(commandString), bytesStr); } break; case kFIResLogicalSizeCommand: { char * cStr = UInt64ToCStr(fiData.rsrcLogicalSize); AppendText(commandString, sizeof(commandString), cStr, std::strlen(cStr) ); delete [] cStr; Str255 bytesStr = "\p"; ::GetIndString(bytesStr, kOtherStrings, kBytesStrIndx); AppendPString(commandString, sizeof(commandString), bytesStr); } break; case kFIResPhysicalSizeCommand: { char * cStr = UInt64ToCStr(fiData.rsrcPhysicalSize); AppendText(commandString, sizeof(commandString), cStr, std::strlen(cStr) ); delete [] cStr; Str255 bytesStr = "\p"; ::GetIndString(bytesStr, kOtherStrings, kBytesStrIndx); AppendPString(commandString, sizeof(commandString), bytesStr); } break; } err = CMUtils::AddCommandToAEDescList(commandString, theCmd, ioCommands); if(err != noErr) break; } } return err; } #pragma mark - Boolean BoolArrayIsAnyTrue(const Boolean inArray[], UInt32 inCount) { for(UInt32 i = 0; i < inCount; i++) { if(inArray[i] == true) return true; } return false; } Boolean BoolArrayAreAllTrue(const Boolean inArray[], UInt32 inCount) { for(UInt32 i = 0; i < inCount; i++) { if(inArray[i] == false) return false; } return true; } Boolean IsItemInTheList(SInt32 inItem, const SInt32 inArray[], UInt32 inCount) { for(UInt32 i = 0; i < inCount; i++) { if(inArray[i] == inItem) return true; } return false; } #pragma mark - void AppendPString(StringPtr inBaseStr, SInt32 inBaseSize, ConstStringPtr inAppendStr) { if( (inBaseStr == NULL) || (inAppendStr == NULL) ) return; SInt32 baseCount = inBaseStr[0]; SInt32 appendCount = inAppendStr[0]; if( appendCount > (inBaseSize - 1 - baseCount) ) { appendCount = inBaseSize - 1 - baseCount; } if(appendCount > 0) { for(int i = 1; i <= appendCount; i++) { inBaseStr[baseCount+i] = inAppendStr[i]; } inBaseStr[0] = baseCount + appendCount; } } void AppendText(StringPtr inBaseStr, SInt32 inBaseSize, const char* inAppendStr, SInt32 inAppendCount) { if( (inBaseStr == NULL) || (inAppendStr == NULL) ) return; SInt32 baseCount = inBaseStr[0]; if( inAppendCount > (inBaseSize - 1 - baseCount) ) { inAppendCount = inBaseSize - 1 - baseCount; } if(inAppendCount > 0) { for(int i = 1; i <= inAppendCount; i++) { inBaseStr[baseCount+i] = inAppendStr[i-1]; } inBaseStr[0] = baseCount + inAppendCount; } } //caller is responsible for releasing the buffer with delete [] //UInt64 must be defined as unsigned long long char * UInt64ToCStr(UInt64 &inNum) {//acessing MSL C++ Lib. MSL __initialize & __terminate must be called for this code fragment std::ostrstream strStream; int flgs = std::ios::dec; strStream.setf( (std::ios_base::fmtflags)flgs ); strStream << inNum << std::ends; char *ptr = strStream.str(); return ptr; }