/*============================================================================= * CAFileHandling.cpp $Log: CAFileHandling.cpp,v $ Revision 1.15 2004/12/16 20:11:56 bills check that URL is correct Revision 1.14 2004/06/02 19:59:32 bills CreateTrees Needs to know if it should search for Network Dir Revision 1.13 2004/05/26 17:21:01 luke [3656248] allow constructor option to search Network Revision 1.12 2003/12/02 01:11:43 luke factor subclasses out into separate files. AUPresetFile stays public, others are private. Revision 1.11 2003/11/06 22:23:26 luke Subdirectory construction needs to happen in the base class Revision 1.10 2003/11/06 19:20:07 luke all subclasses need to call CreateTrees() Revision 1.9 2003/10/22 21:48:32 luke add interface to get a particular tree's path Revision 1.8 2003/10/18 00:57:28 luke fix infinite-recursion bug in subclasses Revision 1.7 2003/10/14 19:16:51 luke (GetItemNameCopy + GetDirectoryNameCopy) -> GetNameCopy Revision 1.6 2003/10/14 18:19:39 luke pull GetDirectoryNameCopy() functionality from GetItemNameCopy() Revision 1.5 2003/10/14 17:18:46 luke add context-awareness & fix spelling errors Revision 1.4 2003/10/11 22:58:08 bills add support for au effect chains Revision 1.3 2003/10/05 23:14:54 bills tweaks and add support for MIDIThru Revision 1.2 2003/10/04 07:06:03 bills further additions Revision 1.1 2003/10/04 01:42:12 bills initial checkin * Created by William Stewart on Thu Oct 02 2003. * Copyright (c) 2003 Apple Computer. All rights reserved. ==============================================================================*/ #include "CAFileHandling.h" #include "CACFDictionary.h" /* kLocalDomain = -32765, // Domain from '/' kNetworkDomain = -32764, // Domain from '/Network/ kUserDomain = -32763, // Domain from '~/' */ const CFStringRef CAFileHandling::kItemNameKey = CFSTR("name"); CAFileHandling::CAFileHandling (CFStringRef inSubDir, bool inShouldSearchNetwork) : mHasLocalDir (false), mHasNetworkDir(false), mHasUserDir(false), mLocalTree (NULL), mUserTree (NULL), mNetworkTree (NULL), mSubDirName (inSubDir) { mHasLocalDir = FindSpecifiedDir (kLocalDomain, inSubDir, mLocalDir) == noErr; mHasUserDir = FindSpecifiedDir (kUserDomain, inSubDir, mUserDir) == noErr; if (inShouldSearchNetwork) mHasNetworkDir = FindSpecifiedDir (kNetworkDomain, inSubDir, mNetworkDir) == noErr; } CAFileHandling::~CAFileHandling() { if (mLocalTree) CFRelease (mLocalTree); if (mUserTree) CFRelease (mUserTree); if (mNetworkTree) CFRelease (mNetworkTree); } OSStatus CAFileHandling::FindSpecifiedDir (SInt16 inDomain, CFStringRef inAudioSubDirName, FSRef &outDir, bool inCreateDir) { OSStatus result; FSRef parentDir; if (result = FSFindFolder (inDomain, kAudioSupportFolderType, (Boolean)inCreateDir, &parentDir)) return result; if (result = FindSpecifiedDir (parentDir, inAudioSubDirName, outDir, inCreateDir)) { return result; } return noErr; } OSStatus CAFileHandling::FindSpecifiedDir (const FSRef &inParentDir, CFStringRef inSubDirName, FSRef &outDir, bool inCreateDir) { UniChar chars[256]; CFRange range; range.location = 0; range.length = 256; CFStringGetCharacters (inSubDirName, range, chars); OSStatus result; if (result = FSMakeFSRefUnicode (&inParentDir, CFStringGetLength (inSubDirName), chars, kTextEncodingDefaultFormat, &outDir)) { if (result == fnfErr && inCreateDir) { result = FSCreateDirectoryUnicode (&inParentDir, CFStringGetLength(inSubDirName), chars, kFSCatInfoNone, NULL, &outDir, NULL, NULL); } return result; } return noErr; } void CAFileHandling::SetUserDir (FSRef *inRef) { if (inRef) { mUserDir = *inRef; mHasUserDir = true; } else { mHasUserDir = false; } } void CAFileHandling::SetLocalDir (FSRef *inRef) { if (inRef) { mLocalDir = *inRef; mHasLocalDir = true; } else { mHasLocalDir = false; } } void CAFileHandling::SetNetworkDir (FSRef *inRef) { if (inRef) { mNetworkDir = *inRef; mHasNetworkDir = true; } else { mHasNetworkDir = false; } } OSStatus CAFileHandling::CreateSubDirectories (FSRef &inRef, SInt16 inDomain) { switch (inDomain) { case kUserDomain: SetUserDir (&inRef); break; case kLocalDomain: SetLocalDir (&inRef); break; case kNetworkDomain: SetNetworkDir (&inRef); break; } return noErr; } void TreeShow (const void *value, void *context) { if (value) { CAFileHandling* This = (CAFileHandling*)context; This->ShowEntireTree ((CFTreeRef)value); } } void CAFileHandling::ShowEntireTree (CFTreeRef inTree) { CFShow (inTree); if (inTree) CFTreeApplyFunctionToChildren (inTree, TreeShow, this); } CFTreeRef CAFileHandling::AddFileItemToTree (const FSRef &inRef, CFTreeRef inParentTree) { CFTreeRef newTree = CreateTree (inRef); CFTreeAppendChild (inParentTree, newTree); #if 0 CFShow (newTree); #endif CFRelease(newTree); return newTree; } void CAFileHandling::CreateTrees (bool inShouldSearchNetwork) { mLocalTree = CreateNewTree (GetLocalDir(), mLocalTree); if (inShouldSearchNetwork) mNetworkTree = CreateNewTree (GetNetworkDir(), mNetworkTree); mUserTree = CreateNewTree (GetUserDir(), mUserTree); } CFTreeRef CAFileHandling::CreateNewTree (const FSRef* inRef, CFTreeRef inTree) { if (inRef) { if (inTree) CFRelease (inTree); CFTreeRef tree = CreateTree (*inRef); Scan (*inRef, tree); return tree; } return NULL; } CFTreeRef CAFileHandling::CreateTree (const FSRef &inRef) { CFURLRef url = CFURLCreateFromFSRef (kCFAllocatorDefault, &inRef); return CreateTree (url); } CFTreeRef CAFileHandling::CreateTree (CFURLRef inURL) { CFTreeContext treeContext; treeContext.version = 0; treeContext.info = (void*)inURL; treeContext.retain = CFRetain; treeContext.release = CFRelease; treeContext.copyDescription = CFCopyDescription; CFTreeRef tree = CFTreeCreate (kCFAllocatorDefault, &treeContext); CFRelease(inURL); return tree; } void CAFileHandling::Scan (const FSRef &inParentDir, CFTreeRef inParentTree) { OSStatus result; FSIterator iter; if (FSOpenIterator (&inParentDir, kFSIterateFlat, &iter)) return; do { ItemCount numItems = 0; const FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeFlags; FSCatalogInfo catalogInfo; FSRef theFSRef; result = FSGetCatalogInfoBulk (iter, 1, &numItems, NULL, whichInfo, &catalogInfo, &theFSRef, NULL, NULL); if (!result && (numItems > 0)) { if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) { // WE FOUND A SUB DIRECTORY CFTreeRef newSubTree = AddFileItemToTree (theFSRef, inParentTree); #if 0 printf ("\n* * * ADDING DIR * * *\n"); CFShow (newSubTree); #endif Scan (theFSRef, newSubTree); } else { //WE FOUND A FILE CFURLRef fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, &theFSRef); CFStringRef fNameExt = CFURLCopyPathExtension (fileURL); bool matches = false; if (fNameExt) { matches = CFStringCompare(fNameExt, GetExtension(), kCFCompareCaseInsensitive) == kCFCompareEqualTo; CFRelease (fNameExt); } CFRelease (fileURL); if (matches) { #if 0 printf ("* * * ADDING FILE * * *\n"); #endif AddFileItemToTree (theFSRef, inParentTree); } } } } while (!result); // clean up FSCloseIterator (iter); } bool CAFileHandling::IsDirectory (CFTreeRef inTree) const { CFTreeContext context; CFTreeGetContext (inTree, &context); return CFURLHasDirectoryPath ((CFURLRef)context.info); } bool CAFileHandling::IsItem (CFTreeRef inTree) const { CFTreeContext context; CFTreeGetContext (inTree, &context); CFStringRef fNameExt = CFURLCopyPathExtension ((CFURLRef)context.info); if (fNameExt) { bool matches = CFStringCompare(fNameExt, GetExtension(), kCFCompareCaseInsensitive) == kCFCompareEqualTo; CFRelease (fNameExt); return matches; } return false; } bool CAFileHandling::IsUserContext (CFTreeRef inTree) { CFTreeContext context; CFTreeGetContext (inTree, &context); CFURLRef URL = (CFURLRef)context.info; CFURLRef userURL = CFURLCreateFromFSRef (NULL, &mUserDir); if (userURL && URL) if (CFStringHasPrefix (CFURLGetString(URL), CFURLGetString(userURL))) return true; return false; } bool CAFileHandling::IsNetworkContext (CFTreeRef inTree) { CFTreeContext context; CFTreeGetContext (inTree, &context); CFURLRef URL = (CFURLRef)context.info; CFURLRef networkURL = CFURLCreateFromFSRef (NULL, &mNetworkDir); if (networkURL && URL) if (CFStringHasPrefix (CFURLGetString(URL), CFURLGetString(networkURL))) return true; return false; } bool CAFileHandling::IsLocalContext (CFTreeRef inTree) { CFTreeContext context; CFTreeGetContext (inTree, &context); CFURLRef URL = (CFURLRef)context.info; CFURLRef localURL = CFURLCreateFromFSRef (NULL, &mLocalDir); if (localURL && URL) if (CFStringHasPrefix (CFURLGetString(URL), CFURLGetString(localURL))) return true; return false; } OSStatus CAFileHandling::CreateUserDirectories () { if (GetUserDir() && mUserTree) return noErr; OSStatus result; if (result = FindSpecifiedDir (kUserDomain, mSubDirName, mUserDir, true)) return result; if (result = CreateSubDirectories (mUserDir, kUserDomain)) return result; mUserTree = CreateNewTree (GetUserDir(), mUserTree); return noErr; } OSStatus CAFileHandling::CreateLocalDirectories () { if (GetLocalDir() && mLocalTree) return noErr; OSStatus result; if (result = FindSpecifiedDir (kLocalDomain, mSubDirName, mLocalDir, true)) return result; if (result = CreateSubDirectories (mLocalDir, kLocalDomain)) return result; mLocalTree = CreateNewTree (GetLocalDir(), mLocalTree); return noErr; } OSStatus CAFileHandling::CreateNetworkDirectories () { if (GetNetworkDir() && mNetworkTree) return noErr; OSStatus result; if (result = FindSpecifiedDir (kNetworkDomain, mSubDirName, mNetworkDir, true)) return result; if (result = CreateSubDirectories (mNetworkDir, kNetworkDomain)) return result; mNetworkTree = CreateNewTree (GetNetworkDir(), mNetworkTree); return noErr; } OSStatus CAFileHandling::CreateDirectory (CFTreeRef inDirTree, CFStringRef inDirName, CFTreeRef *outTree) { if (IsDirectory (inDirTree) == false) return -1; CFTreeContext context; CFTreeGetContext (inDirTree, &context); FSRef parentDir; if (CFURLGetFSRef((CFURLRef)context.info, &parentDir)) return -1; FSRef subDir; OSStatus result; if (result = FindSpecifiedDir (parentDir, inDirName, subDir, true)) return result; CFTreeRef newTree; newTree = CreateTree (subDir); CFTreeAppendChild (inDirTree, newTree); if (outTree) *outTree = newTree; return noErr; } bool CAFileHandling::ValidPropertyList (CFPropertyListRef inData) { // is our data good? (i.e., is it an instance of CFPropertyListRef?) if (!( CFPropertyListIsValid (inData, kCFPropertyListOpenStepFormat) || CFPropertyListIsValid (inData, kCFPropertyListXMLFormat_v1_0) || CFPropertyListIsValid (inData, kCFPropertyListBinaryFormat_v1_0) )) { return false; } return true; } OSStatus CAFileHandling::SaveInDirectory (CFTreeRef inParentTree, CFStringRef inFileName, CFPropertyListRef inData) { CFTreeContext context; CFTreeGetContext (inParentTree, &context); if (CFURLHasDirectoryPath ((CFURLRef)context.info) == false) return paramErr; if (ValidPropertyList (inData) == false) return -1; CFPropertyListRef plist; OSStatus result; if (result = PremassageDataToSave (inData, inFileName, plist)) return result; CFMutableStringRef fileName = NULL; CFURLRef fileURL = NULL; // Convert the property list into XML data. CFDataRef xmlData = CFPropertyListCreateXMLData (kCFAllocatorDefault, plist); if (xmlData == NULL) { result = paramErr; goto home; } fileName = CFStringCreateMutableCopy (kCFAllocatorDefault, 1024, inFileName); UniChar dot; dot = '.'; CFStringAppendCharacters (fileName, &dot, 1); CFStringAppend (fileName, GetExtension()); fileURL = CFURLCreateCopyAppendingPathComponent (kCFAllocatorDefault, (CFURLRef)context.info, fileName, false); // Write the XML data to the file. Boolean status; status = CFURLWriteDataAndPropertiesToResource (fileURL, xmlData, NULL, &result); CFRelease(xmlData); if (status == false || result) { CFRelease(fileURL); if (!result) result = -1; goto home; } CFTreeRef newTree; newTree = CreateTree (fileURL); //this releases the URL CFTreeAppendChild (inParentTree, newTree); home: if (fileName) CFRelease (fileName); PostmassageSavedData (plist); return result; } OSStatus CAFileHandling::ReadFromTreeLeaf (CFTreeRef inTreeLeaf, CFPropertyListRef &outData, CFStringRef *outErrString) const { CFTreeContext context; CFTreeGetContext (inTreeLeaf, &context); if (CFURLHasDirectoryPath ((CFURLRef)context.info)) return paramErr; CFDataRef resourceData = NULL; SInt32 result; // Read the XML file. Boolean status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, (CFURLRef)context.info, &resourceData, // place to put file data NULL, NULL, &result); if (status == false || result) { if (resourceData) CFRelease (resourceData); return result; } CFStringRef errString = NULL; CFPropertyListRef theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errString); if (theData == NULL || errString) { if (resourceData) CFRelease (resourceData); if (errString) { if (outErrString) *outErrString = errString; else CFRelease (errString); } return -1; } CFRelease (resourceData); PostProcessReadData (theData, outData); return noErr; } OSStatus CAFileHandling::GetNameCopy (CFTreeRef inTree, CFStringRef &outName) const { // first check for directory CFTreeContext context; CFTreeGetContext (inTree, &context); CFURLRef url = (CFURLRef)context.info; if (!url) return paramErr; if (CFURLHasDirectoryPath (url)) { outName = CFURLCopyLastPathComponent (url); return noErr; } // else check for item name CFPropertyListRef data; OSStatus result; if ((result = ReadFromTreeLeaf (inTree, data)) == noErr) { if (CFGetTypeID(data) == CFDictionaryGetTypeID()) { CFStringRef name = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef)data, kItemNameKey); if (name) { CFRetain (name); outName = name; } CFRelease (data); return name ? noErr : OSStatus(paramErr); } return paramErr; } return result; } OSStatus CAFileHandling::GetPathCopy (CFTreeRef inTree, CFURLRef &outURL) const { // first check for directory CFTreeContext context; CFTreeGetContext (inTree, &context); CFURLRef url = (CFURLRef)context.info; CFRetain(url); outURL = url; return noErr; }