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.

980 lines
27KB

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