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.

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