1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
extern crate file_metadata_mditem_macros; use std::marker::PhantomData; use core_foundation_sys::base::{CFAllocatorRef, kCFAllocatorDefault}; use core_foundation_sys::base::{TCFTypeRef, CFTypeID}; use core_foundation::url::{CFURL, CFURLRef}; use core_foundation::string::{CFString, CFStringRef}; use core_foundation::array::{CFArray, CFArrayRef}; use core_foundation::base::TCFType; use libc::c_void; #[repr(C)] pub struct __MDItemRef(c_void); pub type MDItemRef = *const __MDItemRef; #[link(name = "CoreServices", kind = "framework")] extern "C" { fn MDItemCreate(allocator: CFAllocatorRef, path: CFStringRef) -> MDItemRef; fn MDItemCreateWithURL(allocator: CFAllocatorRef, url: CFURLRef) -> MDItemRef; fn MDItemCopyAttribute(item: MDItemRef, name: CFStringRef) -> *const c_void; fn MDItemCopyAttributeNames(item: MDItemRef) -> CFArrayRef; fn MDItemGetTypeID() -> CFTypeID; } pub struct Attribute<T> { pub key_getter: fn() -> CFStringRef, pub phantom: PhantomData<T> } impl<T: TCFType> Attribute<T> { pub fn key(&self) -> CFStringRef { (self.key_getter)() } } pub mod attributes; declare_TCFType!{ MDItem, MDItemRef } impl_TCFType!(MDItem, MDItemRef, MDItemGetTypeID); impl MDItem { pub fn from_string(path: CFString) -> Option<MDItem> { let ptr = unsafe { MDItemCreate(kCFAllocatorDefault, path.as_concrete_TypeRef()) }; if ptr.is_null() { None } else { Some(unsafe { TCFType::wrap_under_create_rule(ptr) }) } } pub fn from_url(url: CFURL) -> Option<MDItem> { let ptr = unsafe { MDItemCreateWithURL(kCFAllocatorDefault, url.as_concrete_TypeRef()) }; if ptr.is_null() { None } else { Some(unsafe { TCFType::wrap_under_create_rule(ptr) }) } } pub fn attributes(&self) -> CFArray<CFString> { unsafe { TCFType::wrap_under_create_rule(MDItemCopyAttributeNames(self.0)) } } #[inline] pub fn get<T>(&self, attr: Attribute<T>) -> Option<T> where T: TCFType { let value = unsafe { MDItemCopyAttribute(self.0, attr.key()) }; if value.is_null() { None } else { Some(unsafe { T::wrap_under_create_rule(T::Ref::from_void_ptr(value)) }) } } } #[cfg(test)] mod tests { use super::{MDItem, attributes::{CFBundleIdentifier, DisplayName}}; use core_foundation::url::CFURL; use core_foundation::string::CFString; use std::path::Path; #[test] fn get_safari_bundle_id_and_display_name() { let safari_url = CFURL::from_path(Path::new("/Applications/Safari.app"), true).unwrap(); let safari_item = MDItem::from_url(safari_url).unwrap(); assert_eq!(safari_item.get(CFBundleIdentifier), Some(CFString::new("com.apple.Safari"))); assert_eq!(safari_item.get(DisplayName), Some(CFString::new("Safari"))); } }