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 
private_frameworks_url(&self) -> Option<CFURL>102     pub fn private_frameworks_url(&self) -> Option<CFURL> {
103         unsafe {
104             let fw_url = CFBundleCopyPrivateFrameworksURL(self.0);
105             if fw_url.is_null() {
106                 None
107             } else {
108                 Some(TCFType::wrap_under_create_rule(fw_url))
109             }
110         }
111     }
112 
shared_support_url(&self) -> Option<CFURL>113     pub fn shared_support_url(&self) -> Option<CFURL> {
114         unsafe {
115             let fw_url = CFBundleCopySharedSupportURL(self.0);
116             if fw_url.is_null() {
117                 None
118             } else {
119                 Some(TCFType::wrap_under_create_rule(fw_url))
120             }
121         }
122     }
123 }
124 
125 
126 #[test]
safari_executable_url()127 fn safari_executable_url() {
128     use string::CFString;
129     use url::{CFURL, kCFURLPOSIXPathStyle};
130 
131     let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
132     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
133     let cfurl_executable = CFBundle::new(cfurl_path)
134         .expect("Safari not present")
135         .executable_url();
136     assert!(cfurl_executable.is_some());
137     assert_eq!(cfurl_executable
138                    .unwrap()
139                    .absolute()
140                    .get_file_system_path(kCFURLPOSIXPathStyle)
141                    .to_string(),
142                "/Applications/Safari.app/Contents/MacOS/Safari");
143 }
144 
145 #[test]
safari_private_frameworks_url()146 fn safari_private_frameworks_url() {
147     use string::CFString;
148     use url::{CFURL, kCFURLPOSIXPathStyle};
149 
150     let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
151     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
152     let cfurl_executable = CFBundle::new(cfurl_path)
153         .expect("Safari not present")
154         .private_frameworks_url();
155     assert!(cfurl_executable.is_some());
156     assert_eq!(cfurl_executable
157                    .unwrap()
158                    .absolute()
159                    .get_file_system_path(kCFURLPOSIXPathStyle)
160                    .to_string(),
161                "/Applications/Safari.app/Contents/Frameworks");
162 }
163 
164 #[test]
non_existant_bundle()165 fn non_existant_bundle() {
166     use string::CFString;
167     use url::{CFURL, kCFURLPOSIXPathStyle};
168 
169     let cfstr_path = CFString::from_static_string("/usr/local/foo");
170     let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
171     assert!(CFBundle::new(cfurl_path).is_none());
172 }
173