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.

996 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. const char* resultPath = 0;
  472. switch (type)
  473. {
  474. case userHomeDirectory:
  475. resultPath = getenv ("HOME");
  476. if (resultPath == 0)
  477. {
  478. struct passwd* const pw = getpwuid (getuid());
  479. if (pw != 0)
  480. resultPath = pw->pw_dir;
  481. }
  482. break;
  483. case userDocumentsDirectory:
  484. resultPath = "~/Documents";
  485. break;
  486. case userDesktopDirectory:
  487. resultPath = "~/Desktop";
  488. break;
  489. case userApplicationDataDirectory:
  490. resultPath = "~/Library";
  491. break;
  492. case commonApplicationDataDirectory:
  493. resultPath = "/Library";
  494. break;
  495. case globalApplicationsDirectory:
  496. resultPath = "/Applications";
  497. break;
  498. case userMusicDirectory:
  499. resultPath = "~/Music";
  500. break;
  501. case userMoviesDirectory:
  502. resultPath = "~/Movies";
  503. break;
  504. case tempDirectory:
  505. {
  506. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  507. tmp.createDirectory();
  508. return tmp.getFullPathName();
  509. }
  510. case currentExecutableFile:
  511. return executableFile;
  512. case currentApplicationFile:
  513. {
  514. const File parent (executableFile.getParentDirectory());
  515. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  516. ? parent.getParentDirectory().getParentDirectory()
  517. : executableFile;
  518. }
  519. default:
  520. jassertfalse // unknown type?
  521. break;
  522. }
  523. if (resultPath != 0)
  524. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  525. return File::nonexistent;
  526. }
  527. void juce_setCurrentExecutableFileName (const String& filename) throw()
  528. {
  529. executableFile = File::getCurrentWorkingDirectory()
  530. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  531. }
  532. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  533. {
  534. CFStringRef bundleIdStringRef = PlatformUtilities::juceStringToCFString (bundleId);
  535. CFBundleRef bundleRef = CFBundleGetBundleWithIdentifier (bundleIdStringRef);
  536. CFRelease (bundleIdStringRef);
  537. if (bundleRef != 0)
  538. {
  539. CFURLRef exeURLRef = CFBundleCopyExecutableURL (bundleRef);
  540. if (exeURLRef != 0)
  541. {
  542. CFStringRef pathStringRef = CFURLCopyFileSystemPath (exeURLRef, kCFURLPOSIXPathStyle);
  543. CFRelease (exeURLRef);
  544. if (pathStringRef != 0)
  545. {
  546. juce_setCurrentExecutableFileName (PlatformUtilities::cfStringToJuceString (pathStringRef));
  547. CFRelease (pathStringRef);
  548. }
  549. }
  550. }
  551. }
  552. //==============================================================================
  553. const File File::getCurrentWorkingDirectory() throw()
  554. {
  555. char buf [2048];
  556. getcwd (buf, sizeof(buf));
  557. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  558. }
  559. bool File::setAsCurrentWorkingDirectory() const throw()
  560. {
  561. return chdir (getFullPathName().toUTF8()) == 0;
  562. }
  563. //==============================================================================
  564. struct FindFileStruct
  565. {
  566. String parentDir, wildCard;
  567. DIR* dir;
  568. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  569. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  570. {
  571. const char* const wildCardUTF8 = wildCard.toUTF8();
  572. for (;;)
  573. {
  574. struct dirent* const de = readdir (dir);
  575. if (de == 0)
  576. break;
  577. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  578. {
  579. result = PlatformUtilities::convertToPrecomposedUnicode (String::fromUTF8 ((const uint8*) de->d_name));
  580. const String path (parentDir + result);
  581. if (isDir != 0 || fileSize != 0)
  582. {
  583. struct stat info;
  584. const bool statOk = juce_stat (path, info);
  585. if (isDir != 0)
  586. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  587. if (isHidden != 0)
  588. *isHidden = (de->d_name[0] == '.');
  589. if (fileSize != 0)
  590. *fileSize = statOk ? info.st_size : 0;
  591. }
  592. if (modTime != 0 || creationTime != 0)
  593. {
  594. int64 m, a, c;
  595. juce_getFileTimes (path, m, a, c);
  596. if (modTime != 0)
  597. *modTime = m;
  598. if (creationTime != 0)
  599. *creationTime = c;
  600. }
  601. if (isReadOnly != 0)
  602. *isReadOnly = ! juce_canWriteToFile (path);
  603. return true;
  604. }
  605. }
  606. return false;
  607. }
  608. };
  609. // returns 0 on failure
  610. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  611. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  612. {
  613. DIR* const d = opendir (directory.toUTF8());
  614. if (d != 0)
  615. {
  616. FindFileStruct* const ff = new FindFileStruct();
  617. ff->parentDir = directory;
  618. if (!ff->parentDir.endsWithChar (File::separator))
  619. ff->parentDir += File::separator;
  620. ff->wildCard = wildCard;
  621. ff->dir = d;
  622. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  623. {
  624. return ff;
  625. }
  626. else
  627. {
  628. firstResultFile = String::empty;
  629. isDir = false;
  630. closedir (d);
  631. delete ff;
  632. }
  633. }
  634. return 0;
  635. }
  636. bool juce_findFileNext (void* handle, String& resultFile,
  637. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  638. {
  639. FindFileStruct* const ff = (FindFileStruct*) handle;
  640. if (ff != 0)
  641. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  642. return false;
  643. }
  644. void juce_findFileClose (void* handle) throw()
  645. {
  646. FindFileStruct* const ff = (FindFileStruct*)handle;
  647. if (ff != 0)
  648. {
  649. closedir (ff->dir);
  650. delete ff;
  651. }
  652. }
  653. //==============================================================================
  654. bool juce_launchExecutable (const String& pathAndArguments) throw()
  655. {
  656. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  657. const int cpid = fork();
  658. if (cpid == 0)
  659. {
  660. // Child process
  661. if (execve (argv[0], argv, 0) < 0)
  662. exit (0);
  663. }
  664. else
  665. {
  666. if (cpid < 0)
  667. return false;
  668. }
  669. return true;
  670. }
  671. bool juce_launchFile (const String& fileName,
  672. const String& parameters) throw()
  673. {
  674. bool ok = false;
  675. if (fileName.startsWithIgnoreCase (T("http:"))
  676. || fileName.startsWithIgnoreCase (T("https:"))
  677. || fileName.startsWithIgnoreCase (T("ftp:")))
  678. {
  679. CFStringRef urlString = PlatformUtilities::juceStringToCFString (fileName);
  680. if (urlString != 0)
  681. {
  682. CFURLRef url = CFURLCreateWithString (kCFAllocatorDefault,
  683. urlString, 0);
  684. CFRelease (urlString);
  685. if (url != 0)
  686. {
  687. ok = (LSOpenCFURLRef (url, 0) == noErr);
  688. CFRelease (url);
  689. }
  690. }
  691. }
  692. else
  693. {
  694. FSRef ref;
  695. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  696. {
  697. if (juce_isDirectory (fileName) && parameters.isNotEmpty())
  698. {
  699. // if we're launching a bundled app with a document..
  700. StringArray docs;
  701. docs.addTokens (parameters, true);
  702. FSRef* docRefs = new FSRef [docs.size()];
  703. for (int i = 0; i < docs.size(); ++i)
  704. PlatformUtilities::makeFSRefFromPath (docRefs + i, docs[i]);
  705. LSLaunchFSRefSpec ors;
  706. ors.appRef = &ref;
  707. ors.numDocs = docs.size();
  708. ors.itemRefs = docRefs;
  709. ors.passThruParams = 0;
  710. ors.launchFlags = kLSLaunchDefaults;
  711. ors.asyncRefCon = 0;
  712. FSRef actual;
  713. ok = (LSOpenFromRefSpec (&ors, &actual) == noErr);
  714. delete docRefs;
  715. }
  716. else
  717. {
  718. if (parameters.isNotEmpty())
  719. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  720. else
  721. ok = (LSOpenFSRef (&ref, 0) == noErr);
  722. }
  723. }
  724. }
  725. return ok;
  726. }
  727. //==============================================================================
  728. bool PlatformUtilities::makeFSSpecFromPath (FSSpec* fs, const String& path)
  729. {
  730. FSRef ref;
  731. return makeFSRefFromPath (&ref, path)
  732. && FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, fs, 0) == noErr;
  733. }
  734. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  735. {
  736. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  737. }
  738. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  739. {
  740. uint8 path [2048];
  741. zeromem (path, sizeof (path));
  742. String result;
  743. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  744. result = String::fromUTF8 (path);
  745. return PlatformUtilities::convertToPrecomposedUnicode (result);
  746. }
  747. //==============================================================================
  748. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  749. {
  750. FSRef fs;
  751. if (makeFSRefFromPath (&fs, filename))
  752. {
  753. LSItemInfoRecord info;
  754. if (LSCopyItemInfoForRef (&fs, kLSRequestTypeCreator, &info) == noErr)
  755. return info.filetype;
  756. }
  757. return 0;
  758. }
  759. bool PlatformUtilities::isBundle (const String& filename)
  760. {
  761. FSRef fs;
  762. if (makeFSRefFromPath (&fs, filename))
  763. {
  764. LSItemInfoRecord info;
  765. if (LSCopyItemInfoForRef (&fs, kLSItemInfoIsPackage, &info) == noErr)
  766. return (info.flags & kLSItemInfoIsPackage) != 0;
  767. }
  768. return false;
  769. }
  770. END_JUCE_NAMESPACE