|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
- */
-
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <sys/param.h>
- #include <sys/mount.h>
- #include <unistd.h>
- #include <fnmatch.h>
- #include <utime.h>
- #include <pwd.h>
- #include <fcntl.h>
- #include <Carbon/Carbon.h>
-
- BEGIN_JUCE_NAMESPACE
-
- #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
- #include "../../../src/juce_core/io/files/juce_FileOutputStream.h"
- #include "../../../src/juce_core/io/network/juce_URL.h"
- #include "../../../src/juce_core/basics/juce_SystemStats.h"
- #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
- #include "../../../src/juce_core/io/files/juce_NamedPipe.h"
- #include "../../../src/juce_core/threads/juce_InterProcessLock.h"
- #include "../../../src/juce_core/threads/juce_Thread.h"
-
- //==============================================================================
- /*
- Note that a lot of methods that you'd expect to find in this file actually
- live in juce_posix_SharedCode.cpp!
- */
- #include "juce_posix_SharedCode.cpp"
-
-
- //==============================================================================
- static File executableFile;
-
-
- //==============================================================================
- void PlatformUtilities::copyToStr255 (Str255& d, const String& s)
- {
- unsigned char* t = (unsigned char*) d;
- t[0] = jmin (254, s.length());
- s.copyToBuffer ((char*) t + 1, 254);
- }
-
- void PlatformUtilities::copyToStr63 (Str63& d, const String& s)
- {
- unsigned char* t = (unsigned char*) d;
- t[0] = jmin (62, s.length());
- s.copyToBuffer ((char*) t + 1, 62);
- }
-
- const String PlatformUtilities::cfStringToJuceString (CFStringRef cfString)
- {
- String result;
-
- if (cfString != 0)
- {
- #if JUCE_STRINGS_ARE_UNICODE
- CFRange range = { 0, CFStringGetLength (cfString) };
- UniChar* const u = (UniChar*) juce_malloc (sizeof (UniChar) * (range.length + 1));
-
- CFStringGetCharacters (cfString, range, u);
- u[range.length] = 0;
-
- result = convertUTF16ToString (u);
-
- juce_free (u);
- #else
- const int len = CFStringGetLength (cfString);
- char* buffer = (char*) juce_malloc (len + 1);
- CFStringGetCString (cfString, buffer, len + 1, CFStringGetSystemEncoding());
- result = buffer;
- juce_free (buffer);
- #endif
- }
-
- return result;
- }
-
- CFStringRef PlatformUtilities::juceStringToCFString (const String& s)
- {
- #if JUCE_STRINGS_ARE_UNICODE
- const int len = s.length();
- const juce_wchar* t = (const juce_wchar*) s;
-
- UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4);
-
- for (int i = 0; i <= len; ++i)
- temp[i] = t[i];
-
- CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len);
- juce_free (temp);
-
- return result;
-
- #else
- return CFStringCreateWithCString (kCFAllocatorDefault,
- (const char*) s,
- CFStringGetSystemEncoding());
- #endif
- }
-
- const String PlatformUtilities::convertUTF16ToString (const UniChar* utf16)
- {
- String s;
-
- while (*utf16 != 0)
- s += (juce_wchar) *utf16++;
-
- return s;
- }
-
- const String PlatformUtilities::convertToPrecomposedUnicode (const String& s)
- {
- UnicodeMapping map;
-
- map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
- kUnicodeNoSubset,
- kTextEncodingDefaultFormat);
-
- map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
- kUnicodeCanonicalCompVariant,
- kTextEncodingDefaultFormat);
-
- map.mappingVersion = kUnicodeUseLatestMapping;
-
- UnicodeToTextInfo conversionInfo = 0;
- String result;
-
- if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
- {
- const int len = s.length();
-
- UniChar* const tempIn = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4);
- UniChar* const tempOut = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4);
-
- for (int i = 0; i <= len; ++i)
- tempIn[i] = s[i];
-
- ByteCount bytesRead = 0;
- ByteCount outputBufferSize = 0;
-
- if (ConvertFromUnicodeToText (conversionInfo,
- len * sizeof (UniChar), tempIn,
- kUnicodeDefaultDirectionMask,
- 0, 0, 0, 0,
- len * sizeof (UniChar), &bytesRead,
- &outputBufferSize, tempOut) == noErr)
- {
- result.preallocateStorage (bytesRead / sizeof (UniChar) + 2);
-
- tchar* t = const_cast <tchar*> ((const tchar*) result);
-
- int i;
- for (i = 0; i < bytesRead / sizeof (UniChar); ++i)
- t[i] = (tchar) tempOut[i];
-
- t[i] = 0;
- }
-
- juce_free (tempIn);
- juce_free (tempOut);
-
- DisposeUnicodeToTextInfo (&conversionInfo);
- }
-
- return result;
- }
-
- //==============================================================================
- const unsigned int macTimeToUnixTimeDiff = 0x7c25be90;
-
- static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw()
- {
- if (d.highSeconds == 0 && d.lowSeconds == 0 && d.fraction == 0)
- return 0;
-
- return (((((uint64) d.highSeconds) << 32) | (uint64) d.lowSeconds) * 1000)
- + ((d.fraction * 1000) >> 16)
- - 2082844800000ll;
- }
-
- static void unixTimeToUtcDateTime (uint64 t, UTCDateTime& d) throw()
- {
- if (t != 0)
- t += 2082844800000ll;
-
- d.highSeconds = (t / 1000) >> 32;
- d.lowSeconds = (t / 1000) & (uint64) 0xffffffff;
- d.fraction = ((t % 1000) << 16) / 1000;
- }
-
- void juce_getFileTimes (const String& fileName,
- int64& modificationTime,
- int64& accessTime,
- int64& creationTime) throw()
- {
- modificationTime = 0;
- accessTime = 0;
- creationTime = 0;
-
- FSRef fileRef;
- if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
- {
- FSRefParam info;
- zerostruct (info);
-
- info.ref = &fileRef;
- info.whichInfo = kFSCatInfoAllDates;
-
- FSCatalogInfo catInfo;
- info.catInfo = &catInfo;
-
- if (PBGetCatalogInfoSync (&info) == noErr)
- {
- creationTime = utcDateTimeToUnixTime (catInfo.createDate);
- accessTime = utcDateTimeToUnixTime (catInfo.accessDate);
- modificationTime = utcDateTimeToUnixTime (catInfo.contentModDate);
- }
- }
- }
-
- bool juce_setFileTimes (const String& fileName,
- int64 modificationTime,
- int64 accessTime,
- int64 creationTime) throw()
- {
- FSRef fileRef;
- if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
- {
- FSRefParam info;
- zerostruct (info);
-
- info.ref = &fileRef;
- info.whichInfo = kFSCatInfoAllDates;
-
- FSCatalogInfo catInfo;
- info.catInfo = &catInfo;
-
- if (PBGetCatalogInfoSync (&info) == noErr)
- {
- if (creationTime != 0)
- unixTimeToUtcDateTime (creationTime, catInfo.createDate);
-
- if (modificationTime != 0)
- unixTimeToUtcDateTime (modificationTime, catInfo.contentModDate);
-
- if (accessTime != 0)
- unixTimeToUtcDateTime (accessTime, catInfo.accessDate);
-
- return PBSetCatalogInfoSync (&info) == noErr;
- }
- }
-
- return false;
- }
-
- bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw()
- {
- const char* const fileNameUTF8 = fileName.toUTF8();
-
- struct stat info;
- const int res = stat (fileNameUTF8, &info);
-
- bool ok = false;
-
- if (res == 0)
- {
- info.st_mode &= 0777; // Just permissions
-
- if (isReadOnly)
- info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
- else
- // Give everybody write permission?
- info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
-
- ok = chmod (fileNameUTF8, info.st_mode) == 0;
- }
-
- return ok;
- }
-
- bool juce_copyFile (const String& src, const String& dst) throw()
- {
- const File destFile (dst);
-
- if (! destFile.create())
- return false;
-
- FSRef srcRef, dstRef;
-
- if (! (PlatformUtilities::makeFSRefFromPath (&srcRef, src)
- && PlatformUtilities::makeFSRefFromPath (&dstRef, dst)))
- {
- return false;
- }
-
- int okForks = 0;
-
- CatPositionRec iter;
- iter.initialize = 0;
- HFSUniStr255 forkName;
-
- // can't just copy the data because this is a bloody Mac, so we need to copy each
- // fork separately...
- while (FSIterateForks (&srcRef, &iter, &forkName, 0, 0) == noErr)
- {
- SInt16 srcForkNum = 0, dstForkNum = 0;
- OSErr err = FSOpenFork (&srcRef, forkName.length, forkName.unicode, fsRdPerm, &srcForkNum);
-
- if (err == noErr)
- {
- err = FSOpenFork (&dstRef, forkName.length, forkName.unicode, fsRdWrPerm, &dstForkNum);
-
- if (err == noErr)
- {
- MemoryBlock buf (32768);
- SInt64 pos = 0;
-
- for (;;)
- {
- ByteCount bytesRead = 0;
- err = FSReadFork (srcForkNum, fsFromStart, pos, buf.getSize(), (char*) buf, &bytesRead);
-
- if (bytesRead > 0)
- {
- err = FSWriteFork (dstForkNum, fsFromStart, pos, bytesRead, (const char*) buf, &bytesRead);
- pos += bytesRead;
- }
-
- if (err != noErr)
- {
- if (err == eofErr)
- ++okForks;
-
- break;
- }
- }
-
- FSFlushFork (dstForkNum);
- FSCloseFork (dstForkNum);
- }
-
- FSCloseFork (srcForkNum);
- }
- }
-
- if (okForks > 0) // some files seem to be ok even if not all their forks get copied..
- {
- // copy permissions..
- struct stat info;
- if (juce_stat (src, info))
- chmod (dst.toUTF8(), info.st_mode & 0777);
-
- return true;
- }
-
- return false;
- }
-
- const StringArray juce_getFileSystemRoots() throw()
- {
- StringArray s;
- s.add (T("/"));
- return s;
- }
-
- //==============================================================================
- static bool isFileOnDriveType (const File* const f, const char** types) throw()
- {
- struct statfs buf;
-
- if (doStatFS (f, buf))
- {
- const String type (buf.f_fstypename);
-
- while (*types != 0)
- if (type.equalsIgnoreCase (*types++))
- return true;
- }
-
- return false;
- }
-
- bool File::isOnCDRomDrive() const throw()
- {
- static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
-
- return isFileOnDriveType (this, (const char**) cdTypes);
- }
-
- bool File::isOnHardDisk() const throw()
- {
- static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
-
- return ! (isOnCDRomDrive() || isFileOnDriveType (this, (const char**) nonHDTypes));
- }
-
- static bool juce_isHiddenFile (const String& path) throw()
- {
- FSRef ref;
- if (! PlatformUtilities::makeFSRefFromPath (&ref, path))
- return false;
-
- FSCatalogInfo info;
- FSGetCatalogInfo (&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &info, 0, 0, 0);
-
- if ((info.nodeFlags & kFSNodeIsDirectoryBit) != 0)
- return (((FolderInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
-
- return (((FileInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
- }
-
- bool File::isHidden() const throw()
- {
- return juce_isHiddenFile (getFullPathName());
- }
-
- //==============================================================================
- const File File::getSpecialLocation (const SpecialLocationType type)
- {
- const char* resultPath = 0;
-
- switch (type)
- {
- case userHomeDirectory:
- resultPath = getenv ("HOME");
-
- if (resultPath == 0)
- {
- struct passwd* const pw = getpwuid (getuid());
- if (pw != 0)
- resultPath = pw->pw_dir;
- }
-
- break;
-
- case userDocumentsDirectory:
- resultPath = "~/Documents";
- break;
-
- case userDesktopDirectory:
- resultPath = "~/Desktop";
- break;
-
- case userApplicationDataDirectory:
- resultPath = "~/Library";
- break;
-
- case commonApplicationDataDirectory:
- resultPath = "/Library";
- break;
-
- case globalApplicationsDirectory:
- resultPath = "/Applications";
- break;
-
- case userMusicDirectory:
- resultPath = "~/Music";
- break;
-
- case userMoviesDirectory:
- resultPath = "~/Movies";
- break;
-
- case tempDirectory:
- {
- File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
-
- tmp.createDirectory();
- return tmp.getFullPathName();
- }
-
- case currentExecutableFile:
- return executableFile;
-
- case currentApplicationFile:
- {
- const File parent (executableFile.getParentDirectory());
-
- return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
- ? parent.getParentDirectory().getParentDirectory()
- : executableFile;
- }
-
- default:
- jassertfalse // unknown type?
- break;
- }
-
- if (resultPath != 0)
- return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
-
- return File::nonexistent;
- }
-
- void juce_setCurrentExecutableFileName (const String& filename) throw()
- {
- executableFile = File::getCurrentWorkingDirectory()
- .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
- }
-
- void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
- {
- CFStringRef bundleIdStringRef = PlatformUtilities::juceStringToCFString (bundleId);
- CFBundleRef bundleRef = CFBundleGetBundleWithIdentifier (bundleIdStringRef);
- CFRelease (bundleIdStringRef);
-
- if (bundleRef != 0)
- {
- CFURLRef exeURLRef = CFBundleCopyExecutableURL (bundleRef);
-
- if (exeURLRef != 0)
- {
- CFStringRef pathStringRef = CFURLCopyFileSystemPath (exeURLRef, kCFURLPOSIXPathStyle);
- CFRelease (exeURLRef);
-
- if (pathStringRef != 0)
- {
- juce_setCurrentExecutableFileName (PlatformUtilities::cfStringToJuceString (pathStringRef));
- CFRelease (pathStringRef);
- }
- }
- }
- }
-
- //==============================================================================
- const File File::getCurrentWorkingDirectory() throw()
- {
- char buf [2048];
- getcwd (buf, sizeof(buf));
-
- return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
- }
-
- bool File::setAsCurrentWorkingDirectory() const throw()
- {
- return chdir (getFullPathName().toUTF8()) == 0;
- }
-
- //==============================================================================
- struct FindFileStruct
- {
- String parentDir, wildCard;
- DIR* dir;
-
- bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
- Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
- {
- const char* const wildCardUTF8 = wildCard.toUTF8();
-
- for (;;)
- {
- struct dirent* const de = readdir (dir);
-
- if (de == 0)
- break;
-
- if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
- {
- result = PlatformUtilities::convertToPrecomposedUnicode (String::fromUTF8 ((const uint8*) de->d_name));
-
- const String path (parentDir + result);
-
- if (isDir != 0 || fileSize != 0)
- {
- struct stat info;
- const bool statOk = juce_stat (path, info);
-
- if (isDir != 0)
- *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
-
- if (isHidden != 0)
- *isHidden = (de->d_name[0] == '.')
- || juce_isHiddenFile (path);
-
- if (fileSize != 0)
- *fileSize = statOk ? info.st_size : 0;
- }
-
- if (modTime != 0 || creationTime != 0)
- {
- int64 m, a, c;
- juce_getFileTimes (path, m, a, c);
-
- if (modTime != 0)
- *modTime = m;
-
- if (creationTime != 0)
- *creationTime = c;
- }
-
- if (isReadOnly != 0)
- *isReadOnly = ! juce_canWriteToFile (path);
-
- return true;
- }
- }
-
- return false;
- }
- };
-
- // returns 0 on failure
- void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
- bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
- Time* creationTime, bool* isReadOnly) throw()
- {
- DIR* const d = opendir (directory.toUTF8());
-
- if (d != 0)
- {
- FindFileStruct* const ff = new FindFileStruct();
- ff->parentDir = directory;
-
- if (!ff->parentDir.endsWithChar (File::separator))
- ff->parentDir += File::separator;
-
- ff->wildCard = wildCard;
- ff->dir = d;
-
- if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
- {
- return ff;
- }
- else
- {
- firstResultFile = String::empty;
- isDir = false;
- closedir (d);
- delete ff;
- }
- }
-
- return 0;
- }
-
- bool juce_findFileNext (void* handle, String& resultFile,
- bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
- {
- FindFileStruct* const ff = (FindFileStruct*) handle;
-
- if (ff != 0)
- return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
-
- return false;
- }
-
- void juce_findFileClose (void* handle) throw()
- {
- FindFileStruct* const ff = (FindFileStruct*)handle;
-
- if (ff != 0)
- {
- closedir (ff->dir);
- delete ff;
- }
- }
-
- //==============================================================================
- bool juce_launchExecutable (const String& pathAndArguments) throw()
- {
- char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
-
- const int cpid = fork();
-
- if (cpid == 0)
- {
- // Child process
- if (execve (argv[0], argv, 0) < 0)
- exit (0);
- }
- else
- {
- if (cpid < 0)
- return false;
- }
-
- return true;
- }
-
- bool juce_launchFile (const String& fileName,
- const String& parameters) throw()
- {
- bool ok = false;
-
- if (fileName.startsWithIgnoreCase (T("http:"))
- || fileName.startsWithIgnoreCase (T("https:"))
- || fileName.startsWithIgnoreCase (T("ftp:"))
- || fileName.startsWithIgnoreCase (T("file:")))
- {
- CFStringRef urlString = PlatformUtilities::juceStringToCFString (fileName);
-
- if (urlString != 0)
- {
- CFURLRef url = CFURLCreateWithString (kCFAllocatorDefault,
- urlString, 0);
- CFRelease (urlString);
-
- if (url != 0)
- {
- ok = (LSOpenCFURLRef (url, 0) == noErr);
- CFRelease (url);
- }
- }
- }
- else
- {
- FSRef ref;
- if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
- {
- if (juce_isDirectory (fileName) && parameters.isNotEmpty())
- {
- // if we're launching a bundled app with a document..
- StringArray docs;
- docs.addTokens (parameters, true);
- FSRef* docRefs = new FSRef [docs.size()];
-
- for (int i = 0; i < docs.size(); ++i)
- PlatformUtilities::makeFSRefFromPath (docRefs + i, docs[i]);
-
- LSLaunchFSRefSpec ors;
- ors.appRef = &ref;
- ors.numDocs = docs.size();
- ors.itemRefs = docRefs;
- ors.passThruParams = 0;
- ors.launchFlags = kLSLaunchDefaults;
- ors.asyncRefCon = 0;
-
- FSRef actual;
- ok = (LSOpenFromRefSpec (&ors, &actual) == noErr);
-
- delete docRefs;
- }
- else
- {
- if (parameters.isNotEmpty())
- ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
- else
- ok = (LSOpenFSRef (&ref, 0) == noErr);
- }
- }
- }
-
- return ok;
- }
-
- //==============================================================================
- bool PlatformUtilities::makeFSSpecFromPath (FSSpec* fs, const String& path)
- {
- FSRef ref;
-
- return makeFSRefFromPath (&ref, path)
- && FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, fs, 0) == noErr;
- }
-
- bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
- {
- return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
- }
-
- const String PlatformUtilities::makePathFromFSRef (FSRef* file)
- {
- uint8 path [2048];
- zeromem (path, sizeof (path));
-
- String result;
-
- if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
- result = String::fromUTF8 (path);
-
- return PlatformUtilities::convertToPrecomposedUnicode (result);
- }
-
- //==============================================================================
- OSType PlatformUtilities::getTypeOfFile (const String& filename)
- {
- FSRef fs;
- if (makeFSRefFromPath (&fs, filename))
- {
- LSItemInfoRecord info;
-
- if (LSCopyItemInfoForRef (&fs, kLSRequestTypeCreator, &info) == noErr)
- return info.filetype;
- }
-
- return 0;
- }
-
- bool PlatformUtilities::isBundle (const String& filename)
- {
- FSRef fs;
- if (makeFSRefFromPath (&fs, filename))
- {
- LSItemInfoRecord info;
-
- if (LSCopyItemInfoForRef (&fs, kLSItemInfoIsPackage, &info) == noErr)
- return (info.flags & kLSItemInfoIsPackage) != 0;
- }
-
- return false;
- }
-
-
- END_JUCE_NAMESPACE
|