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.

592 lines
17KB

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