1 //
2 // CoreFoundation.cs
3 //
4 // Author:
5 //       Michael Hutchinson <mhutchinson@novell.com>
6 //       Miguel de Icaza
7 //
8 // Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 
28 using System;
29 using System.Runtime.InteropServices;
30 
31 namespace MonoDevelop.MacInterop
32 {
33     internal static class CoreFoundation
34     {
35         const string CFLib = "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation";
36         const string LSLib = "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices";
37 
38         [DllImport (CFLib)]
CFStringCreateWithCString(IntPtr alloc, string str, int encoding)39         static extern IntPtr CFStringCreateWithCString (IntPtr alloc, string str, int encoding);
40 
CreateString(string s)41         public static IntPtr CreateString (string s)
42         {
43             // The magic value is "kCFStringENcodingUTF8"
44             return CFStringCreateWithCString (IntPtr.Zero, s, 0x08000100);
45         }
46 
47         [DllImport (CFLib, EntryPoint="CFRelease")]
Release(IntPtr cfRef)48         public static extern void Release (IntPtr cfRef);
49 
50         struct CFRange {
51             public int Location, Length;
CFRangeMonoDevelop.MacInterop.CoreFoundation.CFRange52             public CFRange (int l, int len)
53             {
54                 Location = l;
55                 Length = len;
56             }
57         }
58 
59         [DllImport (CFLib, CharSet=CharSet.Unicode)]
CFStringGetLength(IntPtr handle)60         extern static int CFStringGetLength (IntPtr handle);
61 
62         [DllImport (CFLib, CharSet=CharSet.Unicode)]
CFStringGetCharactersPtr(IntPtr handle)63         extern static IntPtr CFStringGetCharactersPtr (IntPtr handle);
64 
65         [DllImport (CFLib, CharSet=CharSet.Unicode)]
CFStringGetCharacters(IntPtr handle, CFRange range, IntPtr buffer)66         extern static IntPtr CFStringGetCharacters (IntPtr handle, CFRange range, IntPtr buffer);
67 
FetchString(IntPtr handle)68         public static string FetchString (IntPtr handle)
69         {
70             if (handle == IntPtr.Zero)
71                 return null;
72 
73             string str;
74 
75             int l = CFStringGetLength (handle);
76             IntPtr u = CFStringGetCharactersPtr (handle);
77             IntPtr buffer = IntPtr.Zero;
78             if (u == IntPtr.Zero){
79                 CFRange r = new CFRange (0, l);
80                 buffer = Marshal.AllocCoTaskMem (l * 2);
81                 CFStringGetCharacters (handle, r, buffer);
82                 u = buffer;
83             }
84 
85             /*
86             unsafe {
87                 str = new string ((char *) u, 0, l);
88             }
89             */
90             str = Marshal.PtrToStringUni(u, l);
91 
92             if (buffer != IntPtr.Zero)
93                 Marshal.FreeCoTaskMem (buffer);
94 
95             return str;
96         }
97 
FSRefToString(ref FSRef fsref)98         public static string FSRefToString (ref FSRef fsref)
99         {
100             IntPtr url = IntPtr.Zero;
101             IntPtr str = IntPtr.Zero;
102             try {
103                 url = CFURLCreateFromFSRef (IntPtr.Zero, ref fsref);
104                 if (url == IntPtr.Zero)
105                     return null;
106                 str = CFURLCopyFileSystemPath (url, CFUrlPathStyle.Posix);
107                 if (str == IntPtr.Zero)
108                     return null;
109                 return FetchString (str);
110             } finally {
111                 if (url != IntPtr.Zero)
112                     Release (url);
113                 if (str != IntPtr.Zero)
114                     Release (str);
115             }
116         }
117 
118         [DllImport (CFLib)]
CFURLCreateFromFSRef(IntPtr allocator, ref FSRef fsref)119         extern static IntPtr CFURLCreateFromFSRef (IntPtr allocator, ref FSRef fsref);
120 
121         [DllImport (CFLib)]
CFURLCopyFileSystemPath(IntPtr urlRef, CFUrlPathStyle pathStyle)122         extern static IntPtr CFURLCopyFileSystemPath (IntPtr urlRef, CFUrlPathStyle pathStyle);
123 
124         enum CFUrlPathStyle
125         {
126             Posix = 0,
127             Hfs = 1,
128             Windows = 2
129         };
130 
131         [DllImport (CFLib)]
CFURLCreateWithFileSystemPath(IntPtr allocator, IntPtr filePathString, CFUrlPathStyle pathStyle, bool isDirectory)132         extern static IntPtr CFURLCreateWithFileSystemPath (IntPtr allocator, IntPtr filePathString,
133             CFUrlPathStyle pathStyle, bool isDirectory);
134 
135         [DllImport (LSLib)]
LSCopyApplicationURLsForURL(IntPtr urlRef, LSRolesMask roleMask)136         extern static IntPtr LSCopyApplicationURLsForURL (IntPtr urlRef, LSRolesMask roleMask); //CFArrayRef
137 
138         [DllImport (LSLib)]
LSGetApplicationForURL(IntPtr url, LSRolesMask roleMask, IntPtr fsRefZero, ref IntPtr appUrl)139         extern static int LSGetApplicationForURL (IntPtr url, LSRolesMask roleMask, IntPtr fsRefZero,
140             ref IntPtr  appUrl);
141 
142         [DllImport (CFLib)]
CFArrayGetCount(IntPtr theArray)143         extern static int CFArrayGetCount (IntPtr theArray);
144 
145         [DllImport (CFLib)]
CFArrayGetValueAtIndex(IntPtr theArray, int idx)146         extern static IntPtr CFArrayGetValueAtIndex (IntPtr theArray, int idx);
147 
148         [Flags]
149         public enum LSRolesMask : uint
150         {
151             None = 0x00000001,
152             Viewer = 0x00000002,
153             Editor = 0x00000004,
154             Shell = 0x00000008,
155             All = 0xFFFFFFFF
156         }
157 
CreatePathUrl(string path)158         static IntPtr CreatePathUrl (string path)
159         {
160             IntPtr str = IntPtr.Zero;
161             IntPtr url = IntPtr.Zero;
162             try {
163                 str = CreateString (path);
164                 if (str == IntPtr.Zero)
165                     throw new Exception ("CreateString failed");
166                 url = CFURLCreateWithFileSystemPath (IntPtr.Zero, str, CFUrlPathStyle.Posix, false);
167                 if (url == IntPtr.Zero)
168                     throw new Exception ("CFURLCreateWithFileSystemPath failed");
169                 return url;
170             } finally {
171                 if (str != IntPtr.Zero)
172                     Release (str);
173             }
174         }
175 
UrlToPath(IntPtr url)176         public static string UrlToPath (IntPtr url)
177         {
178             IntPtr str = IntPtr.Zero;
179             try {
180                 str = CFURLCopyFileSystemPath (url, CFUrlPathStyle.Posix);
181                 return str == IntPtr.Zero? null : FetchString (str);
182             } finally {
183                 if (str != IntPtr.Zero)
184                     Release (str);
185             }
186         }
187 
GetApplicationUrl(string filePath, LSRolesMask roles)188         public static string GetApplicationUrl (string filePath, LSRolesMask roles)
189         {
190             IntPtr url = IntPtr.Zero;
191             try {
192                 url = CreatePathUrl (filePath);
193                 IntPtr appUrl = IntPtr.Zero;
194                 if (LSGetApplicationForURL (url, roles, IntPtr.Zero, ref appUrl) == 0 && appUrl != IntPtr.Zero)
195                     return UrlToPath (appUrl);
196                 return null;
197             } finally {
198                 if (url != IntPtr.Zero)
199                     Release (url);
200             }
201         }
202 
GetApplicationUrls(string filePath, LSRolesMask roles)203         public static string[] GetApplicationUrls (string filePath, LSRolesMask roles)
204         {
205             IntPtr url = IntPtr.Zero;
206             IntPtr arr = IntPtr.Zero;
207             try {
208                 url = CreatePathUrl (filePath);
209                 arr = LSCopyApplicationURLsForURL (url, roles);
210                 if (arr == IntPtr.Zero)
211                     return new string[0];
212                 int count = CFArrayGetCount (arr);
213                 string[] values = new string [count];
214                 for (int i = 0; i < values.Length; i++ ) {
215                     var u = CFArrayGetValueAtIndex (arr, i);
216                     if (u != IntPtr.Zero)
217                         values[i] = UrlToPath (u);
218                 }
219                 return values;
220             } finally {
221                 if (url != IntPtr.Zero)
222                     Release (url);
223                 if (arr != IntPtr.Zero)
224                     Release (arr);
225             }
226         }
227     }
228 }