The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

842 lines
24KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  24. #include <ApplicationServices/ApplicationServices.h>
  25. #include <sys/stat.h>
  26. #include <sys/dir.h>
  27. #include <sys/param.h>
  28. #include <sys/mount.h>
  29. #include <unistd.h>
  30. #include <fnmatch.h>
  31. #include <utime.h>
  32. #include <pwd.h>
  33. #include <fcntl.h>
  34. BEGIN_JUCE_NAMESPACE
  35. #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
  36. #include "../../../src/juce_core/io/files/juce_FileOutputStream.h"
  37. #include "../../../src/juce_core/io/network/juce_URL.h"
  38. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  39. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  40. #include "../../../src/juce_core/io/files/juce_NamedPipe.h"
  41. #include "../../../src/juce_core/threads/juce_InterProcessLock.h"
  42. #include "../../../src/juce_core/threads/juce_Thread.h"
  43. //==============================================================================
  44. /*
  45. Note that a lot of methods that you'd expect to find in this file actually
  46. live in juce_posix_SharedCode.cpp!
  47. */
  48. #include "juce_posix_SharedCode.cpp"
  49. //==============================================================================
  50. static File executableFile;
  51. //==============================================================================
  52. void PlatformUtilities::copyToStr255 (Str255& d, const String& s)
  53. {
  54. unsigned char* t = (unsigned char*) d;
  55. t[0] = jmin (254, s.length());
  56. s.copyToBuffer ((char*) t + 1, 254);
  57. }
  58. void PlatformUtilities::copyToStr63 (Str63& d, const String& s)
  59. {
  60. unsigned char* t = (unsigned char*) d;
  61. t[0] = jmin (62, s.length());
  62. s.copyToBuffer ((char*) t + 1, 62);
  63. }
  64. const String PlatformUtilities::cfStringToJuceString (CFStringRef cfString)
  65. {
  66. String result;
  67. if (cfString != 0)
  68. {
  69. #if JUCE_STRINGS_ARE_UNICODE
  70. CFRange range = { 0, CFStringGetLength (cfString) };
  71. UniChar* const u = (UniChar*) juce_malloc (sizeof (UniChar) * (range.length + 1));
  72. CFStringGetCharacters (cfString, range, u);
  73. u[range.length] = 0;
  74. result = convertUTF16ToString (u);
  75. juce_free (u);
  76. #else
  77. const int len = CFStringGetLength (cfString);
  78. char* buffer = (char*) juce_malloc (len + 1);
  79. CFStringGetCString (cfString, buffer, len + 1, CFStringGetSystemEncoding());
  80. result = buffer;
  81. juce_free (buffer);
  82. #endif
  83. }
  84. return result;
  85. }
  86. CFStringRef PlatformUtilities::juceStringToCFString (const String& s)
  87. {
  88. #if JUCE_STRINGS_ARE_UNICODE
  89. const int len = s.length();
  90. const juce_wchar* t = (const juce_wchar*) s;
  91. UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4);
  92. for (int i = 0; i <= len; ++i)
  93. temp[i] = t[i];
  94. CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len);
  95. juce_free (temp);
  96. return result;
  97. #else
  98. return CFStringCreateWithCString (kCFAllocatorDefault,
  99. (const char*) s,
  100. CFStringGetSystemEncoding());
  101. #endif
  102. }
  103. const String PlatformUtilities::convertUTF16ToString (const UniChar* utf16)
  104. {
  105. String s;
  106. while (*utf16 != 0)
  107. s += (juce_wchar) *utf16++;
  108. return s;
  109. }
  110. const String PlatformUtilities::convertToPrecomposedUnicode (const String& s)
  111. {
  112. UnicodeMapping map;
  113. map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
  114. kUnicodeNoSubset,
  115. kTextEncodingDefaultFormat);
  116. map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
  117. kUnicodeCanonicalCompVariant,
  118. kTextEncodingDefaultFormat);
  119. map.mappingVersion = kUnicodeUseLatestMapping;
  120. UnicodeToTextInfo conversionInfo = 0;
  121. String result;
  122. if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
  123. {
  124. const int len = s.length();
  125. UniChar* const tempIn = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4);
  126. UniChar* const tempOut = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4);
  127. for (int i = 0; i <= len; ++i)
  128. tempIn[i] = s[i];
  129. ByteCount bytesRead = 0;
  130. ByteCount outputBufferSize = 0;
  131. if (ConvertFromUnicodeToText (conversionInfo,
  132. len * sizeof (UniChar), tempIn,
  133. kUnicodeDefaultDirectionMask,
  134. 0, 0, 0, 0,
  135. len * sizeof (UniChar), &bytesRead,
  136. &outputBufferSize, tempOut) == noErr)
  137. {
  138. result.preallocateStorage (bytesRead / sizeof (UniChar) + 2);
  139. tchar* t = const_cast <tchar*> ((const tchar*) result);
  140. int i;
  141. for (i = 0; i < bytesRead / sizeof (UniChar); ++i)
  142. t[i] = (tchar) tempOut[i];
  143. t[i] = 0;
  144. }
  145. juce_free (tempIn);
  146. juce_free (tempOut);
  147. DisposeUnicodeToTextInfo (&conversionInfo);
  148. }
  149. return result;
  150. }
  151. //==============================================================================
  152. const unsigned int macTimeToUnixTimeDiff = 0x7c25be90;
  153. static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw()
  154. {
  155. if (d.highSeconds == 0 && d.lowSeconds == 0 && d.fraction == 0)
  156. return 0;
  157. return (((((uint64) d.highSeconds) << 32) | (uint64) d.lowSeconds) * 1000)
  158. + ((d.fraction * 1000) >> 16)
  159. - 2082844800000ll;
  160. }
  161. static void unixTimeToUtcDateTime (uint64 t, UTCDateTime& d) throw()
  162. {
  163. if (t != 0)
  164. t += 2082844800000ll;
  165. d.highSeconds = (t / 1000) >> 32;
  166. d.lowSeconds = (t / 1000) & (uint64) 0xffffffff;
  167. d.fraction = ((t % 1000) << 16) / 1000;
  168. }
  169. void juce_getFileTimes (const String& fileName,
  170. int64& modificationTime,
  171. int64& accessTime,
  172. int64& creationTime) throw()
  173. {
  174. modificationTime = 0;
  175. accessTime = 0;
  176. creationTime = 0;
  177. FSRef fileRef;
  178. if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
  179. {
  180. FSRefParam info;
  181. zerostruct (info);
  182. info.ref = &fileRef;
  183. info.whichInfo = kFSCatInfoAllDates;
  184. FSCatalogInfo catInfo;
  185. info.catInfo = &catInfo;
  186. if (PBGetCatalogInfoSync (&info) == noErr)
  187. {
  188. creationTime = utcDateTimeToUnixTime (catInfo.createDate);
  189. accessTime = utcDateTimeToUnixTime (catInfo.accessDate);
  190. modificationTime = utcDateTimeToUnixTime (catInfo.contentModDate);
  191. }
  192. }
  193. }
  194. bool juce_setFileTimes (const String& fileName,
  195. int64 modificationTime,
  196. int64 accessTime,
  197. int64 creationTime) throw()
  198. {
  199. FSRef fileRef;
  200. if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
  201. {
  202. FSRefParam info;
  203. zerostruct (info);
  204. info.ref = &fileRef;
  205. info.whichInfo = kFSCatInfoAllDates;
  206. FSCatalogInfo catInfo;
  207. info.catInfo = &catInfo;
  208. if (PBGetCatalogInfoSync (&info) == noErr)
  209. {
  210. if (creationTime != 0)
  211. unixTimeToUtcDateTime (creationTime, catInfo.createDate);
  212. if (modificationTime != 0)
  213. unixTimeToUtcDateTime (modificationTime, catInfo.contentModDate);
  214. if (accessTime != 0)
  215. unixTimeToUtcDateTime (accessTime, catInfo.accessDate);
  216. return PBSetCatalogInfoSync (&info) == noErr;
  217. }
  218. }
  219. return false;
  220. }
  221. bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw()
  222. {
  223. const char* const fileNameUTF8 = fileName.toUTF8();
  224. struct stat info;
  225. const int res = stat (fileNameUTF8, &info);
  226. bool ok = false;
  227. if (res == 0)
  228. {
  229. info.st_mode &= 0777; // Just permissions
  230. if (isReadOnly)
  231. info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
  232. else
  233. // Give everybody write permission?
  234. info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
  235. ok = chmod (fileNameUTF8, info.st_mode) == 0;
  236. }
  237. return ok;
  238. }
  239. bool juce_copyFile (const String& src, const String& dst) throw()
  240. {
  241. const File destFile (dst);
  242. if (! destFile.create())
  243. return false;
  244. FSRef srcRef, dstRef;
  245. if (! (PlatformUtilities::makeFSRefFromPath (&srcRef, src)
  246. && PlatformUtilities::makeFSRefFromPath (&dstRef, dst)))
  247. {
  248. return false;
  249. }
  250. int okForks = 0;
  251. CatPositionRec iter;
  252. iter.initialize = 0;
  253. HFSUniStr255 forkName;
  254. // can't just copy the data because this is a bloody Mac, so we need to copy each
  255. // fork separately...
  256. while (FSIterateForks (&srcRef, &iter, &forkName, 0, 0) == noErr)
  257. {
  258. SInt16 srcForkNum = 0, dstForkNum = 0;
  259. OSErr err = FSOpenFork (&srcRef, forkName.length, forkName.unicode, fsRdPerm, &srcForkNum);
  260. if (err == noErr)
  261. {
  262. err = FSOpenFork (&dstRef, forkName.length, forkName.unicode, fsRdWrPerm, &dstForkNum);
  263. if (err == noErr)
  264. {
  265. MemoryBlock buf (32768);
  266. SInt64 pos = 0;
  267. for (;;)
  268. {
  269. ByteCount bytesRead = 0;
  270. err = FSReadFork (srcForkNum, fsFromStart, pos, buf.getSize(), (char*) buf, &bytesRead);
  271. if (bytesRead > 0)
  272. {
  273. err = FSWriteFork (dstForkNum, fsFromStart, pos, bytesRead, (const char*) buf, &bytesRead);
  274. pos += bytesRead;
  275. }
  276. if (err != noErr)
  277. {
  278. if (err == eofErr)
  279. ++okForks;
  280. break;
  281. }
  282. }
  283. FSFlushFork (dstForkNum);
  284. FSCloseFork (dstForkNum);
  285. }
  286. FSCloseFork (srcForkNum);
  287. }
  288. }
  289. if (okForks > 0) // some files seem to be ok even if not all their forks get copied..
  290. {
  291. // copy permissions..
  292. struct stat info;
  293. if (juce_stat (src, info))
  294. chmod (dst.toUTF8(), info.st_mode & 0777);
  295. return true;
  296. }
  297. return false;
  298. }
  299. const StringArray juce_getFileSystemRoots() throw()
  300. {
  301. StringArray s;
  302. s.add (T("/"));
  303. return s;
  304. }
  305. //==============================================================================
  306. static bool isFileOnDriveType (const File* const f, const char** types) throw()
  307. {
  308. struct statfs buf;
  309. if (doStatFS (f, buf))
  310. {
  311. const String type (buf.f_fstypename);
  312. while (*types != 0)
  313. if (type.equalsIgnoreCase (*types++))
  314. return true;
  315. }
  316. return false;
  317. }
  318. bool File::isOnCDRomDrive() const throw()
  319. {
  320. static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
  321. return isFileOnDriveType (this, (const char**) cdTypes);
  322. }
  323. bool File::isOnHardDisk() const throw()
  324. {
  325. static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
  326. return ! (isOnCDRomDrive() || isFileOnDriveType (this, (const char**) nonHDTypes));
  327. }
  328. bool File::isOnRemovableDrive() const throw()
  329. {
  330. jassertfalse // xxx not implemented for mac!
  331. return false;
  332. }
  333. static bool juce_isHiddenFile (const String& path) throw()
  334. {
  335. FSRef ref;
  336. if (! PlatformUtilities::makeFSRefFromPath (&ref, path))
  337. return false;
  338. FSCatalogInfo info;
  339. FSGetCatalogInfo (&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &info, 0, 0, 0);
  340. if ((info.nodeFlags & kFSNodeIsDirectoryBit) != 0)
  341. return (((FolderInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  342. return (((FileInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  343. }
  344. bool File::isHidden() const throw()
  345. {
  346. return juce_isHiddenFile (getFullPathName());
  347. }
  348. //==============================================================================
  349. const File File::getSpecialLocation (const SpecialLocationType type)
  350. {
  351. const char* resultPath = 0;
  352. switch (type)
  353. {
  354. case userHomeDirectory:
  355. resultPath = getenv ("HOME");
  356. if (resultPath == 0)
  357. {
  358. struct passwd* const pw = getpwuid (getuid());
  359. if (pw != 0)
  360. resultPath = pw->pw_dir;
  361. }
  362. break;
  363. case userDocumentsDirectory:
  364. resultPath = "~/Documents";
  365. break;
  366. case userDesktopDirectory:
  367. resultPath = "~/Desktop";
  368. break;
  369. case userApplicationDataDirectory:
  370. resultPath = "~/Library";
  371. break;
  372. case commonApplicationDataDirectory:
  373. resultPath = "/Library";
  374. break;
  375. case globalApplicationsDirectory:
  376. resultPath = "/Applications";
  377. break;
  378. case userMusicDirectory:
  379. resultPath = "~/Music";
  380. break;
  381. case userMoviesDirectory:
  382. resultPath = "~/Movies";
  383. break;
  384. case tempDirectory:
  385. {
  386. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  387. tmp.createDirectory();
  388. return tmp.getFullPathName();
  389. }
  390. case currentExecutableFile:
  391. return executableFile;
  392. case currentApplicationFile:
  393. {
  394. const File parent (executableFile.getParentDirectory());
  395. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  396. ? parent.getParentDirectory().getParentDirectory()
  397. : executableFile;
  398. }
  399. default:
  400. jassertfalse // unknown type?
  401. break;
  402. }
  403. if (resultPath != 0)
  404. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  405. return File::nonexistent;
  406. }
  407. void juce_setCurrentExecutableFileName (const String& filename) throw()
  408. {
  409. executableFile = File::getCurrentWorkingDirectory()
  410. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  411. }
  412. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  413. {
  414. CFStringRef bundleIdStringRef = PlatformUtilities::juceStringToCFString (bundleId);
  415. CFBundleRef bundleRef = CFBundleGetBundleWithIdentifier (bundleIdStringRef);
  416. CFRelease (bundleIdStringRef);
  417. if (bundleRef != 0)
  418. {
  419. CFURLRef exeURLRef = CFBundleCopyExecutableURL (bundleRef);
  420. if (exeURLRef != 0)
  421. {
  422. CFStringRef pathStringRef = CFURLCopyFileSystemPath (exeURLRef, kCFURLPOSIXPathStyle);
  423. CFRelease (exeURLRef);
  424. if (pathStringRef != 0)
  425. {
  426. juce_setCurrentExecutableFileName (PlatformUtilities::cfStringToJuceString (pathStringRef));
  427. CFRelease (pathStringRef);
  428. }
  429. }
  430. }
  431. }
  432. //==============================================================================
  433. const File File::getCurrentWorkingDirectory() throw()
  434. {
  435. char buf [2048];
  436. getcwd (buf, sizeof(buf));
  437. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  438. }
  439. bool File::setAsCurrentWorkingDirectory() const throw()
  440. {
  441. return chdir (getFullPathName().toUTF8()) == 0;
  442. }
  443. //==============================================================================
  444. struct FindFileStruct
  445. {
  446. String parentDir, wildCard;
  447. DIR* dir;
  448. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  449. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  450. {
  451. const char* const wildCardUTF8 = wildCard.toUTF8();
  452. for (;;)
  453. {
  454. struct dirent* const de = readdir (dir);
  455. if (de == 0)
  456. break;
  457. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  458. {
  459. result = PlatformUtilities::convertToPrecomposedUnicode (String::fromUTF8 ((const uint8*) de->d_name));
  460. const String path (parentDir + result);
  461. if (isDir != 0 || fileSize != 0)
  462. {
  463. struct stat info;
  464. const bool statOk = juce_stat (path, info);
  465. if (isDir != 0)
  466. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  467. if (isHidden != 0)
  468. *isHidden = (de->d_name[0] == '.')
  469. || juce_isHiddenFile (path);
  470. if (fileSize != 0)
  471. *fileSize = statOk ? info.st_size : 0;
  472. }
  473. if (modTime != 0 || creationTime != 0)
  474. {
  475. int64 m, a, c;
  476. juce_getFileTimes (path, m, a, c);
  477. if (modTime != 0)
  478. *modTime = m;
  479. if (creationTime != 0)
  480. *creationTime = c;
  481. }
  482. if (isReadOnly != 0)
  483. *isReadOnly = ! juce_canWriteToFile (path);
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. };
  490. // returns 0 on failure
  491. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  492. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  493. Time* creationTime, bool* isReadOnly) throw()
  494. {
  495. DIR* const d = opendir (directory.toUTF8());
  496. if (d != 0)
  497. {
  498. FindFileStruct* const ff = new FindFileStruct();
  499. ff->parentDir = directory;
  500. if (!ff->parentDir.endsWithChar (File::separator))
  501. ff->parentDir += File::separator;
  502. ff->wildCard = wildCard;
  503. ff->dir = d;
  504. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  505. {
  506. return ff;
  507. }
  508. else
  509. {
  510. firstResultFile = String::empty;
  511. isDir = false;
  512. closedir (d);
  513. delete ff;
  514. }
  515. }
  516. return 0;
  517. }
  518. bool juce_findFileNext (void* handle, String& resultFile,
  519. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  520. {
  521. FindFileStruct* const ff = (FindFileStruct*) handle;
  522. if (ff != 0)
  523. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  524. return false;
  525. }
  526. void juce_findFileClose (void* handle) throw()
  527. {
  528. FindFileStruct* const ff = (FindFileStruct*)handle;
  529. if (ff != 0)
  530. {
  531. closedir (ff->dir);
  532. delete ff;
  533. }
  534. }
  535. //==============================================================================
  536. bool juce_launchExecutable (const String& pathAndArguments) throw()
  537. {
  538. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  539. const int cpid = fork();
  540. if (cpid == 0)
  541. {
  542. // Child process
  543. if (execve (argv[0], argv, 0) < 0)
  544. exit (0);
  545. }
  546. else
  547. {
  548. if (cpid < 0)
  549. return false;
  550. }
  551. return true;
  552. }
  553. bool juce_launchFile (const String& fileName,
  554. const String& parameters) throw()
  555. {
  556. bool ok = false;
  557. if (fileName.startsWithIgnoreCase (T("http:"))
  558. || fileName.startsWithIgnoreCase (T("https:"))
  559. || fileName.startsWithIgnoreCase (T("ftp:"))
  560. || fileName.startsWithIgnoreCase (T("file:")))
  561. {
  562. CFStringRef urlString = PlatformUtilities::juceStringToCFString (fileName);
  563. if (urlString != 0)
  564. {
  565. CFURLRef url = CFURLCreateWithString (kCFAllocatorDefault,
  566. urlString, 0);
  567. CFRelease (urlString);
  568. if (url != 0)
  569. {
  570. ok = (LSOpenCFURLRef (url, 0) == noErr);
  571. CFRelease (url);
  572. }
  573. }
  574. }
  575. else
  576. {
  577. FSRef ref;
  578. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  579. {
  580. if (juce_isDirectory (fileName) && parameters.isNotEmpty())
  581. {
  582. // if we're launching a bundled app with a document..
  583. StringArray docs;
  584. docs.addTokens (parameters, true);
  585. FSRef* docRefs = new FSRef [docs.size()];
  586. for (int i = 0; i < docs.size(); ++i)
  587. PlatformUtilities::makeFSRefFromPath (docRefs + i, docs[i]);
  588. LSLaunchFSRefSpec ors;
  589. ors.appRef = &ref;
  590. ors.numDocs = docs.size();
  591. ors.itemRefs = docRefs;
  592. ors.passThruParams = 0;
  593. ors.launchFlags = kLSLaunchDefaults;
  594. ors.asyncRefCon = 0;
  595. FSRef actual;
  596. ok = (LSOpenFromRefSpec (&ors, &actual) == noErr);
  597. delete docRefs;
  598. }
  599. else
  600. {
  601. if (parameters.isNotEmpty())
  602. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  603. else
  604. ok = (LSOpenFSRef (&ref, 0) == noErr);
  605. }
  606. }
  607. }
  608. return ok;
  609. }
  610. //==============================================================================
  611. bool PlatformUtilities::makeFSSpecFromPath (FSSpec* fs, const String& path)
  612. {
  613. FSRef ref;
  614. return makeFSRefFromPath (&ref, path)
  615. && FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, fs, 0) == noErr;
  616. }
  617. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  618. {
  619. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  620. }
  621. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  622. {
  623. uint8 path [2048];
  624. zeromem (path, sizeof (path));
  625. String result;
  626. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  627. result = String::fromUTF8 (path);
  628. return PlatformUtilities::convertToPrecomposedUnicode (result);
  629. }
  630. //==============================================================================
  631. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  632. {
  633. FSRef fs;
  634. if (makeFSRefFromPath (&fs, filename))
  635. {
  636. LSItemInfoRecord info;
  637. if (LSCopyItemInfoForRef (&fs, kLSRequestTypeCreator, &info) == noErr)
  638. return info.filetype;
  639. }
  640. return 0;
  641. }
  642. bool PlatformUtilities::isBundle (const String& filename)
  643. {
  644. FSRef fs;
  645. if (makeFSRefFromPath (&fs, filename))
  646. {
  647. LSItemInfoRecord info;
  648. if (LSCopyItemInfoForRef (&fs, kLSItemInfoIsPackage, &info) == noErr)
  649. return (info.flags & kLSItemInfoIsPackage) != 0;
  650. }
  651. return false;
  652. }
  653. END_JUCE_NAMESPACE