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.

835 lines
23KB

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