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.

602 lines
17KB

  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. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  24. // compiled on its own).
  25. #ifdef JUCE_INCLUDED_FILE
  26. /*
  27. Note that a lot of methods that you'd expect to find in this file actually
  28. live in juce_posix_SharedCode.h!
  29. */
  30. //==============================================================================
  31. static File executableFile;
  32. const unsigned int macTimeToUnixTimeDiff = 0x7c25be90;
  33. static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw()
  34. {
  35. if (d.highSeconds == 0 && d.lowSeconds == 0 && d.fraction == 0)
  36. return 0;
  37. return (((((uint64) d.highSeconds) << 32) | (uint64) d.lowSeconds) * 1000)
  38. + ((d.fraction * 1000) >> 16)
  39. - 2082844800000ll;
  40. }
  41. static void unixTimeToUtcDateTime (uint64 t, UTCDateTime& d) throw()
  42. {
  43. if (t != 0)
  44. t += 2082844800000ll;
  45. d.highSeconds = (t / 1000) >> 32;
  46. d.lowSeconds = (t / 1000) & (uint64) 0xffffffff;
  47. d.fraction = ((t % 1000) << 16) / 1000;
  48. }
  49. void juce_getFileTimes (const String& fileName,
  50. int64& modificationTime,
  51. int64& accessTime,
  52. int64& creationTime) throw()
  53. {
  54. modificationTime = 0;
  55. accessTime = 0;
  56. creationTime = 0;
  57. FSRef fileRef;
  58. if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
  59. {
  60. FSRefParam info;
  61. zerostruct (info);
  62. info.ref = &fileRef;
  63. info.whichInfo = kFSCatInfoAllDates;
  64. FSCatalogInfo catInfo;
  65. info.catInfo = &catInfo;
  66. if (PBGetCatalogInfoSync (&info) == noErr)
  67. {
  68. creationTime = utcDateTimeToUnixTime (catInfo.createDate);
  69. accessTime = utcDateTimeToUnixTime (catInfo.accessDate);
  70. modificationTime = utcDateTimeToUnixTime (catInfo.contentModDate);
  71. }
  72. }
  73. }
  74. bool juce_setFileTimes (const String& fileName,
  75. int64 modificationTime,
  76. int64 accessTime,
  77. int64 creationTime) throw()
  78. {
  79. FSRef fileRef;
  80. if (PlatformUtilities::makeFSRefFromPath (&fileRef, fileName))
  81. {
  82. FSRefParam info;
  83. zerostruct (info);
  84. info.ref = &fileRef;
  85. info.whichInfo = kFSCatInfoAllDates;
  86. FSCatalogInfo catInfo;
  87. info.catInfo = &catInfo;
  88. if (PBGetCatalogInfoSync (&info) == noErr)
  89. {
  90. if (creationTime != 0)
  91. unixTimeToUtcDateTime (creationTime, catInfo.createDate);
  92. if (modificationTime != 0)
  93. unixTimeToUtcDateTime (modificationTime, catInfo.contentModDate);
  94. if (accessTime != 0)
  95. unixTimeToUtcDateTime (accessTime, catInfo.accessDate);
  96. return PBSetCatalogInfoSync (&info) == noErr;
  97. }
  98. }
  99. return false;
  100. }
  101. bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw()
  102. {
  103. const char* const fileNameUTF8 = fileName.toUTF8();
  104. struct stat info;
  105. const int res = stat (fileNameUTF8, &info);
  106. bool ok = false;
  107. if (res == 0)
  108. {
  109. info.st_mode &= 0777; // Just permissions
  110. if (isReadOnly)
  111. info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
  112. else
  113. // Give everybody write permission?
  114. info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
  115. ok = chmod (fileNameUTF8, info.st_mode) == 0;
  116. }
  117. return ok;
  118. }
  119. bool juce_copyFile (const String& src, const String& dst) throw()
  120. {
  121. const ScopedAutoReleasePool pool;
  122. NSFileManager* fm = [NSFileManager defaultManager];
  123. return [fm fileExistsAtPath: juceStringToNS (src)]
  124. && [fm copyPath: juceStringToNS (src)
  125. toPath: juceStringToNS (dst)
  126. handler: nil];
  127. }
  128. const StringArray juce_getFileSystemRoots() throw()
  129. {
  130. StringArray s;
  131. s.add (T("/"));
  132. return s;
  133. }
  134. //==============================================================================
  135. static bool isFileOnDriveType (const File* const f, const char** types) throw()
  136. {
  137. struct statfs buf;
  138. if (doStatFS (f, buf))
  139. {
  140. const String type (buf.f_fstypename);
  141. while (*types != 0)
  142. if (type.equalsIgnoreCase (*types++))
  143. return true;
  144. }
  145. return false;
  146. }
  147. bool File::isOnCDRomDrive() const throw()
  148. {
  149. static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
  150. return isFileOnDriveType (this, (const char**) cdTypes);
  151. }
  152. bool File::isOnHardDisk() const throw()
  153. {
  154. static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
  155. return ! (isOnCDRomDrive() || isFileOnDriveType (this, (const char**) nonHDTypes));
  156. }
  157. bool File::isOnRemovableDrive() const throw()
  158. {
  159. jassertfalse // xxx not implemented for mac!
  160. return false;
  161. }
  162. static bool juce_isHiddenFile (const String& path) throw()
  163. {
  164. FSRef ref;
  165. if (! PlatformUtilities::makeFSRefFromPath (&ref, path))
  166. return false;
  167. FSCatalogInfo info;
  168. FSGetCatalogInfo (&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &info, 0, 0, 0);
  169. if ((info.nodeFlags & kFSNodeIsDirectoryBit) != 0)
  170. return (((FolderInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  171. return (((FileInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  172. }
  173. bool File::isHidden() const throw()
  174. {
  175. return juce_isHiddenFile (getFullPathName());
  176. }
  177. //==============================================================================
  178. const File File::getSpecialLocation (const SpecialLocationType type)
  179. {
  180. const ScopedAutoReleasePool pool;
  181. const char* resultPath = 0;
  182. switch (type)
  183. {
  184. case userHomeDirectory:
  185. resultPath = nsStringToJuce (NSHomeDirectory());
  186. break;
  187. case userDocumentsDirectory:
  188. resultPath = "~/Documents";
  189. break;
  190. case userDesktopDirectory:
  191. resultPath = "~/Desktop";
  192. break;
  193. case userApplicationDataDirectory:
  194. resultPath = "~/Library";
  195. break;
  196. case commonApplicationDataDirectory:
  197. resultPath = "/Library";
  198. break;
  199. case globalApplicationsDirectory:
  200. resultPath = "/Applications";
  201. break;
  202. case userMusicDirectory:
  203. resultPath = "~/Music";
  204. break;
  205. case userMoviesDirectory:
  206. resultPath = "~/Movies";
  207. break;
  208. case tempDirectory:
  209. {
  210. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  211. tmp.createDirectory();
  212. return tmp.getFullPathName();
  213. }
  214. case currentExecutableFile:
  215. return executableFile;
  216. case currentApplicationFile:
  217. {
  218. const File parent (executableFile.getParentDirectory());
  219. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  220. ? parent.getParentDirectory().getParentDirectory()
  221. : executableFile;
  222. }
  223. default:
  224. jassertfalse // unknown type?
  225. break;
  226. }
  227. if (resultPath != 0)
  228. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  229. return File::nonexistent;
  230. }
  231. void juce_setCurrentExecutableFileName (const String& filename) throw()
  232. {
  233. executableFile = File::getCurrentWorkingDirectory()
  234. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  235. }
  236. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  237. {
  238. const ScopedAutoReleasePool pool;
  239. NSBundle* b = [NSBundle bundleWithIdentifier: juceStringToNS (bundleId)];
  240. if (b != nil)
  241. executableFile = nsStringToJuce ([b executablePath]);
  242. }
  243. //==============================================================================
  244. const File File::getCurrentWorkingDirectory() throw()
  245. {
  246. char buf [2048];
  247. getcwd (buf, sizeof(buf));
  248. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  249. }
  250. bool File::setAsCurrentWorkingDirectory() const throw()
  251. {
  252. return chdir (getFullPathName().toUTF8()) == 0;
  253. }
  254. //==============================================================================
  255. const String File::getVersion() const throw()
  256. {
  257. const ScopedAutoReleasePool pool;
  258. String result;
  259. NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())];
  260. if (bundle != 0)
  261. {
  262. NSDictionary* info = [bundle infoDictionary];
  263. if (info != 0)
  264. {
  265. NSString* name = [info valueForKey: @"CFBundleShortVersionString"];
  266. if (name != nil)
  267. result = nsStringToJuce (name);
  268. }
  269. }
  270. return result;
  271. }
  272. //==============================================================================
  273. const File File::getLinkedTarget() const throw()
  274. {
  275. FSRef ref;
  276. Boolean targetIsAFolder, wasAliased;
  277. if (PlatformUtilities::makeFSRefFromPath (&ref, getFullPathName())
  278. && (FSResolveAliasFileWithMountFlags (&ref, true, &targetIsAFolder, &wasAliased, 0) == noErr)
  279. && wasAliased)
  280. {
  281. return File (PlatformUtilities::makePathFromFSRef (&ref));
  282. }
  283. return *this;
  284. }
  285. //==============================================================================
  286. bool File::moveToTrash() const throw()
  287. {
  288. if (! exists())
  289. return true;
  290. const ScopedAutoReleasePool pool;
  291. NSString* p = juceStringToNS (getFullPathName());
  292. return [[NSWorkspace sharedWorkspace]
  293. performFileOperation: NSWorkspaceRecycleOperation
  294. source: [p stringByDeletingLastPathComponent]
  295. destination: @""
  296. files: [NSArray arrayWithObject: [p lastPathComponent]]
  297. tag: nil ];
  298. }
  299. //==============================================================================
  300. struct FindFileStruct
  301. {
  302. String parentDir, wildCard;
  303. DIR* dir;
  304. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  305. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  306. {
  307. const char* const wildCardUTF8 = wildCard.toUTF8();
  308. for (;;)
  309. {
  310. struct dirent* const de = readdir (dir);
  311. if (de == 0)
  312. break;
  313. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  314. {
  315. result = String::fromUTF8 ((const uint8*) de->d_name);
  316. const String path (parentDir + result);
  317. if (isDir != 0 || fileSize != 0)
  318. {
  319. struct stat info;
  320. const bool statOk = juce_stat (path, info);
  321. if (isDir != 0)
  322. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  323. if (isHidden != 0)
  324. *isHidden = (de->d_name[0] == '.')
  325. || juce_isHiddenFile (path);
  326. if (fileSize != 0)
  327. *fileSize = statOk ? info.st_size : 0;
  328. }
  329. if (modTime != 0 || creationTime != 0)
  330. {
  331. int64 m, a, c;
  332. juce_getFileTimes (path, m, a, c);
  333. if (modTime != 0)
  334. *modTime = m;
  335. if (creationTime != 0)
  336. *creationTime = c;
  337. }
  338. if (isReadOnly != 0)
  339. *isReadOnly = ! juce_canWriteToFile (path);
  340. return true;
  341. }
  342. }
  343. return false;
  344. }
  345. };
  346. // returns 0 on failure
  347. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  348. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  349. Time* creationTime, bool* isReadOnly) throw()
  350. {
  351. DIR* const d = opendir (directory.toUTF8());
  352. if (d != 0)
  353. {
  354. FindFileStruct* const ff = new FindFileStruct();
  355. ff->parentDir = directory;
  356. if (!ff->parentDir.endsWithChar (File::separator))
  357. ff->parentDir += File::separator;
  358. ff->wildCard = wildCard;
  359. ff->dir = d;
  360. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  361. {
  362. return ff;
  363. }
  364. else
  365. {
  366. firstResultFile = String::empty;
  367. isDir = false;
  368. closedir (d);
  369. delete ff;
  370. }
  371. }
  372. return 0;
  373. }
  374. bool juce_findFileNext (void* handle, String& resultFile,
  375. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  376. {
  377. FindFileStruct* const ff = (FindFileStruct*) handle;
  378. if (ff != 0)
  379. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  380. return false;
  381. }
  382. void juce_findFileClose (void* handle) throw()
  383. {
  384. FindFileStruct* const ff = (FindFileStruct*)handle;
  385. if (ff != 0)
  386. {
  387. closedir (ff->dir);
  388. delete ff;
  389. }
  390. }
  391. //==============================================================================
  392. bool juce_launchExecutable (const String& pathAndArguments) throw()
  393. {
  394. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  395. const int cpid = fork();
  396. if (cpid == 0)
  397. {
  398. // Child process
  399. if (execve (argv[0], argv, 0) < 0)
  400. exit (0);
  401. }
  402. else
  403. {
  404. if (cpid < 0)
  405. return false;
  406. }
  407. return true;
  408. }
  409. bool juce_launchFile (const String& fileName,
  410. const String& parameters) throw()
  411. {
  412. const ScopedAutoReleasePool pool;
  413. if (parameters.isEmpty())
  414. return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)];
  415. bool ok = false;
  416. FSRef ref;
  417. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  418. {
  419. if (PlatformUtilities::isBundle (fileName))
  420. {
  421. NSMutableArray* urls = [NSMutableArray array];
  422. StringArray docs;
  423. docs.addTokens (parameters, true);
  424. for (int i = 0; i < docs.size(); ++i)
  425. [urls addObject: juceStringToNS (docs[i])];
  426. ok = [[NSWorkspace sharedWorkspace] openURLs: urls
  427. withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (fileName)] bundleIdentifier]
  428. options: nil
  429. additionalEventParamDescriptor: nil
  430. launchIdentifiers: nil];
  431. }
  432. else
  433. {
  434. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  435. }
  436. }
  437. return ok;
  438. }
  439. //==============================================================================
  440. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  441. {
  442. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  443. }
  444. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  445. {
  446. uint8 path [2048];
  447. zeromem (path, sizeof (path));
  448. String result;
  449. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  450. result = String::fromUTF8 (path);
  451. return PlatformUtilities::convertToPrecomposedUnicode (result);
  452. }
  453. //==============================================================================
  454. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  455. {
  456. const ScopedAutoReleasePool pool;
  457. return NSHFSTypeCodeFromFileType (NSHFSTypeOfFile (juceStringToNS (filename)));
  458. }
  459. bool PlatformUtilities::isBundle (const String& filename)
  460. {
  461. const ScopedAutoReleasePool pool;
  462. return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (filename)];
  463. }
  464. #endif