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.

542 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 char* resultPath = 0;
  181. switch (type)
  182. {
  183. case userHomeDirectory:
  184. resultPath = nsStringToJuce (NSHomeDirectory());
  185. break;
  186. case userDocumentsDirectory:
  187. resultPath = "~/Documents";
  188. break;
  189. case userDesktopDirectory:
  190. resultPath = "~/Desktop";
  191. break;
  192. case userApplicationDataDirectory:
  193. resultPath = "~/Library";
  194. break;
  195. case commonApplicationDataDirectory:
  196. resultPath = "/Library";
  197. break;
  198. case globalApplicationsDirectory:
  199. resultPath = "/Applications";
  200. break;
  201. case userMusicDirectory:
  202. resultPath = "~/Music";
  203. break;
  204. case userMoviesDirectory:
  205. resultPath = "~/Movies";
  206. break;
  207. case tempDirectory:
  208. {
  209. File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension());
  210. tmp.createDirectory();
  211. return tmp.getFullPathName();
  212. }
  213. case currentExecutableFile:
  214. return executableFile;
  215. case currentApplicationFile:
  216. {
  217. const File parent (executableFile.getParentDirectory());
  218. return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS"))
  219. ? parent.getParentDirectory().getParentDirectory()
  220. : executableFile;
  221. }
  222. default:
  223. jassertfalse // unknown type?
  224. break;
  225. }
  226. if (resultPath != 0)
  227. return File (PlatformUtilities::convertToPrecomposedUnicode (resultPath));
  228. return File::nonexistent;
  229. }
  230. void juce_setCurrentExecutableFileName (const String& filename) throw()
  231. {
  232. executableFile = File::getCurrentWorkingDirectory()
  233. .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename));
  234. }
  235. void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw()
  236. {
  237. const ScopedAutoReleasePool pool;
  238. NSBundle* b = [NSBundle bundleWithIdentifier: juceStringToNS (bundleId)];
  239. if (b != nil)
  240. executableFile = nsStringToJuce ([b executablePath]);
  241. }
  242. //==============================================================================
  243. const File File::getCurrentWorkingDirectory() throw()
  244. {
  245. char buf [2048];
  246. getcwd (buf, sizeof(buf));
  247. return File (PlatformUtilities::convertToPrecomposedUnicode (buf));
  248. }
  249. bool File::setAsCurrentWorkingDirectory() const throw()
  250. {
  251. return chdir (getFullPathName().toUTF8()) == 0;
  252. }
  253. //==============================================================================
  254. struct FindFileStruct
  255. {
  256. String parentDir, wildCard;
  257. DIR* dir;
  258. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  259. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  260. {
  261. const char* const wildCardUTF8 = wildCard.toUTF8();
  262. for (;;)
  263. {
  264. struct dirent* const de = readdir (dir);
  265. if (de == 0)
  266. break;
  267. if (fnmatch (wildCardUTF8, de->d_name, 0) == 0)
  268. {
  269. result = String::fromUTF8 ((const uint8*) de->d_name);
  270. const String path (parentDir + result);
  271. if (isDir != 0 || fileSize != 0)
  272. {
  273. struct stat info;
  274. const bool statOk = juce_stat (path, info);
  275. if (isDir != 0)
  276. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  277. if (isHidden != 0)
  278. *isHidden = (de->d_name[0] == '.')
  279. || juce_isHiddenFile (path);
  280. if (fileSize != 0)
  281. *fileSize = statOk ? info.st_size : 0;
  282. }
  283. if (modTime != 0 || creationTime != 0)
  284. {
  285. int64 m, a, c;
  286. juce_getFileTimes (path, m, a, c);
  287. if (modTime != 0)
  288. *modTime = m;
  289. if (creationTime != 0)
  290. *creationTime = c;
  291. }
  292. if (isReadOnly != 0)
  293. *isReadOnly = ! juce_canWriteToFile (path);
  294. return true;
  295. }
  296. }
  297. return false;
  298. }
  299. };
  300. // returns 0 on failure
  301. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  302. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  303. Time* creationTime, bool* isReadOnly) throw()
  304. {
  305. DIR* const d = opendir (directory.toUTF8());
  306. if (d != 0)
  307. {
  308. FindFileStruct* const ff = new FindFileStruct();
  309. ff->parentDir = directory;
  310. if (!ff->parentDir.endsWithChar (File::separator))
  311. ff->parentDir += File::separator;
  312. ff->wildCard = wildCard;
  313. ff->dir = d;
  314. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  315. {
  316. return ff;
  317. }
  318. else
  319. {
  320. firstResultFile = String::empty;
  321. isDir = false;
  322. closedir (d);
  323. delete ff;
  324. }
  325. }
  326. return 0;
  327. }
  328. bool juce_findFileNext (void* handle, String& resultFile,
  329. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  330. {
  331. FindFileStruct* const ff = (FindFileStruct*) handle;
  332. if (ff != 0)
  333. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  334. return false;
  335. }
  336. void juce_findFileClose (void* handle) throw()
  337. {
  338. FindFileStruct* const ff = (FindFileStruct*)handle;
  339. if (ff != 0)
  340. {
  341. closedir (ff->dir);
  342. delete ff;
  343. }
  344. }
  345. //==============================================================================
  346. bool juce_launchExecutable (const String& pathAndArguments) throw()
  347. {
  348. char* const argv[4] = { "/bin/sh", "-c", (char*) (const char*) pathAndArguments, 0 };
  349. const int cpid = fork();
  350. if (cpid == 0)
  351. {
  352. // Child process
  353. if (execve (argv[0], argv, 0) < 0)
  354. exit (0);
  355. }
  356. else
  357. {
  358. if (cpid < 0)
  359. return false;
  360. }
  361. return true;
  362. }
  363. bool juce_launchFile (const String& fileName,
  364. const String& parameters) throw()
  365. {
  366. const ScopedAutoReleasePool pool;
  367. if (parameters.isEmpty())
  368. return [[NSWorkspace sharedWorkspace] openFile: juceStringToNS (fileName)];
  369. bool ok = false;
  370. FSRef ref;
  371. if (PlatformUtilities::makeFSRefFromPath (&ref, fileName))
  372. {
  373. if (PlatformUtilities::isBundle (fileName))
  374. {
  375. NSMutableArray* urls = [NSMutableArray array];
  376. StringArray docs;
  377. docs.addTokens (parameters, true);
  378. for (int i = 0; i < docs.size(); ++i)
  379. [urls addObject: juceStringToNS (docs[i])];
  380. ok = [[NSWorkspace sharedWorkspace] openURLs: urls
  381. withAppBundleIdentifier: [[NSBundle bundleWithPath: juceStringToNS (fileName)] bundleIdentifier]
  382. options: nil
  383. additionalEventParamDescriptor: nil
  384. launchIdentifiers: nil];
  385. }
  386. else
  387. {
  388. ok = juce_launchExecutable (T("\"") + fileName + T("\" ") + parameters);
  389. }
  390. }
  391. return ok;
  392. }
  393. //==============================================================================
  394. bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path)
  395. {
  396. return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr;
  397. }
  398. const String PlatformUtilities::makePathFromFSRef (FSRef* file)
  399. {
  400. uint8 path [2048];
  401. zeromem (path, sizeof (path));
  402. String result;
  403. if (FSRefMakePath (file, (UInt8*) path, sizeof (path) - 1) == noErr)
  404. result = String::fromUTF8 (path);
  405. return PlatformUtilities::convertToPrecomposedUnicode (result);
  406. }
  407. //==============================================================================
  408. OSType PlatformUtilities::getTypeOfFile (const String& filename)
  409. {
  410. const ScopedAutoReleasePool pool;
  411. return NSHFSTypeCodeFromFileType (NSHFSTypeOfFile (juceStringToNS (filename)));
  412. }
  413. bool PlatformUtilities::isBundle (const String& filename)
  414. {
  415. const ScopedAutoReleasePool pool;
  416. return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (filename)];
  417. }
  418. #endif