Vuo 2.4.2
Loading...
Searching...
No Matches
VuoFileUtilitiesCocoa.mm
Go to the documentation of this file.
1
10#include "VuoFileUtilities.hh"
12#include "VuoException.hh"
13#include "VuoStringUtilities.hh"
14
15#include <AppKit/AppKit.h>
16#include <sys/utsname.h>
17
24{
25 NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filePath.c_str()]];
26 if (!url)
27 throw VuoException("Couldn't move file '" + filePath + "' to the trash: Couldn't create NSURL.");
28
29 NSError *error = nil;
30 bool success = [[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:nil error:&error];
31 if (!success)
32 throw VuoException(string("Couldn't move file '" + filePath + "' to the trash: ") + [[error localizedDescription] UTF8String]);
33}
34
46{
47 NSString *pathNS = [NSString stringWithUTF8String:path.c_str()];
48 if (!pathNS)
49 throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
50
51 NSURL *baseURL = [NSURL fileURLWithPath:pathNS isDirectory:YES];
52 if (!baseURL)
53 throw VuoException("Path \"" + path + "\" isn't a valid directory.");
54
55 NSURL *temporaryDirectoryURL = nil;
56 while (true)
57 {
58 NSError *error = nil;
59 temporaryDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSItemReplacementDirectory
60 inDomain:NSUserDomainMask
61 appropriateForURL:baseURL
62 create:YES
63 error:&error];
64 if (error)
65 {
66 NSError *underlyingError = [[error userInfo] objectForKey:NSUnderlyingErrorKey];
67 if ([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain]
68 && [underlyingError code] == ENOENT)
69 {
70 // File not found; go up a directory and try again.
71 baseURL = [baseURL URLByDeletingLastPathComponent];
72 }
73 else
74 throw VuoException((string("Couldn't get a temp folder: ") + [[error localizedDescription] UTF8String]).c_str());
75 }
76 else if (!temporaryDirectoryURL)
77 throw VuoException("Couldn't get a temp folder for path \"" + path + "\".");
78 else
79 break;
80 }
81
82 return [[temporaryDirectoryURL path] UTF8String];
83}
84
93{
94 NSString *pathNS = [NSString stringWithUTF8String:path.c_str()];
95 if (!pathNS)
96 throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
97
98 NSDictionary *fileAttributes;
99 while (true)
100 {
101 NSError *error = nil;
102 fileAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:pathNS error:&error];
103 if (error)
104 {
105 NSError *underlyingError = [[error userInfo] objectForKey:NSUnderlyingErrorKey];
106 if ([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain]
107 && [underlyingError code] == ENOENT)
108 {
109 // File not found; go up a directory and try again.
110 pathNS = [pathNS stringByDeletingLastPathComponent];
111 }
112 else
113 throw VuoException((string("Couldn't get information about path: ") + [[error localizedDescription] UTF8String]).c_str());
114 }
115 else if (!fileAttributes)
116 throw VuoException("Couldn't get information about path \"" + path + "\".");
117 else
118 break;
119 }
120
121 unsigned long long freeSpace = [fileAttributes[NSFileSystemFreeSize] longLongValue];
122 return freeSpace;
123}
124
130void VuoFileUtilitiesCocoa_focusProcess(pid_t pid, bool force)
131{
132 // On recent macOS versions, `-[NSRunningApplication activateWithOptions:]` fails,
133 // but the older `SetFrontProcess()` API works, so use that instead.
134
135 // NSRunningApplication *compositionApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
136 // BOOL ret = [compositionApp activateWithOptions: NSApplicationActivateAllWindows
137 // | (force ? NSApplicationActivateIgnoringOtherApps : 0)];
138 // if (!ret)
139 // VUserLog("-[NSRunningApplication activateWithOptions:] failed for pid %d", pid);
140
141#pragma clang diagnostic push
142#pragma clang diagnostic ignored "-Wdeprecated-declarations"
143 ProcessSerialNumber psn;
144 OSErr ret = GetProcessForPID(pid, &psn);
145 if (ret != noErr)
146 {
147 VUserLog("GetProcessForPID(%d) failed: %d", pid, ret);
148 return;
149 }
150
151 ret = SetFrontProcess(&psn);
152 if (ret != noErr)
153 {
154 VUserLog("SetFrontProcess(%d) failed: %d", pid, ret);
155 return;
156 }
157#pragma clang diagnostic pop
158}
159
164{
165 return NSProcessInfo.processInfo.operatingSystemVersion.majorVersion;
166}
167
172{
173 return NSProcessInfo.processInfo.operatingSystemVersion.minorVersion;
174}
175
180{
181 struct utsname un;
182 if (uname(&un) < 0)
183 throw VuoException("Couldn't look up the system's architecture: %s", strerror(errno));
184
185 return un.machine;
186}
187
193{
194 CFStringRef path = CFStringCreateWithCString(NULL, filePath.c_str(), kCFStringEncodingUTF8);
195 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, true);
196 CFErrorRef error;
197 if (!CFURLSetResourcePropertyForKey(url, kCFURLIsPackageKey, kCFBooleanTrue, &error))
198 {
199 CFStringRef errorString = CFErrorCopyDescription(error);
200 VUserLog("Warning: Couldn't set kCFURLIsPackageKey on this bundle: %s", VuoStringUtilities::makeFromCFString(errorString).c_str());
201 CFRelease(errorString);
202 }
203 CFRelease(url);
204 CFRelease(path);
205}
206
210static CFURLRef VuoFileUtilitiesCocoa_getCFURL(const string &path)
211{
212 if (path.empty())
213 return nullptr;
214
215 CFStringRef cfpath = CFStringCreateWithCString(nullptr, path.c_str(), kCFStringEncodingUTF8);
216 if (!cfpath)
217 throw VuoException("Path \"" + path + "\" isn't a valid UTF-8 string.");
218 VuoDefer(^{ CFRelease(cfpath); });
219
220 CFURLRef url = CFURLCreateWithFileSystemPath(nullptr, cfpath, kCFURLPOSIXPathStyle, true);
221 if (!url)
222 throw VuoException("Path \"" + path + "\" isn't a valid POSIX path.");
223
224 return url;
225}
226
230static CFDataRef VuoFileUtilitiesCocoa_getMacAliasData(const string &path)
231{
232 CFURLRef url = VuoFileUtilitiesCocoa_getCFURL(path);
233 if (!url)
234 return nullptr;
235 VuoDefer(^{ CFRelease(url); });
236
237 return CFURLCreateBookmarkDataFromFile(nullptr, url, nullptr);
238}
239
245bool VuoFileUtilitiesCocoa_isMacAlias(const string &path)
246{
247 CFDataRef aliasData = VuoFileUtilitiesCocoa_getMacAliasData(path);
248 if (!aliasData)
249 return false;
250
251 CFRelease(aliasData);
252 return true;
253}
254
261{
262 CFDataRef aliasData = VuoFileUtilitiesCocoa_getMacAliasData(path);
263 if (!aliasData)
264 throw VuoException("Path \"" + path + "\" isn't a macOS Alias.");
265 VuoDefer(^{ CFRelease(aliasData); });
266
267 CFURLRef url = VuoFileUtilitiesCocoa_getCFURL(path);
268 VuoDefer(^{ CFRelease(url); });
269
270 Boolean isStale = false;
271 CFErrorRef error = nullptr;
272 CFURLRef resolvedURL = CFURLCreateByResolvingBookmarkData(nullptr, aliasData, kCFBookmarkResolutionWithoutUIMask, url, nullptr, &isStale, &error);
273 if (!resolvedURL)
274 {
275 CFStringRef desc = CFErrorCopyDescription(error);
276 VuoDefer(^{ CFRelease(desc); });
277 throw VuoException("Path \"" + path + "\" is a macOS Alias, but it couldn't be resolved: \"" + VuoStringUtilities::makeFromCFString(desc) + "\" (isStale=" + std::to_string(isStale) + ")");
278 }
279 VuoDefer(^{ CFRelease(resolvedURL); });
280
281 CFStringRef resolvedPath = CFURLCopyFileSystemPath(resolvedURL, kCFURLPOSIXPathStyle);
282 if (!resolvedPath)
283 throw VuoException("Path \"" + path + "\" is a macOS Alias, but it resolved to something that isn't a POSIX path (\"" + VuoStringUtilities::makeFromCFString(((NSURL *)resolvedURL).description) + "\").");
284 VuoDefer(^{ CFRelease(resolvedPath); });
285
286 return VuoStringUtilities::makeFromCFString(resolvedPath);
287}