Vuo  2.2.1
VuoFileUtilitiesCocoa.mm
Go to the documentation of this file.
1 
10 #include "VuoFileUtilities.hh"
11 #include "VuoFileUtilitiesCocoa.hh"
12 #include "VuoException.hh"
13 #include "VuoStringUtilities.hh"
14 
15 #ifndef NS_RETURNS_INNER_POINTER
16 #define NS_RETURNS_INNER_POINTER
17 #endif
18 #include <Cocoa/Cocoa.h>
19 
26 {
27  NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filePath.c_str()]];
28  if (!url)
29  throw VuoException("Couldn't move file '" + filePath + "' to the trash: Couldn't create NSURL.");
30 
31  NSError *error = nil;
32  bool success = [[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:nil error:&error];
33  if (!success)
34  throw VuoException(string("Couldn't move file '" + filePath + "' to the trash: ") + [[error localizedDescription] UTF8String]);
35 }
36 
48 {
49  NSString *pathNS = [NSString stringWithUTF8String:path.c_str()];
50  if (!pathNS)
51  throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
52 
53  NSURL *baseURL = [NSURL fileURLWithPath:pathNS isDirectory:YES];
54  if (!baseURL)
55  throw VuoException("Path \"" + path + "\" isn't a valid directory.");
56 
57  NSURL *temporaryDirectoryURL = nil;
58  while (true)
59  {
60  NSError *error = nil;
61  temporaryDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSItemReplacementDirectory
62  inDomain:NSUserDomainMask
63  appropriateForURL:baseURL
64  create:YES
65  error:&error];
66  if (error)
67  {
68  NSError *underlyingError = [[error userInfo] objectForKey:NSUnderlyingErrorKey];
69  if ([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain]
70  && [underlyingError code] == ENOENT)
71  {
72  // File not found; go up a directory and try again.
73  baseURL = [baseURL URLByDeletingLastPathComponent];
74  }
75  else
76  throw VuoException((string("Couldn't get a temp folder: ") + [[error localizedDescription] UTF8String]).c_str());
77  }
78  else if (!temporaryDirectoryURL)
79  throw VuoException("Couldn't get a temp folder for path \"" + path + "\".");
80  else
81  break;
82  }
83 
84  return [[temporaryDirectoryURL path] UTF8String];
85 }
86 
95 {
96  NSString *pathNS = [NSString stringWithUTF8String:path.c_str()];
97  if (!pathNS)
98  throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
99 
100  NSDictionary *fileAttributes;
101  while (true)
102  {
103  NSError *error = nil;
104  fileAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:pathNS error:&error];
105  if (error)
106  {
107  NSError *underlyingError = [[error userInfo] objectForKey:NSUnderlyingErrorKey];
108  if ([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain]
109  && [underlyingError code] == ENOENT)
110  {
111  // File not found; go up a directory and try again.
112  pathNS = [pathNS stringByDeletingLastPathComponent];
113  }
114  else
115  throw VuoException((string("Couldn't get information about path: ") + [[error localizedDescription] UTF8String]).c_str());
116  }
117  else if (!fileAttributes)
118  throw VuoException("Couldn't get information about path \"" + path + "\".");
119  else
120  break;
121  }
122 
123  unsigned long long freeSpace = [fileAttributes[NSFileSystemFreeSize] longLongValue];
124  return freeSpace;
125 }
126 
132 void VuoFileUtilitiesCocoa_focusProcess(pid_t pid, bool force)
133 {
134  NSRunningApplication *compositionApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
135  [compositionApp activateWithOptions: NSApplicationActivateAllWindows
136  | (force ? NSApplicationActivateIgnoringOtherApps : 0)];
137 }
138 
143 {
144  return NSProcessInfo.processInfo.operatingSystemVersion.majorVersion;
145 }
146 
151 {
152  return NSProcessInfo.processInfo.operatingSystemVersion.minorVersion;
153 }
154 
158 void VuoFileUtilitiesCocoa_setIcon(string filePath, string imagePath)
159 {
160  NSImage *image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:imagePath.c_str()]];
161  [[NSWorkspace sharedWorkspace] setIcon:image forFile:[NSString stringWithUTF8String:filePath.c_str()] options:0];
162  [image release];
163 }
164 
169 void VuoFileUtilitiesCocoa_setBundle(string filePath)
170 {
171  CFStringRef path = CFStringCreateWithCString(NULL, filePath.c_str(), kCFStringEncodingUTF8);
172  CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, true);
173  CFErrorRef error;
174  if (!CFURLSetResourcePropertyForKey(url, kCFURLIsPackageKey, kCFBooleanTrue, &error))
175  {
176  CFStringRef errorString = CFErrorCopyDescription(error);
177  VUserLog("Warning: Couldn't set kCFURLIsPackageKey on this bundle: %s", VuoStringUtilities::makeFromCFString(errorString).c_str());
178  CFRelease(errorString);
179  }
180  CFRelease(url);
181  CFRelease(path);
182 }
183 
187 static CFURLRef VuoFileUtilitiesCocoa_getCFURL(const string &path)
188 {
189  if (path.empty())
190  return nullptr;
191 
192  CFStringRef cfpath = CFStringCreateWithCString(nullptr, path.c_str(), kCFStringEncodingUTF8);
193  if (!cfpath)
194  throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
195  VuoDefer(^{ CFRelease(cfpath); });
196 
197  CFURLRef url = CFURLCreateWithFileSystemPath(nullptr, cfpath, kCFURLPOSIXPathStyle, true);
198  if (!url)
199  throw VuoException("Path \"" + path + "\" isn't a valid POSIX path.");
200 
201  return url;
202 }
203 
207 static CFDataRef VuoFileUtilitiesCocoa_getMacAliasData(const string &path)
208 {
209  CFURLRef url = VuoFileUtilitiesCocoa_getCFURL(path);
210  if (!url)
211  return nullptr;
212  VuoDefer(^{ CFRelease(url); });
213 
214  return CFURLCreateBookmarkDataFromFile(nullptr, url, nullptr);
215 }
216 
222 bool VuoFileUtilitiesCocoa_isMacAlias(const string &path)
223 {
224  CFDataRef aliasData = VuoFileUtilitiesCocoa_getMacAliasData(path);
225  if (!aliasData)
226  return false;
227 
228  CFRelease(aliasData);
229  return true;
230 }
231 
237 string VuoFileUtilitiesCocoa_resolveMacAlias(const string &path)
238 {
239  CFDataRef aliasData = VuoFileUtilitiesCocoa_getMacAliasData(path);
240  if (!aliasData)
241  throw VuoException("Path \"" + path + "\" isn't a macOS Alias.");
242  VuoDefer(^{ CFRelease(aliasData); });
243 
244  CFURLRef url = VuoFileUtilitiesCocoa_getCFURL(path);
245  VuoDefer(^{ CFRelease(url); });
246 
247  Boolean isStale = false;
248  CFErrorRef error = nullptr;
249  CFURLRef resolvedURL = CFURLCreateByResolvingBookmarkData(nullptr, aliasData, kCFBookmarkResolutionWithoutUIMask, url, nullptr, &isStale, &error);
250  if (!resolvedURL)
251  {
252  CFStringRef desc = CFErrorCopyDescription(error);
253  VuoDefer(^{ CFRelease(desc); });
254  throw VuoException("Path \"" + path + "\" is a macOS Alias, but it couldn't be resolved: \"" + VuoStringUtilities::makeFromCFString(desc) + "\" (isStale=" + std::to_string(isStale) + ")");
255  }
256  VuoDefer(^{ CFRelease(resolvedURL); });
257 
258  CFStringRef resolvedPath = CFURLCopyFileSystemPath(resolvedURL, kCFURLPOSIXPathStyle);
259  if (!resolvedPath)
260  throw VuoException("Path \"" + path + "\" is a macOS Alias, but it resolved to something that isn't a POSIX path (\"" + VuoStringUtilities::makeFromCFString(((NSURL *)resolvedURL).description) + "\").");
261  VuoDefer(^{ CFRelease(resolvedPath); });
262 
263  return VuoStringUtilities::makeFromCFString(resolvedPath);
264 }