iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugPaths.mm
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
17#include "IPlugPaths.h"
18#include <string>
19#include <map>
20
21#if defined(OS_IOS) || defined(OS_MAC)
22#import <Foundation/Foundation.h>
23#include <TargetConditionals.h>
24#endif
25
26#ifdef IGRAPHICS_METAL
27extern std::map<std::string, void*> gTextureMap;
28#endif
29
30BEGIN_IPLUG_NAMESPACE
31
32#ifdef OS_MAC
33#pragma mark - macOS
34
35void HostPath(WDL_String& path, const char* bundleID)
36{
37 @autoreleasepool
38 {
39 NSBundle* pBundle = [NSBundle bundleWithIdentifier: [NSString stringWithUTF8String:bundleID]];
40
41 if (pBundle)
42 {
43 NSString* pPath = [pBundle executablePath];
44 if (pPath)
45 {
46 path.Set([pPath UTF8String]);
47 }
48 }
49 }
50}
51
52void PluginPath(WDL_String& path, PluginIDType bundleID)
53{
54 @autoreleasepool
55 {
56 NSBundle* pBundle = [NSBundle bundleWithIdentifier: [NSString stringWithUTF8String:bundleID]];
57
58 if (pBundle)
59 {
60 NSString* pPath = [[pBundle bundlePath] stringByDeletingLastPathComponent];
61
62 if (pPath)
63 {
64 path.Set([pPath UTF8String]);
65 path.Append("/");
66 }
67 }
68 }
69}
70
71void BundleResourcePath(WDL_String& path, PluginIDType bundleID)
72{
73 @autoreleasepool
74 {
75 NSBundle* pBundle = nil;
76
77 if (IsAUv3AppExtensionBundleID(bundleID))
78 {
79 // For AUv3: use Framework bundle (appex can't access container app's resources in sandbox)
80 // Derive Framework bundle ID: "xxx.AUv3" -> "xxx.AUv3Framework"
81 NSString* frameworkBundleID = [[NSString stringWithUTF8String:bundleID] stringByAppendingString:@"Framework"];
82 pBundle = [NSBundle bundleWithIdentifier:frameworkBundleID];
83 }
84 else
85 {
86 pBundle = [NSBundle bundleWithIdentifier:[NSString stringWithUTF8String:bundleID]];
87 }
88
89 NSString* pResPath = [pBundle resourcePath];
90
91 path.Set([pResPath UTF8String]);
92 }
93}
94
95void DesktopPath(WDL_String& path)
96{
97 NSArray* pPaths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
98 NSString* pDesktopDirectory = [pPaths objectAtIndex:0];
99 path.Set([pDesktopDirectory UTF8String]);
100}
101
102void UserHomePath(WDL_String& path)
103{
104 NSString* pHomeDir = NSHomeDirectory();
105 path.Set([pHomeDir UTF8String]);
106}
107
108void VST3PresetsPath(WDL_String& path, const char* mfrName, const char* pluginName, bool isSystem)
109{
110 NSArray* pPaths;
111 if (isSystem)
112 pPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSLocalDomainMask, YES);
113 else
114 pPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
115
116 NSString* pApplicationSupportDirectory = [pPaths objectAtIndex:0];
117 path.SetFormatted(MAX_MACOS_PATH_LEN, "%s/Audio/Presets/%s/%s/", [pApplicationSupportDirectory UTF8String], mfrName, pluginName);
118}
119
120void INIPath(WDL_String& path, const char* pluginName)
121{
122 AppSupportPath(path, false);
123 path.AppendFormatted(MAX_MACOS_PATH_LEN, "/%s", pluginName);
124}
125
126void AppSupportPath(WDL_String& path, bool isSystem)
127{
128 NSArray* pPaths;
129
130 if (isSystem)
131 pPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSSystemDomainMask, YES);
132 else
133 pPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
134
135 NSString *pApplicationSupportDirectory = [pPaths objectAtIndex:0];
136 path.Set([pApplicationSupportDirectory UTF8String]);
137}
138
139void AppGroupContainerPath(WDL_String& path, const char* appGroupID)
140{
141 NSFileManager* mgr = [NSFileManager defaultManager];
142 NSURL* url = [mgr containerURLForSecurityApplicationGroupIdentifier:[NSString stringWithUTF8String:appGroupID]];
143 path.Set([[url path] UTF8String]);
144}
145
146void SharedMusicPath(WDL_String& path)
147{
148 NSArray* pPaths = NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES);
149 NSString* pUserMusicDirectory = [pPaths objectAtIndex:0];
150 path.Set([pUserMusicDirectory UTF8String]);
151}
152
153bool GetResourcePathFromBundle(const char* fileName, const char* searchExt, WDL_String& fullPath, const char* bundleID)
154{
155 @autoreleasepool
156 {
157 const char* ext = fileName+strlen(fileName)-1;
158 while (ext >= fileName && *ext != '.') --ext;
159 ++ext;
160
161 bool isCorrectType = !strcasecmp(ext, searchExt);
162
163 bool isAppExtension = IsAUv3AppExtensionBundleID(bundleID);
164
165 NSBundle* pBundle = nil;
166
167 if (isAppExtension)
168 {
169 // For AUv3: use Framework bundle (appex can't access container app's resources in sandbox)
170 // Derive Framework bundle ID: "xxx.AUv3" -> "xxx.AUv3Framework"
171 NSString* frameworkBundleID = [[NSString stringWithUTF8String:bundleID] stringByAppendingString:@"Framework"];
172 pBundle = [NSBundle bundleWithIdentifier:frameworkBundleID];
173 }
174 else
175 {
176 pBundle = [NSBundle bundleWithIdentifier:[NSString stringWithUTF8String:bundleID]];
177 }
178
179 NSString* pFile = [[NSString stringWithUTF8String:fileName] stringByDeletingPathExtension];
180 NSString* pExt = [NSString stringWithUTF8String:searchExt];
181
182 if (isCorrectType && pBundle && pFile)
183 {
184 NSString* pBasePath = [[pBundle resourcePath] stringByAppendingString:@"/"];
185
186 NSString* pPath = [[[pBasePath stringByAppendingString:pFile] stringByAppendingString: @"."] stringByAppendingString:pExt];
187
188 if (pPath && [[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
189 {
190 fullPath.Set([pPath UTF8String]);
191 return true;
192 }
193 }
194
195 fullPath.Set("");
196 return false;
197 }
198}
199
200bool GetResourcePathFromSharedLocation(const char* fileName, const char* searchExt, WDL_String& fullPath, const char* subfolder)
201{
202 @autoreleasepool
203 {
204 const char* ext = fileName+strlen(fileName)-1;
205 while (ext >= fileName && *ext != '.') --ext;
206 ++ext;
207
208 bool isCorrectType = !strcasecmp(ext, searchExt);
209
210 NSString* pExt = [NSString stringWithUTF8String:searchExt];
211 NSString* pFile = [[[NSString stringWithUTF8String:fileName] lastPathComponent] stringByDeletingPathExtension];
212
213 if (isCorrectType && pFile)
214 {
215 WDL_String musicPath;
216 SharedMusicPath(musicPath);
217
218 if (subfolder)
219 {
220 NSString* pPluginName = [NSString stringWithUTF8String:subfolder];
221 NSString* pMusicLocation = [NSString stringWithUTF8String:musicPath.Get()];
222 NSString* pPath = [[[[pMusicLocation stringByAppendingPathComponent: pPluginName] stringByAppendingPathComponent:@"Resources"] stringByAppendingPathComponent: pFile] stringByAppendingPathExtension:pExt];
223
224 if ([[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
225 {
226 fullPath.Set([pPath UTF8String]);
227 return true;
228 }
229 }
230 }
231
232 fullPath.Set("");
233 return false;
234 }
235}
236
237EResourceLocation LocateResource(const char* name, const char* type, WDL_String& result, const char* bundleID, void*, const char* sharedResourcesSubPath)
238{
239 if(CStringHasContents(name))
240 {
241 // first check this bundle
242 if(GetResourcePathFromBundle(name, type, result, bundleID))
243 return EResourceLocation::kAbsolutePath;
244
245 // then check ~/Music/sharedResourcesSubPath, which is a shared folder that can be accessed from app sandbox
246 if(GetResourcePathFromSharedLocation(name, type, result, sharedResourcesSubPath))
247 return EResourceLocation::kAbsolutePath;
248
249 // finally check name, which might be a full path - if the plug-in is trying to load a resource at runtime (e.g. skin-able UI)
250 NSString* pPath = [NSString stringWithUTF8String:name];
251
252 if([[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
253 {
254 result.Set([pPath UTF8String]);
255 return EResourceLocation::kAbsolutePath;
256 }
257 }
258 return EResourceLocation::kNotFound;
259}
260
261bool AppIsSandboxed()
262{
263 NSString* pHomeDir = NSHomeDirectory();
264
265 if ([pHomeDir containsString:@"Library/Containers/"])
266 return true;
267 else
268 return false;
269}
270
271bool IsXPCAuHost()
272{
273 return ([[[NSProcessInfo processInfo] processName] containsString:@"XPC"]);
274}
275
276bool IsOOPAuv3AppExtension()
277{
278 return ([[[NSBundle mainBundle] bundleIdentifier] containsString:@"AUv3"]);
279}
280
281bool IsAUv3AppExtensionBundleID(const char* bundleID)
282{
283 if (!bundleID)
284 return false;
285
286 return [[NSString stringWithUTF8String:bundleID] containsString:@".AUv3"];
287}
288
289#elif defined OS_IOS
290#pragma mark - iOS
291
292void HostPath(WDL_String& path, const char* bundleID)
293{
294}
295
296void PluginPath(WDL_String& path, PluginIDType bundleID)
297{
298}
299
300void BundleResourcePath(WDL_String& path, PluginIDType bundleID)
301{
302 NSBundle* pBundle = [NSBundle mainBundle];
303
304 if(IsOOPAuv3AppExtension())
305 pBundle = [NSBundle bundleWithPath: [[[pBundle bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]];
306
307 path.Set([[pBundle resourcePath] UTF8String]);
308}
309
310void DesktopPath(WDL_String& path)
311{
312}
313
314void VST3PresetsPath(WDL_String& path, const char* mfrName, const char* pluginName, bool isSystem)
315{
316 path.Set("");
317}
318
319void INIPath(WDL_String& path, const char* pluginName)
320{
321 path.Set("");
322}
323
324void AppSupportPath(WDL_String& path, bool isSystem)
325{
326}
327
328void AppGroupContainerPath(WDL_String& path, const char* appGroupID)
329{
330 NSFileManager* mgr = [NSFileManager defaultManager];
331 NSURL* url = [mgr containerURLForSecurityApplicationGroupIdentifier:[NSString stringWithUTF8String:appGroupID]];
332 path.Set([[url path] UTF8String]);
333}
334
335bool GetResourcePathFromBundle(const char* fileName, const char* searchExt, WDL_String& fullPath, const char* bundleID)
336{
337 @autoreleasepool
338 {
339 const char* ext = fileName+strlen(fileName)-1;
340 while (ext >= fileName && *ext != '.') --ext;
341 ++ext;
342
343 bool isCorrectType = !strcasecmp(ext, searchExt);
344
345 bool isAppExtension = IsOOPAuv3AppExtension();
346
347 NSBundle* pBundle;
348
349 if(isAppExtension)
350 pBundle = [NSBundle bundleWithIdentifier:[NSString stringWithUTF8String:bundleID]];
351 else
352 pBundle = [NSBundle mainBundle];
353
354 NSString* pFile = [[NSString stringWithUTF8String:fileName] stringByDeletingPathExtension];
355 NSString* pExt = [NSString stringWithUTF8String:searchExt];
356
357 if (isCorrectType && pBundle && pFile)
358 {
359 NSString* pRootPath;
360
361 if (isAppExtension)
362 {
363 pRootPath = [[[pBundle bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
364 #if TARGET_OS_MACCATALYST
365 pRootPath = [pRootPath stringByAppendingString: @"/Resources"];
366 #endif
367 }
368 else
369 {
370 pRootPath = [pBundle resourcePath];
371 }
372
373 NSString* pPath = [[[[pRootPath stringByAppendingString:@"/"] stringByAppendingString:pFile] stringByAppendingString: @"."] stringByAppendingString:pExt];
374
375 if (pPath && [[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
376 {
377 fullPath.Set([pPath UTF8String]);
378 return true;
379 }
380 }
381
382 fullPath.Set("");
383 return false;
384 }
385}
386
387EResourceLocation LocateResource(const char* name, const char* type, WDL_String& result, const char* bundleID, void*, const char*)
388{
389 if (CStringHasContents(name))
390 {
391#ifdef IGRAPHICS_METAL
392 auto itr = gTextureMap.find(name);
393
394 if (itr != gTextureMap.end())
395 {
396 result.Set(name);
397 return EResourceLocation::kPreloadedTexture;
398 }
399#endif
400
401 if (GetResourcePathFromBundle(name, type, result, bundleID))
402 return EResourceLocation::kAbsolutePath;
403 }
404
405 return EResourceLocation::kNotFound;
406}
407
408bool AppIsSandboxed()
409{
410 return true;
411}
412
413bool IsXPCAuHost()
414{
415 // TODO: actually not allways the case if AUv3 is instantiated from framework
416 return true;
417}
418
419bool IsOOPAuv3AppExtension()
420{
421 return ([[[NSBundle mainBundle] bundleIdentifier] containsString:@"AUv3"]);
422}
423
424#endif
425
426END_IPLUG_NAMESPACE
Common paths useful for plug-ins.
void UserHomePath(WDL_String &path)
EResourceLocation LocateResource(const char *fileNameOrResID, const char *type, WDL_String &result, const char *bundleID, void *pHInstance, const char *sharedResourcesSubPath)
Find the absolute path of a resource based on it's file name (e.g.
void VST3PresetsPath(WDL_String &path, const char *mfrName, const char *pluginName, bool isSystem=true)
void PluginPath(WDL_String &path, PluginIDType pExtra)
Get the path to the plug-in binary.
void DesktopPath(WDL_String &path)
void HostPath(WDL_String &path, const char *bundleID=0)
Get the path to the host binary.
void AppSupportPath(WDL_String &path, bool isSystem=false)
void BundleResourcePath(WDL_String &path, PluginIDType pExtra=0)
Get the path to the plug-in bundle resource path.
void INIPath(WDL_String &path, const char *pluginName)
Get the path to the folder where the App's settings.ini file is stored.