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.

544 lines
16KB

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