1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-17 00:44:19 +00:00
JUCE/src/native/mac/juce_mac_Files.mm
2011-04-16 22:09:19 +01:00

484 lines
16 KiB
XML

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
// (This file gets included by juce_mac_NativeCode.mm, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
/*
Note that a lot of methods that you'd expect to find in this file actually
live in juce_posix_SharedCode.h!
*/
//==============================================================================
bool File::copyInternal (const File& dest) const
{
JUCE_AUTORELEASEPOOL
NSFileManager* fm = [NSFileManager defaultManager];
return [fm fileExistsAtPath: juceStringToNS (fullPath)]
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
&& [fm copyItemAtPath: juceStringToNS (fullPath)
toPath: juceStringToNS (dest.getFullPathName())
error: nil];
#else
&& [fm copyPath: juceStringToNS (fullPath)
toPath: juceStringToNS (dest.getFullPathName())
handler: nil];
#endif
}
void File::findFileSystemRoots (Array<File>& destArray)
{
destArray.add (File ("/"));
}
//==============================================================================
namespace FileHelpers
{
bool isFileOnDriveType (const File& f, const char* const* types)
{
struct statfs buf;
if (juce_doStatFS (f, buf))
{
const String type (buf.f_fstypename);
while (*types != 0)
if (type.equalsIgnoreCase (*types++))
return true;
}
return false;
}
bool isHiddenFile (const String& path)
{
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
JUCE_AUTORELEASEPOOL
NSNumber* hidden = nil;
NSError* err = nil;
return [[NSURL fileURLWithPath: juceStringToNS (path)]
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
&& [hidden boolValue];
#elif JUCE_IOS
return File (path).getFileName().startsWithChar ('.');
#else
FSRef ref;
LSItemInfoRecord info;
return FSPathMakeRefWithOptions ((const UInt8*) path.toUTF8().getAddress(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
&& (info.flags & kLSItemInfoIsInvisible) != 0;
#endif
}
#if JUCE_IOS
const String getIOSSystemLocation (NSSearchPathDirectory type)
{
return nsStringToJuce ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
objectAtIndex: 0]);
}
#endif
bool launchExecutable (const String& pathAndArguments)
{
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
const int cpid = fork();
if (cpid == 0)
{
// Child process
if (execve (argv[0], (char**) argv, 0) < 0)
exit (0);
}
else
{
if (cpid < 0)
return false;
}
return true;
}
}
bool File::isOnCDRomDrive() const
{
const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
return FileHelpers::isFileOnDriveType (*this, cdTypes);
}
bool File::isOnHardDisk() const
{
const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
}
bool File::isOnRemovableDrive() const
{
#if JUCE_IOS
return false; // xxx is this possible?
#else
JUCE_AUTORELEASEPOOL
BOOL removable = false;
[[NSWorkspace sharedWorkspace]
getFileSystemInfoForPath: juceStringToNS (getFullPathName())
isRemovable: &removable
isWritable: nil
isUnmountable: nil
description: nil
type: nil];
return removable;
#endif
}
bool File::isHidden() const
{
return FileHelpers::isHiddenFile (getFullPathName());
}
//==============================================================================
const char* juce_Argv0 = nullptr; // referenced from juce_Application.cpp
const File File::getSpecialLocation (const SpecialLocationType type)
{
JUCE_AUTORELEASEPOOL
String resultPath;
switch (type)
{
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
#if JUCE_IOS
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
case tempDirectory:
{
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
}
#else
case userDocumentsDirectory: resultPath = "~/Documents"; break;
case userDesktopDirectory: resultPath = "~/Desktop"; break;
case tempDirectory:
{
File tmp ("~/Library/Caches/" + juce_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
}
#endif
case userMusicDirectory: resultPath = "~/Music"; break;
case userMoviesDirectory: resultPath = "~/Movies"; break;
case userApplicationDataDirectory: resultPath = "~/Library"; break;
case commonApplicationDataDirectory: resultPath = "/Library"; break;
case globalApplicationsDirectory: resultPath = "/Applications"; break;
case invokedExecutableFile:
if (juce_Argv0 != 0)
return File (CharPointer_UTF8 (juce_Argv0));
// deliberate fall-through...
case currentExecutableFile:
return juce_getExecutableFile();
case currentApplicationFile:
{
const File exe (juce_getExecutableFile());
const File parent (exe.getParentDirectory());
#if JUCE_IOS
return parent;
#else
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
? parent.getParentDirectory().getParentDirectory()
: exe;
#endif
}
case hostApplicationPath:
{
unsigned int size = 8192;
HeapBlock<char> buffer;
buffer.calloc (size + 8);
_NSGetExecutablePath (buffer.getData(), &size);
return String::fromUTF8 (buffer, size);
}
default:
jassertfalse; // unknown type?
break;
}
if (resultPath.isNotEmpty())
return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
return File::nonexistent;
}
//==============================================================================
const String File::getVersion() const
{
JUCE_AUTORELEASEPOOL
String result;
NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())];
if (bundle != nil)
{
NSDictionary* info = [bundle infoDictionary];
if (info != nil)
{
NSString* name = [info valueForKey: @"CFBundleShortVersionString"];
if (name != nil)
result = nsStringToJuce (name);
}
}
return result;
}
//==============================================================================
const File File::getLinkedTarget() const
{
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_ALLOWED >= MAC_OS_X_VERSION_10_5)
NSString* dest = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (getFullPathName()) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (getFullPathName())];
#endif
if (dest != nil)
return File (nsStringToJuce (dest));
return *this;
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
#if JUCE_IOS
return deleteFile(); //xxx is there a trashcan on the iPhone?
#else
JUCE_AUTORELEASEPOOL
NSString* p = juceStringToNS (getFullPathName());
return [[NSWorkspace sharedWorkspace]
performFileOperation: NSWorkspaceRecycleOperation
source: [p stringByDeletingLastPathComponent]
destination: @""
files: [NSArray arrayWithObject: [p lastPathComponent]]
tag: nil ];
#endif
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl
{
public:
Pimpl (const File& directory, const String& wildCard_)
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
wildCard (wildCard_),
enumerator (nil)
{
JUCE_AUTORELEASEPOOL
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: juceStringToNS (directory.getFullPathName())] retain];
}
~Pimpl()
{
[enumerator release];
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
JUCE_AUTORELEASEPOOL
const char* wildcardUTF8 = nullptr;
for (;;)
{
NSString* file;
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
return false;
[enumerator skipDescendents];
filenameFound = nsStringToJuce (file);
if (wildcardUTF8 == nullptr)
wildcardUTF8 = wildCard.toUTF8();
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
continue;
const String path (parentDir + filenameFound);
updateStatInfoForFile (path, isDir, fileSize, modTime, creationTime, isReadOnly);
if (isHidden != nullptr)
*isHidden = FileHelpers::isHiddenFile (path);
return true;
}
}
private:
String parentDir, wildCard;
NSDirectoryEnumerator* enumerator;
JUCE_DECLARE_NON_COPYABLE (Pimpl);
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
bool PlatformUtilities::openDocument (const String& fileName, const String& parameters)
{
#if JUCE_IOS
return [[UIApplication sharedApplication] openURL: [NSURL fileURLWithPath: juceStringToNS (fileName)]];
#else
JUCE_AUTORELEASEPOOL
if (parameters.isEmpty())
{
return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)]
|| [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: juceStringToNS (fileName)]];
}
bool ok = false;
if (PlatformUtilities::isBundle (fileName))
{
NSMutableArray* urls = [NSMutableArray array];
StringArray docs;
docs.addTokens (parameters, true);
for (int i = 0; i < docs.size(); ++i)
[urls addObject: juceStringToNS (docs[i])];
ok = [[NSWorkspace sharedWorkspace] openURLs: urls
withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (fileName)] bundleIdentifier]
options: 0
additionalEventParamDescriptor: nil
launchIdentifiers: nil];
}
else if (File (fileName).exists())
{
ok = FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
}
return ok;
#endif
}
void File::revealToUser() const
{
#if ! JUCE_IOS
if (exists())
[[NSWorkspace sharedWorkspace] selectFile: juceStringToNS (getFullPathName()) inFileViewerRootedAtPath: @""];
else if (getParentDirectory().exists())
getParentDirectory().revealToUser();
#endif
}
//==============================================================================
#if ! JUCE_IOS
bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
{
return FSPathMakeRef (reinterpret_cast <const UInt8*> (path.toUTF8().getAddress()), destFSRef, 0) == noErr;
}
const String PlatformUtilities::makePathFromFSRef (FSRef* file)
{
char path [2048] = { 0 };
if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
return PlatformUtilities::convertToPrecomposedUnicode (CharPointer_UTF8 (path));
return String::empty;
}
#endif
//==============================================================================
OSType PlatformUtilities::getTypeOfFile (const String& filename)
{
JUCE_AUTORELEASEPOOL
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_ALLOWED >= MAC_OS_X_VERSION_10_5)
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: juceStringToNS (filename) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: juceStringToNS (filename) traverseLink: NO];
#endif
return [fileDict fileHFSTypeCode];
}
bool PlatformUtilities::isBundle (const String& filename)
{
#if JUCE_IOS
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
#else
JUCE_AUTORELEASEPOOL
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (filename)];
#endif
}
#endif