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.

578 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 File File::getLinkedTarget() const throw()
  256. {
  257. FSRef ref;
  258. Boolean targetIsAFolder, wasAliased;
  259. if (PlatformUtilities::makeFSRefFromPath (&ref, getFullPathName())
  260. && (FSResolveAliasFileWithMountFlags (&ref, true, &targetIsAFolder, &wasAliased, 0) == noErr)
  261. && wasAliased)
  262. {
  263. return File (PlatformUtilities::makePathFromFSRef (&ref));
  264. }
  265. return *this;
  266. }
  267. //==============================================================================
  268. bool File::moveToTrash() const throw()
  269. {
  270. if (! exists())
  271. return true;
  272. const ScopedAutoReleasePool pool;
  273. NSString* p = juceStringToNS (getFullPathName());
  274. return [[NSWorkspace sharedWorkspace]
  275. performFileOperation: NSWorkspaceRecycleOperation
  276. source: [p stringByDeletingLastPathComponent]
  277. destination: @""
  278. files: [NSArray arrayWithObject: [p lastPathComponent]]
  279. tag: nil ];
  280. }
  281. //==============================================================================
  282. struct FindFileStruct
  283. {
  284. String parentDir, wildCard;
  285. DIR* dir;
  286. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  287. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  288. {
  289. const char* const wildCardUTF8 = wildCard.toUTF8();
  290. for (;;)
  291. {
  292. struct dirent* const de = readdir (dir);
  293. if (de == 0)
  294. break;
  295. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  296. {
  297. result = String::fromUTF8 ((const uint8*) de->d_name);
  298. const String path (parentDir + result);
  299. if (isDir != 0 || fileSize != 0)
  300. {
  301. struct stat info;
  302. const bool statOk = juce_stat (path, info);
  303. if (isDir != 0)
  304. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  305. if (isHidden != 0)
  306. *isHidden = (de->d_name[0] == '.')
  307. || juce_isHiddenFile (path);
  308. if (fileSize != 0)
  309. *fileSize = statOk ? info.st_size : 0;
  310. }
  311. if (modTime != 0 || creationTime != 0)
  312. {
  313. int64 m, a, c;
  314. juce_getFileTimes (path, m, a, c);
  315. if (modTime != 0)
  316. *modTime = m;
  317. if (creationTime != 0)
  318. *creationTime = c;
  319. }
  320. if (isReadOnly != 0)
  321. *isReadOnly = ! juce_canWriteToFile (path);
  322. return true;
  323. }
  324. }
  325. return false;
  326. }
  327. };
  328. // returns 0 on failure
  329. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  330. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  331. Time* creationTime, bool* isReadOnly) throw()
  332. {
  333. DIR* const d = opendir (directory.toUTF8());
  334. if (d != 0)
  335. {
  336. FindFileStruct* const ff = new FindFileStruct();
  337. ff->parentDir = directory;
  338. if (!ff->parentDir.endsWithChar (File::separator))
  339. ff->parentDir += File::separator;
  340. ff->wildCard = wildCard;
  341. ff->dir = d;
  342. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  343. {
  344. return ff;
  345. }
  346. else
  347. {
  348. firstResultFile = String::empty;
  349. isDir = false;
  350. closedir (d);
  351. delete ff;
  352. }
  353. }
  354. return 0;
  355. }
  356. bool juce_findFileNext (void* handle, String& resultFile,
  357. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  358. {
  359. FindFileStruct* const ff = (FindFileStruct*) handle;
  360. if (ff != 0)
  361. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  362. return false;
  363. }
  364. void juce_findFileClose (void* handle) throw()
  365. {
  366. FindFileStruct* const ff = (FindFileStruct*)handle;
  367. if (ff != 0)
  368. {
  369. closedir (ff->dir);
  370. delete ff;
  371. }
  372. }
  373. //==============================================================================
  374. bool juce_launchExecutable (const String& pathAndArguments) throw()
  375. {
  376. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  377. const int cpid = fork();
  378. if (cpid == 0)
  379. {
  380. // Child process
  381. if (execve (argv[0], argv, 0) < 0)
  382. exit (0);
  383. }
  384. else
  385. {
  386. if (cpid < 0)
  387. return false;
  388. }
  389. return true;
  390. }
  391. bool juce_launchFile (const String& fileName,
  392. const String& parameters) throw()
  393. {
  394. const ScopedAutoReleasePool pool;
  395. if (parameters.isEmpty())
  396. return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)];
  397. bool ok = false;
  398. FSRef ref;
  399. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  400. {
  401. if (PlatformUtilities::isBundle (fileName))
  402. {
  403. NSMutableArray* urls = [NSMutableArray array];
  404. StringArray docs;
  405. docs.addTokens (parameters, true);
  406. for (int i = 0; i < docs.size(); ++i)
  407. [urls addObject: juceStringToNS (docs[i])];
  408. ok = [[NSWorkspace sharedWorkspace] openURLs: urls
  409. withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (fileName)] bundleIdentifier]
  410. options: nil
  411. additionalEventParamDescriptor: nil
  412. launchIdentifiers: nil];
  413. }
  414. else
  415. {
  416. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  417. }
  418. }
  419. return ok;
  420. }
  421. //==============================================================================
  422. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  423. {
  424. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  425. }
  426. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  427. {
  428. uint8 path [2048];
  429. zeromem (path, sizeof (path));
  430. String result;
  431. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  432. result = String::fromUTF8 (path);
  433. return PlatformUtilities::convertToPrecomposedUnicode (result);
  434. }
  435. //==============================================================================
  436. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  437. {
  438. const ScopedAutoReleasePool pool;
  439. return NSHFSTypeCodeFromFileType (NSHFSTypeOfFile (juceStringToNS (filename)));
  440. }
  441. bool PlatformUtilities::isBundle (const String& filename)
  442. {
  443. const ScopedAutoReleasePool pool;
  444. return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (filename)];
  445. }
  446. #endif