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.

836 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 <sys/stat.h>
  25. #include <sys/dir.h>
  26. #include <sys/param.h>
  27. #include <sys/mount.h>
  28. #include <unistd.h>
  29. #include <fnmatch.h>
  30. #include <utime.h>
  31. #include <pwd.h>
  32. #include <fcntl.h>
  33. #include <Carbon/Carbon.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. static bool juce_isHiddenFile (const String& path) throw()
  329. {
  330. FSRef ref;
  331. if (! PlatformUtilities::makeFSRefFromPath (&ref, path))
  332. return false;
  333. FSCatalogInfo info;
  334. FSGetCatalogInfo (&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &info, 0, 0, 0);
  335. if ((info.nodeFlags & kFSNodeIsDirectoryBit) != 0)
  336. return (((FolderInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  337. return (((FileInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  338. }
  339. bool File::isHidden() const throw()
  340. {
  341. return juce_isHiddenFile (getFullPathName());
  342. }
  343. //==============================================================================
  344. const File File::getSpecialLocation (const SpecialLocationType type)
  345. {
  346. const char* resultPath = 0;
  347. switch (type)
  348. {
  349. case userHomeDirectory:
  350. resultPath = getenv ("HOME");
  351. if (resultPath == 0)
  352. {
  353. struct passwd* const pw = getpwuid (getuid());
  354. if (pw != 0)
  355. resultPath = pw->pw_dir;
  356. }
  357. break;
  358. case userDocumentsDirectory:
  359. resultPath = "~/Documents";
  360. break;
  361. case userDesktopDirectory:
  362. resultPath = "~/Desktop";
  363. break;
  364. case userApplicationDataDirectory:
  365. resultPath = "~/Library";
  366. break;
  367. case commonApplicationDataDirectory:
  368. resultPath = "/Library";
  369. break;
  370. case globalApplicationsDirectory:
  371. resultPath = "/Applications";
  372. break;
  373. case userMusicDirectory:
  374. resultPath = "~/Music";
  375. break;
  376. case userMoviesDirectory:
  377. resultPath = "~/Movies";
  378. break;
  379. case tempDirectory:
  380. {
  381. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  382. tmp.createDirectory();
  383. return tmp.getFullPathName();
  384. }
  385. case currentExecutableFile:
  386. return executableFile;
  387. case currentApplicationFile:
  388. {
  389. const File parent (executableFile.getParentDirectory());
  390. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  391. ? parent.getParentDirectory().getParentDirectory()
  392. : executableFile;
  393. }
  394. default:
  395. jassertfalse // unknown type?
  396. break;
  397. }
  398. if (resultPath != 0)
  399. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  400. return File::nonexistent;
  401. }
  402. void juce_setCurrentExecutableFileName (const String& filename) throw()
  403. {
  404. executableFile = File::getCurrentWorkingDirectory()
  405. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  406. }
  407. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  408. {
  409. CFStringRef bundleIdStringRef = PlatformUtilities::juceStringToCFString (bundleId);
  410. CFBundleRef bundleRef = CFBundleGetBundleWithIdentifier (bundleIdStringRef);
  411. CFRelease (bundleIdStringRef);
  412. if (bundleRef != 0)
  413. {
  414. CFURLRef exeURLRef = CFBundleCopyExecutableURL (bundleRef);
  415. if (exeURLRef != 0)
  416. {
  417. CFStringRef pathStringRef = CFURLCopyFileSystemPath (exeURLRef, kCFURLPOSIXPathStyle);
  418. CFRelease (exeURLRef);
  419. if (pathStringRef != 0)
  420. {
  421. juce_setCurrentExecutableFileName (PlatformUtilities::cfStringToJuceString (pathStringRef));
  422. CFRelease (pathStringRef);
  423. }
  424. }
  425. }
  426. }
  427. //==============================================================================
  428. const File File::getCurrentWorkingDirectory() throw()
  429. {
  430. char buf [2048];
  431. getcwd (buf, sizeof(buf));
  432. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  433. }
  434. bool File::setAsCurrentWorkingDirectory() const throw()
  435. {
  436. return chdir (getFullPathName().toUTF8()) == 0;
  437. }
  438. //==============================================================================
  439. struct FindFileStruct
  440. {
  441. String parentDir, wildCard;
  442. DIR* dir;
  443. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  444. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  445. {
  446. const char* const wildCardUTF8 = wildCard.toUTF8();
  447. for (;;)
  448. {
  449. struct dirent* const de = readdir (dir);
  450. if (de == 0)
  451. break;
  452. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  453. {
  454. result = PlatformUtilities::convertToPrecomposedUnicode (String::fromUTF8 ((const uint8*) de->d_name));
  455. const String path (parentDir + result);
  456. if (isDir != 0 || fileSize != 0)
  457. {
  458. struct stat info;
  459. const bool statOk = juce_stat (path, info);
  460. if (isDir != 0)
  461. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  462. if (isHidden != 0)
  463. *isHidden = (de->d_name[0] == '.')
  464. || juce_isHiddenFile (path);
  465. if (fileSize != 0)
  466. *fileSize = statOk ? info.st_size : 0;
  467. }
  468. if (modTime != 0 || creationTime != 0)
  469. {
  470. int64 m, a, c;
  471. juce_getFileTimes (path, m, a, c);
  472. if (modTime != 0)
  473. *modTime = m;
  474. if (creationTime != 0)
  475. *creationTime = c;
  476. }
  477. if (isReadOnly != 0)
  478. *isReadOnly = ! juce_canWriteToFile (path);
  479. return true;
  480. }
  481. }
  482. return false;
  483. }
  484. };
  485. // returns 0 on failure
  486. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  487. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  488. Time* creationTime, bool* isReadOnly) throw()
  489. {
  490. DIR* const d = opendir (directory.toUTF8());
  491. if (d != 0)
  492. {
  493. FindFileStruct* const ff = new FindFileStruct();
  494. ff->parentDir = directory;
  495. if (!ff->parentDir.endsWithChar (File::separator))
  496. ff->parentDir += File::separator;
  497. ff->wildCard = wildCard;
  498. ff->dir = d;
  499. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  500. {
  501. return ff;
  502. }
  503. else
  504. {
  505. firstResultFile = String::empty;
  506. isDir = false;
  507. closedir (d);
  508. delete ff;
  509. }
  510. }
  511. return 0;
  512. }
  513. bool juce_findFileNext (void* handle, String& resultFile,
  514. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  515. {
  516. FindFileStruct* const ff = (FindFileStruct*) handle;
  517. if (ff != 0)
  518. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  519. return false;
  520. }
  521. void juce_findFileClose (void* handle) throw()
  522. {
  523. FindFileStruct* const ff = (FindFileStruct*)handle;
  524. if (ff != 0)
  525. {
  526. closedir (ff->dir);
  527. delete ff;
  528. }
  529. }
  530. //==============================================================================
  531. bool juce_launchExecutable (const String& pathAndArguments) throw()
  532. {
  533. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  534. const int cpid = fork();
  535. if (cpid == 0)
  536. {
  537. // Child process
  538. if (execve (argv[0], argv, 0) < 0)
  539. exit (0);
  540. }
  541. else
  542. {
  543. if (cpid < 0)
  544. return false;
  545. }
  546. return true;
  547. }
  548. bool juce_launchFile (const String& fileName,
  549. const String& parameters) throw()
  550. {
  551. bool ok = false;
  552. if (fileName.startsWithIgnoreCase (T("http:"))
  553. || fileName.startsWithIgnoreCase (T("https:"))
  554. || fileName.startsWithIgnoreCase (T("ftp:"))
  555. || fileName.startsWithIgnoreCase (T("file:")))
  556. {
  557. CFStringRef urlString = PlatformUtilities::juceStringToCFString (fileName);
  558. if (urlString != 0)
  559. {
  560. CFURLRef url = CFURLCreateWithString (kCFAllocatorDefault,
  561. urlString, 0);
  562. CFRelease (urlString);
  563. if (url != 0)
  564. {
  565. ok = (LSOpenCFURLRef (url, 0) == noErr);
  566. CFRelease (url);
  567. }
  568. }
  569. }
  570. else
  571. {
  572. FSRef ref;
  573. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  574. {
  575. if (juce_isDirectory (fileName) && parameters.isNotEmpty())
  576. {
  577. // if we're launching a bundled app with a document..
  578. StringArray docs;
  579. docs.addTokens (parameters, true);
  580. FSRef* docRefs = new FSRef [docs.size()];
  581. for (int i = 0; i < docs.size(); ++i)
  582. PlatformUtilities::makeFSRefFromPath (docRefs + i, docs[i]);
  583. LSLaunchFSRefSpec ors;
  584. ors.appRef = &ref;
  585. ors.numDocs = docs.size();
  586. ors.itemRefs = docRefs;
  587. ors.passThruParams = 0;
  588. ors.launchFlags = kLSLaunchDefaults;
  589. ors.asyncRefCon = 0;
  590. FSRef actual;
  591. ok = (LSOpenFromRefSpec (&ors, &actual) == noErr);
  592. delete docRefs;
  593. }
  594. else
  595. {
  596. if (parameters.isNotEmpty())
  597. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  598. else
  599. ok = (LSOpenFSRef (&ref, 0) == noErr);
  600. }
  601. }
  602. }
  603. return ok;
  604. }
  605. //==============================================================================
  606. bool PlatformUtilities::makeFSSpecFromPath (FSSpec* fs, const String& path)
  607. {
  608. FSRef ref;
  609. return makeFSRefFromPath (&ref, path)
  610. && FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, fs, 0) == noErr;
  611. }
  612. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  613. {
  614. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  615. }
  616. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  617. {
  618. uint8 path [2048];
  619. zeromem (path, sizeof (path));
  620. String result;
  621. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  622. result = String::fromUTF8 (path);
  623. return PlatformUtilities::convertToPrecomposedUnicode (result);
  624. }
  625. //==============================================================================
  626. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  627. {
  628. FSRef fs;
  629. if (makeFSRefFromPath (&fs, filename))
  630. {
  631. LSItemInfoRecord info;
  632. if (LSCopyItemInfoForRef (&fs, kLSRequestTypeCreator, &info) == noErr)
  633. return info.filetype;
  634. }
  635. return 0;
  636. }
  637. bool PlatformUtilities::isBundle (const String& filename)
  638. {
  639. FSRef fs;
  640. if (makeFSRefFromPath (&fs, filename))
  641. {
  642. LSItemInfoRecord info;
  643. if (LSCopyItemInfoForRef (&fs, kLSItemInfoIsPackage, &info) == noErr)
  644. return (info.flags & kLSItemInfoIsPackage) != 0;
  645. }
  646. return false;
  647. }
  648. END_JUCE_NAMESPACE