1 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 //! Core Foundation Bundle Type
11 
12 use core_foundation_sys::base::kCFAllocatorDefault;
13 pub use core_foundation_sys::bundle::*;
14 use core_foundation_sys::url::kCFURLPOSIXPathStyle;
15 use std::path::PathBuf;
16 
17 use base::{CFType, TCFType};
18 use url::CFURL;
19 use dictionary::CFDictionary;
20 use std::os::raw::c_void;
21 use string::CFString;
22 
23 declare_TCFType!{
24     /// A Bundle type.
25     CFBundle, CFBundleRef
26 }
27 impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID);
28 
29 impl CFBundle {
new(bundleURL: CFURL) -> Option<CFBundle>30     pub fn new(bundleURL: CFURL) -> Option<CFBundle> {
31         unsafe {
32             let bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundleURL.as_concrete_TypeRef());
33             if bundle_ref.is_null() {
34                 None
35             } else {
36                 Some(TCFType::wrap_under_create_rule(bundle_ref))
37             }
38         }
39     }
40 
bundle_with_identifier(identifier: CFString) -> Option<CFBundle>41     pub fn bundle_with_identifier(identifier: CFString) -> Option<CFBundle> {
42         unsafe {
43             let bundle_ref = CFBundleGetBundleWithIdentifier(identifier.as_concrete_TypeRef());
44             if bundle_ref.is_null() {
45                 None
46             } else {
47                 Some(TCFType::wrap_under_get_rule(bundle_ref))
48             }
49         }
50     }
51 
function_pointer_for_name(&self, function_name: CFString) -> *const c_void52     pub fn function_pointer_for_name(&self, function_name: CFString) -> *const c_void {
53         unsafe {
54             CFBundleGetFunctionPointerForName(self.as_concrete_TypeRef(),
55                                               function_name.as_concrete_TypeRef())
56         }
57     }
58 
main_bundle() -> CFBundle59     pub fn main_bundle() -> CFBundle {
60         unsafe {
61             let bundle_ref = CFBundleGetMainBundle();
62             TCFType::wrap_under_get_rule(bundle_ref)
63         }
64     }
65 
info_dictionary(&self) -> CFDictionary<CFString, CFType>66     pub fn info_dictionary(&self) -> CFDictionary<CFString, CFType> {
67         unsafe {
68             let info_dictionary = CFBundleGetInfoDictionary(self.0);
69             TCFType::wrap_under_get_rule(info_dictionary)
70         }
71     }
72 
executable_url(&self) -> Option<CFURL>73     pub fn executable_url(&self) -> Option<CFURL> {
74         unsafe {
75             let exe_url = CFBundleCopyExecutableURL(self.0);
76             if exe_url.is_null() {
77                 None
78             } else {
79                 Some(TCFType::wrap_under_create_rule(exe_url))
80             }
81         }
82     }
83 
84     /// Bundle's own location
bundle_url(&self) -> Option<CFURL>85     pub fn bundle_url(&self) -> Option<CFURL> {
86         unsafe {
87             let bundle_url = CFBundleCopyBundleURL(self.0);
88             if bundle_url.is_null() {
89                 None
90             } else {
91                 Some(TCFType::wrap_under_create_rule(bundle_url))
92             }
93         }
94     }
95 
96     /// Bundle's own location
path(&self) -> Option<PathBuf>97     pub fn path(&self) -> Option<PathBuf> {
98         let url = self.bundle_url()?;
99         Some(PathBuf::from(url.get_file_system_path(kCFURLPOSIXPathStyle).to_string()))
100     }
101 
102     /// Bundle's resources location
bundle_resources_url(&self) -> Option<CFURL>103     pub fn bundle_resources_url(&self) -> Option<CFURL> {
104         unsafe {
105             let bundle_url = CFBundleCopyResourcesDirectoryURL(self.0);
106             if bundle_url.is_null() {
107                 None
108             } else {
109                 Some(TCFType::wrap_under_create_rule(bundle_url))
110             }
111         }
112     }
113 
114     /// Bundle's resources location
resources_path(&self) -> Option<PathBuf>115     pub fn resources_path(&self) -> Option<PathBuf> {
116         let url = self.bundle_resources_url()?;
117         Some(PathBuf::from(url.get_file_system_path(kCFURLPOSIXPathStyle).to_string()))
118     }
119 
private_frameworks_url(&self) -> Option<CFURL>120     pub fn private_frameworks_url(&self) -> Option<CFURL> {
121         unsafe {
122             let fw_url = CFBundleCopyPrivateFrameworksURL(self.0);
123             if fw_url.is_null() {
124                 None
125             } else {
126                 Some(TCFType::wrap_under_create_rule(fw_url))
127             }
128         }
129     }
130 
shared_support_url(&self) -> Option<CFURL>131     pub fn shared_support_url(&self) -> Option<CFURL> {
132         unsafe {
133             let fw_url = CFBundleCopySharedSupportURL(self.0);
134             if fw_url.is_null() {
135                 None
136             } else {
137                 Some(TCFType::wrap_under_create_rule(fw_url))
138             }
139         }
140     }
141 }
142 
143 
144 #[test]
safari_executable_url()145 fn safari_executable_url() {
146     use string::CFString;
147     use url::{CFURL, kCFURLPOSIXPathStyle};
148 
149     let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
150     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
151     let cfurl_executable = CFBundle::new(cfurl_path)
152         .expect("Safari not present")
153         .executable_url();
154     assert!(cfurl_executable.is_some());
155     assert_eq!(cfurl_executable
156                    .unwrap()
157                    .absolute()
158                    .get_file_system_path(kCFURLPOSIXPathStyle)
159                    .to_string(),
160                "/Applications/Safari.app/Contents/MacOS/Safari");
161 }
162 
163 #[test]
safari_private_frameworks_url()164 fn safari_private_frameworks_url() {
165     use string::CFString;
166     use url::{CFURL, kCFURLPOSIXPathStyle};
167 
168     let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
169     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
170     let cfurl_executable = CFBundle::new(cfurl_path)
171         .expect("Safari not present")
172         .private_frameworks_url();
173     assert!(cfurl_executable.is_some());
174     assert_eq!(cfurl_executable
175                    .unwrap()
176                    .absolute()
177                    .get_file_system_path(kCFURLPOSIXPathStyle)
178                    .to_string(),
179                "/Applications/Safari.app/Contents/Frameworks");
180 }
181 
182 #[test]
non_existant_bundle()183 fn non_existant_bundle() {
184     use string::CFString;
185     use url::{CFURL, kCFURLPOSIXPathStyle};
186 
187     let cfstr_path = CFString::from_static_string("/usr/local/foo");
188     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
189     assert!(CFBundle::new(cfurl_path).is_none());
190 }
191