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.

612 lines
18KB

  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. const ScopedAutoReleasePool pool;
  160. BOOL removable = false;
  161. [[NSWorkspace sharedWorkspace]
  162. getFileSystemInfoForPath: juceStringToNS (getFullPathName())
  163. isRemovable: &removable
  164. isWritable: nil
  165. isUnmountable: nil
  166. description: nil
  167. type: nil];
  168. return removable;
  169. }
  170. static bool juce_isHiddenFile (const String& path) throw()
  171. {
  172. FSRef ref;
  173. if (! PlatformUtilities::makeFSRefFromPath (&ref, path))
  174. return false;
  175. FSCatalogInfo info;
  176. FSGetCatalogInfo (&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &info, 0, 0, 0);
  177. if ((info.nodeFlags & kFSNodeIsDirectoryBit) != 0)
  178. return (((FolderInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  179. return (((FileInfo*) &info.finderInfo)->finderFlags & kIsInvisible) != 0;
  180. }
  181. bool File::isHidden() const throw()
  182. {
  183. return juce_isHiddenFile (getFullPathName());
  184. }
  185. //==============================================================================
  186. const File File::getSpecialLocation (const SpecialLocationType type)
  187. {
  188. const ScopedAutoReleasePool pool;
  189. const char* resultPath = 0;
  190. switch (type)
  191. {
  192. case userHomeDirectory:
  193. resultPath = nsStringToJuce (NSHomeDirectory());
  194. break;
  195. case userDocumentsDirectory:
  196. resultPath = "~/Documents";
  197. break;
  198. case userDesktopDirectory:
  199. resultPath = "~/Desktop";
  200. break;
  201. case userApplicationDataDirectory:
  202. resultPath = "~/Library";
  203. break;
  204. case commonApplicationDataDirectory:
  205. resultPath = "/Library";
  206. break;
  207. case globalApplicationsDirectory:
  208. resultPath = "/Applications";
  209. break;
  210. case userMusicDirectory:
  211. resultPath = "~/Music";
  212. break;
  213. case userMoviesDirectory:
  214. resultPath = "~/Movies";
  215. break;
  216. case tempDirectory:
  217. {
  218. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  219. tmp.createDirectory();
  220. return tmp.getFullPathName();
  221. }
  222. case currentExecutableFile:
  223. return executableFile;
  224. case currentApplicationFile:
  225. {
  226. const File parent (executableFile.getParentDirectory());
  227. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  228. ? parent.getParentDirectory().getParentDirectory()
  229. : executableFile;
  230. }
  231. default:
  232. jassertfalse // unknown type?
  233. break;
  234. }
  235. if (resultPath != 0)
  236. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  237. return File::nonexistent;
  238. }
  239. void juce_setCurrentExecutableFileName (const String& filename) throw()
  240. {
  241. executableFile = File::getCurrentWorkingDirectory()
  242. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  243. }
  244. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  245. {
  246. const ScopedAutoReleasePool pool;
  247. NSBundle* b = [NSBundle bundleWithIdentifier: juceStringToNS (bundleId)];
  248. if (b != nil)
  249. executableFile = nsStringToJuce ([b executablePath]);
  250. }
  251. //==============================================================================
  252. const File File::getCurrentWorkingDirectory() throw()
  253. {
  254. char buf [2048];
  255. getcwd (buf, sizeof(buf));
  256. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  257. }
  258. bool File::setAsCurrentWorkingDirectory() const throw()
  259. {
  260. return chdir (getFullPathName().toUTF8()) == 0;
  261. }
  262. //==============================================================================
  263. const String File::getVersion() const throw()
  264. {
  265. const ScopedAutoReleasePool pool;
  266. String result;
  267. NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())];
  268. if (bundle != 0)
  269. {
  270. NSDictionary* info = [bundle infoDictionary];
  271. if (info != 0)
  272. {
  273. NSString* name = [info valueForKey: @"CFBundleShortVersionString"];
  274. if (name != nil)
  275. result = nsStringToJuce (name);
  276. }
  277. }
  278. return result;
  279. }
  280. //==============================================================================
  281. const File File::getLinkedTarget() const throw()
  282. {
  283. FSRef ref;
  284. Boolean targetIsAFolder, wasAliased;
  285. if (PlatformUtilities::makeFSRefFromPath (&ref, getFullPathName())
  286. && (FSResolveAliasFileWithMountFlags (&ref, true, &targetIsAFolder, &wasAliased, 0) == noErr)
  287. && wasAliased)
  288. {
  289. return File (PlatformUtilities::makePathFromFSRef (&ref));
  290. }
  291. return *this;
  292. }
  293. //==============================================================================
  294. bool File::moveToTrash() const throw()
  295. {
  296. if (! exists())
  297. return true;
  298. const ScopedAutoReleasePool pool;
  299. NSString* p = juceStringToNS (getFullPathName());
  300. return [[NSWorkspace sharedWorkspace]
  301. performFileOperation: NSWorkspaceRecycleOperation
  302. source: [p stringByDeletingLastPathComponent]
  303. destination: @""
  304. files: [NSArray arrayWithObject: [p lastPathComponent]]
  305. tag: nil ];
  306. }
  307. //==============================================================================
  308. struct FindFileStruct
  309. {
  310. String parentDir, wildCard;
  311. DIR* dir;
  312. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  313. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  314. {
  315. const char* const wildCardUTF8 = wildCard.toUTF8();
  316. for (;;)
  317. {
  318. struct dirent* const de = readdir (dir);
  319. if (de == 0)
  320. break;
  321. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  322. {
  323. result = String::fromUTF8 ((const uint8*) de->d_name);
  324. const String path (parentDir + result);
  325. if (isDir != 0 || fileSize != 0)
  326. {
  327. struct stat info;
  328. const bool statOk = juce_stat (path, info);
  329. if (isDir != 0)
  330. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  331. if (isHidden != 0)
  332. *isHidden = (de->d_name[0] == '.')
  333. || juce_isHiddenFile (path);
  334. if (fileSize != 0)
  335. *fileSize = statOk ? info.st_size : 0;
  336. }
  337. if (modTime != 0 || creationTime != 0)
  338. {
  339. int64 m, a, c;
  340. juce_getFileTimes (path, m, a, c);
  341. if (modTime != 0)
  342. *modTime = m;
  343. if (creationTime != 0)
  344. *creationTime = c;
  345. }
  346. if (isReadOnly != 0)
  347. *isReadOnly = ! juce_canWriteToFile (path);
  348. return true;
  349. }
  350. }
  351. return false;
  352. }
  353. };
  354. // returns 0 on failure
  355. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  356. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  357. Time* creationTime, bool* isReadOnly) throw()
  358. {
  359. DIR* const d = opendir (directory.toUTF8());
  360. if (d != 0)
  361. {
  362. FindFileStruct* const ff = new FindFileStruct();
  363. ff->parentDir = directory;
  364. if (!ff->parentDir.endsWithChar (File::separator))
  365. ff->parentDir += File::separator;
  366. ff->wildCard = wildCard;
  367. ff->dir = d;
  368. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  369. {
  370. return ff;
  371. }
  372. else
  373. {
  374. firstResultFile = String::empty;
  375. isDir = false;
  376. closedir (d);
  377. delete ff;
  378. }
  379. }
  380. return 0;
  381. }
  382. bool juce_findFileNext (void* handle, String& resultFile,
  383. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  384. {
  385. FindFileStruct* const ff = (FindFileStruct*) handle;
  386. if (ff != 0)
  387. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  388. return false;
  389. }
  390. void juce_findFileClose (void* handle) throw()
  391. {
  392. FindFileStruct* const ff = (FindFileStruct*)handle;
  393. if (ff != 0)
  394. {
  395. closedir (ff->dir);
  396. delete ff;
  397. }
  398. }
  399. //==============================================================================
  400. bool juce_launchExecutable (const String& pathAndArguments) throw()
  401. {
  402. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  403. const int cpid = fork();
  404. if (cpid == 0)
  405. {
  406. // Child process
  407. if (execve (argv[0], argv, 0) < 0)
  408. exit (0);
  409. }
  410. else
  411. {
  412. if (cpid < 0)
  413. return false;
  414. }
  415. return true;
  416. }
  417. bool juce_launchFile (const String& fileName,
  418. const String& parameters) throw()
  419. {
  420. const ScopedAutoReleasePool pool;
  421. if (parameters.isEmpty())
  422. return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)];
  423. bool ok = false;
  424. FSRef ref;
  425. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  426. {
  427. if (PlatformUtilities::isBundle (fileName))
  428. {
  429. NSMutableArray* urls = [NSMutableArray array];
  430. StringArray docs;
  431. docs.addTokens (parameters, true);
  432. for (int i = 0; i < docs.size(); ++i)
  433. [urls addObject: juceStringToNS (docs[i])];
  434. ok = [[NSWorkspace sharedWorkspace] openURLs: urls
  435. withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (fileName)] bundleIdentifier]
  436. options: nil
  437. additionalEventParamDescriptor: nil
  438. launchIdentifiers: nil];
  439. }
  440. else
  441. {
  442. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  443. }
  444. }
  445. return ok;
  446. }
  447. //==============================================================================
  448. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  449. {
  450. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  451. }
  452. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  453. {
  454. uint8 path [2048];
  455. zeromem (path, sizeof (path));
  456. String result;
  457. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  458. result = String::fromUTF8 (path);
  459. return PlatformUtilities::convertToPrecomposedUnicode (result);
  460. }
  461. //==============================================================================
  462. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  463. {
  464. const ScopedAutoReleasePool pool;
  465. return NSHFSTypeCodeFromFileType (NSHFSTypeOfFile (juceStringToNS (filename)));
  466. }
  467. bool PlatformUtilities::isBundle (const String& filename)
  468. {
  469. const ScopedAutoReleasePool pool;
  470. return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (filename)];
  471. }
  472. #endif